mirror of
https://github.com/1f349/dendrite.git
synced 2024-11-10 06:53:00 +00:00
1ed732cc78
* Implement /_synapse/admin/v1/register This is implemented identically to Synapse, so scripts which work with Synapse should work with Dendrite. ``` Test 27 POST /_synapse/admin/v1/register with shared secret... OK Test 28 POST /_synapse/admin/v1/register admin with shared secret... OK Test 29 POST /_synapse/admin/v1/register with shared secret downcases capitals... OK Test 30 POST /_synapse/admin/v1/register with shared secret disallows symbols... OK ``` Sytest however has `implementation_specific => "synapse"` which stops these tests from running. * Add missing muxes to gobind * Linting
100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package routing
|
|
|
|
import (
|
|
"context"
|
|
"crypto/hmac"
|
|
"crypto/sha1"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/matrix-org/dendrite/internal"
|
|
"github.com/matrix-org/util"
|
|
cache "github.com/patrickmn/go-cache"
|
|
)
|
|
|
|
type SharedSecretRegistrationRequest struct {
|
|
User string `json:"username"`
|
|
Password string `json:"password"`
|
|
Nonce string `json:"nonce"`
|
|
MacBytes []byte
|
|
MacStr string `json:"mac"`
|
|
Admin bool `json:"admin"`
|
|
}
|
|
|
|
func NewSharedSecretRegistrationRequest(reader io.ReadCloser) (*SharedSecretRegistrationRequest, error) {
|
|
defer internal.CloseAndLogIfError(context.Background(), reader, "NewSharedSecretRegistrationRequest: failed to close request body")
|
|
var ssrr SharedSecretRegistrationRequest
|
|
err := json.NewDecoder(reader).Decode(&ssrr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ssrr.MacBytes, err = hex.DecodeString(ssrr.MacStr)
|
|
return &ssrr, err
|
|
}
|
|
|
|
type SharedSecretRegistration struct {
|
|
sharedSecret string
|
|
nonces *cache.Cache
|
|
}
|
|
|
|
func NewSharedSecretRegistration(sharedSecret string) *SharedSecretRegistration {
|
|
return &SharedSecretRegistration{
|
|
sharedSecret: sharedSecret,
|
|
// nonces live for 5mins, purge every 10mins
|
|
nonces: cache.New(5*time.Minute, 10*time.Minute),
|
|
}
|
|
}
|
|
|
|
func (r *SharedSecretRegistration) GenerateNonce() string {
|
|
nonce := util.RandomString(16)
|
|
r.nonces.Set(nonce, true, cache.DefaultExpiration)
|
|
return nonce
|
|
}
|
|
|
|
func (r *SharedSecretRegistration) validNonce(nonce string) bool {
|
|
_, exists := r.nonces.Get(nonce)
|
|
return exists
|
|
}
|
|
|
|
func (r *SharedSecretRegistration) IsValidMacLogin(
|
|
nonce, username, password string,
|
|
isAdmin bool,
|
|
givenMac []byte,
|
|
) (bool, error) {
|
|
// Check that shared secret registration isn't disabled.
|
|
if r.sharedSecret == "" {
|
|
return false, errors.New("Shared secret registration is disabled")
|
|
}
|
|
if !r.validNonce(nonce) {
|
|
return false, fmt.Errorf("Incorrect or expired nonce: %s", nonce)
|
|
}
|
|
|
|
// Check that username/password don't contain the HMAC delimiters.
|
|
if strings.Contains(username, "\x00") {
|
|
return false, errors.New("Username contains invalid character")
|
|
}
|
|
if strings.Contains(password, "\x00") {
|
|
return false, errors.New("Password contains invalid character")
|
|
}
|
|
|
|
adminString := "notadmin"
|
|
if isAdmin {
|
|
adminString = "admin"
|
|
}
|
|
joined := strings.Join([]string{nonce, username, password, adminString}, "\x00")
|
|
|
|
mac := hmac.New(sha1.New, []byte(r.sharedSecret))
|
|
_, err := mac.Write([]byte(joined))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
expectedMAC := mac.Sum(nil)
|
|
|
|
return hmac.Equal(givenMac, expectedMAC), nil
|
|
}
|