Initial Commit
This commit is contained in:
135
registration.go
Normal file
135
registration.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
// regEndpoint is the endpoint for shared secret registration
|
||||
const regEndpoint = "/_synapse/admin/v1/register"
|
||||
|
||||
// RegistrationReq represents the JSON body of a registration request
|
||||
type RegistrationReq struct {
|
||||
Nonce string `json:"nonce"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"displayname"`
|
||||
Password string `json:"password"`
|
||||
Admin bool `json:"admin"`
|
||||
MAC string `json:"mac"`
|
||||
}
|
||||
|
||||
// registerUser registers the given user with the matrix server
|
||||
func registerUser(username, displayName, password string, u url.URL) error {
|
||||
u.Path = regEndpoint
|
||||
req, err := generateRegRequest(username, displayName, password, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Issuing registration request",
|
||||
slog.String("username", req.Username),
|
||||
slog.String("nonce", req.Nonce),
|
||||
slog.String("mac", req.MAC),
|
||||
)
|
||||
|
||||
res, err := http.Post(u.String(), "application/json", bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
var errRes struct {
|
||||
Message string `json:"message"`
|
||||
ErrCode string `json:"errcode"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
err = json.NewDecoder(res.Body).Decode(&errRes)
|
||||
if err != nil || (errRes.Message == "" && errRes.Error == "") {
|
||||
return errors.New("http: " + res.Status)
|
||||
} else if errRes.Error != "" {
|
||||
return errors.New(u.Host + ": " + errRes.ErrCode + ": " + errRes.Error)
|
||||
} else {
|
||||
return errors.New(u.Host + ": " + errRes.Message)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateRegRequest generates the JSON struct that will serve as the body of a use registration request
|
||||
func generateRegRequest(username, displayName, password string, u url.URL) (*RegistrationReq, error) {
|
||||
secret := os.Getenv("SHARED_SECRET")
|
||||
|
||||
nonce, err := getNonce(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mac, err := calculateMAC(secret, username, password, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &RegistrationReq{
|
||||
nonce,
|
||||
username,
|
||||
displayName,
|
||||
password,
|
||||
false,
|
||||
mac,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getNonce requests and returns a nonce from the matrix server
|
||||
func getNonce(u url.URL) (string, error) {
|
||||
u.Path = regEndpoint
|
||||
res, err := http.Get(u.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
return "", errors.New("http: " + res.Status)
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
err = json.NewDecoder(res.Body).Decode(&resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.Nonce, nil
|
||||
}
|
||||
|
||||
// calculateMAC calculates a returns an HMAC-SHA1 for a new non-admin user
|
||||
func calculateMAC(secret, username, password, nonce string) (string, error) {
|
||||
h := hmac.New(sha1.New, []byte(secret))
|
||||
b := &bytes.Buffer{}
|
||||
b.WriteString(nonce)
|
||||
b.WriteByte(0)
|
||||
b.WriteString(username)
|
||||
b.WriteByte(0)
|
||||
b.WriteString(password)
|
||||
b.WriteByte(0)
|
||||
b.WriteString("notadmin")
|
||||
b.WriteTo(h)
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
Reference in New Issue
Block a user