From 80ceb18c7860cce8d4f19ae44fa60a69bfaf5209 Mon Sep 17 00:00:00 2001 From: santhoshivan23 Date: Sat, 3 Jun 2023 21:47:24 +0530 Subject: [PATCH] CreateNewToken API: Initial Changes --- clientapi/auth/authtypes/logintypes.go | 1 + clientapi/routing/admin.go | 81 ++++++++++++++++++++++++++ clientapi/routing/routing.go | 5 ++ setup/config/config_clientapi.go | 9 +++ 4 files changed, 96 insertions(+) diff --git a/clientapi/auth/authtypes/logintypes.go b/clientapi/auth/authtypes/logintypes.go index f01e48f80..6e08d9735 100644 --- a/clientapi/auth/authtypes/logintypes.go +++ b/clientapi/auth/authtypes/logintypes.go @@ -11,4 +11,5 @@ const ( LoginTypeRecaptcha = "m.login.recaptcha" LoginTypeApplicationService = "m.login.application_service" LoginTypeToken = "m.login.token" + LoginTypeRegistrationToken = "m.login.registration_token" ) diff --git a/clientapi/routing/admin.go b/clientapi/routing/admin.go index 3d64454c4..c25a76d85 100644 --- a/clientapi/routing/admin.go +++ b/clientapi/routing/admin.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "regexp" "time" "github.com/gorilla/mux" @@ -24,6 +25,86 @@ import ( "github.com/matrix-org/dendrite/userapi/api" ) +func AdminCreateNewToken(req *http.Request) util.JSONResponse { + request := struct { + Token string `json:"token"` + UsesAllowed int32 `json:"uses_allowed"` + ExpiryTime int64 `json:"expiry_time"` + Length int32 `json:"length"` + }{} + + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: spec.Unknown("Failed to decode request body: " + err.Error()), + } + } + token := request.Token + if len(token) > 0 { + if len(token) > 64 { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + "token must not be empty and must not be longer than 64") + } + is_token_valid, _ := regexp.MatchString("^[[:ascii:][:digit:]_]*$", token) + if !is_token_valid { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + "token must consist only of characters matched by the regex [A-Za-z0-9-_]") + } + } else { + length := request.Length + if length > 0 && length <= 64 { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + "length must be greater than zero and not greater than 64") + } + // TODO: Generate Random Token + // token = GenerateRandomToken(length) + } + uses_allowed := request.UsesAllowed + if uses_allowed < 0 { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + "uses_allowed must be a non-negative integer or null") + } + + expiry_time := request.ExpiryTime + if expiry_time != 0 && expiry_time < time.Now().UnixNano()/int64(time.Millisecond) { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + "expiry_time must not be in the past") + } + created := CreateToken(token, uses_allowed, expiry_time) + if !created { + return util.MatrixErrorResponse( + http.StatusBadRequest, + string(spec.ErrorInvalidParam), + fmt.Sprintf("Token alreaady exists: %s", token)) + } + return util.JSONResponse{ + Code: 200, + JSON: map[string]interface{}{ + "token": token, + "uses_allowed": uses_allowed, + "pending": 0, + "completed": 0, + "expiry_time": expiry_time, + }, + } +} + +func CreateToken(token string, uses_allowed int32, expiryTime int64) bool { + // TODO: Implement Create Token -> Inserts token into table registration_tokens. + // Returns true if token created, false if token already exists. + return true +} + func AdminEvacuateRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) if err != nil { diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index d3f19cae1..cef558f09 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -162,6 +162,11 @@ func Setup( }), ).Methods(http.MethodGet, http.MethodPost, http.MethodOptions) } + dendriteAdminRouter.Handle("/admin/registrationTokens/new", + httputil.MakeAdminAPI("admin_registration_tokens_new", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { + return AdminCreateNewToken(req) + }), + ).Methods(http.MethodPost, http.MethodOptions) dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}", httputil.MakeAdminAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { diff --git a/setup/config/config_clientapi.go b/setup/config/config_clientapi.go index b6c74a75f..b04d617e0 100644 --- a/setup/config/config_clientapi.go +++ b/setup/config/config_clientapi.go @@ -13,6 +13,10 @@ type ClientAPI struct { // secrets) RegistrationDisabled bool `yaml:"registration_disabled"` + // If set, requires users to submit a token during registration. + // Tokens can be managed using admin API. + RegistrationRequiresToken bool `yaml:"registration_requires_token"` + // Enable registration without captcha verification or shared secret. // This option is populated by the -really-enable-open-registration // command line parameter as it is not recommended. @@ -56,6 +60,7 @@ type ClientAPI struct { func (c *ClientAPI) Defaults(opts DefaultOpts) { c.RegistrationSharedSecret = "" + c.RegistrationRequiresToken = false c.RecaptchaPublicKey = "" c.RecaptchaPrivateKey = "" c.RecaptchaEnabled = false @@ -100,6 +105,10 @@ func (c *ClientAPI) Verify(configErrs *ConfigErrors) { ) } } + + if c.RegistrationDisabled && c.RegistrationRequiresToken { + configErrs.Add("registration_requires_token cannot be set to true when registration_disabled is true") + } } type TURN struct {