mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-14 21:32:23 +03:00
mas: first successful attempt of login with via mas
This commit is contained in:
parent
150be588f5
commit
63a199cec3
31 changed files with 1224 additions and 287 deletions
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
capi "github.com/element-hq/dendrite/clientapi/api"
|
capi "github.com/element-hq/dendrite/clientapi/api"
|
||||||
|
"github.com/element-hq/dendrite/clientapi/auth"
|
||||||
"github.com/element-hq/dendrite/test"
|
"github.com/element-hq/dendrite/test"
|
||||||
"github.com/element-hq/dendrite/test/testrig"
|
"github.com/element-hq/dendrite/test/testrig"
|
||||||
"github.com/element-hq/dendrite/userapi"
|
"github.com/element-hq/dendrite/userapi"
|
||||||
|
@ -48,7 +49,8 @@ func TestAdminCreateToken(t *testing.T) {
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: {},
|
aliceAdmin: {},
|
||||||
bob: {},
|
bob: {},
|
||||||
|
@ -199,7 +201,8 @@ func TestAdminListRegistrationTokens(t *testing.T) {
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: {},
|
aliceAdmin: {},
|
||||||
bob: {},
|
bob: {},
|
||||||
|
@ -317,7 +320,8 @@ func TestAdminGetRegistrationToken(t *testing.T) {
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: {},
|
aliceAdmin: {},
|
||||||
bob: {},
|
bob: {},
|
||||||
|
@ -418,7 +422,8 @@ func TestAdminDeleteRegistrationToken(t *testing.T) {
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: {},
|
aliceAdmin: {},
|
||||||
bob: {},
|
bob: {},
|
||||||
|
@ -512,7 +517,8 @@ func TestAdminUpdateRegistrationToken(t *testing.T) {
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: {},
|
aliceAdmin: {},
|
||||||
bob: {},
|
bob: {},
|
||||||
|
@ -697,7 +703,8 @@ func TestAdminResetPassword(t *testing.T) {
|
||||||
// Needed for changing the password/login
|
// Needed for changing the password/login
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
@ -801,8 +808,9 @@ func TestPurgeRoom(t *testing.T) {
|
||||||
t.Fatalf("failed to send events: %v", err)
|
t.Fatalf("failed to send events: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
@ -872,8 +880,10 @@ func TestAdminEvacuateRoom(t *testing.T) {
|
||||||
t.Fatalf("failed to send events: %v", err)
|
t.Fatalf("failed to send events: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
@ -976,8 +986,10 @@ func TestAdminEvacuateUser(t *testing.T) {
|
||||||
t.Fatalf("failed to send events: %v", err)
|
t.Fatalf("failed to send events: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
@ -1059,8 +1071,10 @@ func TestAdminMarkAsStale(t *testing.T) {
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil, caching.DisableMetrics, testIsBlacklistedOrBackingOff)
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
@ -1147,8 +1161,10 @@ func TestAdminQueryEventReports(t *testing.T) {
|
||||||
t.Fatalf("failed to send events: %v", err)
|
t.Fatalf("failed to send events: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
alice: {},
|
alice: {},
|
||||||
|
@ -1376,8 +1392,10 @@ func TestEventReportsGetDelete(t *testing.T) {
|
||||||
t.Fatalf("failed to send events: %v", err)
|
t.Fatalf("failed to send events: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVerifier := auth.DefaultUserVerifier{UserAPI: userAPI}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, &userVerifier, caching.DisableMetrics)
|
||||||
|
|
||||||
accessTokens := map[*test.User]userDevice{
|
accessTokens := map[*test.User]userDevice{
|
||||||
alice: {},
|
alice: {},
|
||||||
|
|
|
@ -16,8 +16,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/element-hq/dendrite/userapi/api"
|
"github.com/element-hq/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
|
||||||
"github.com/matrix-org/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OWASP recommends at least 128 bits of entropy for tokens: https://www.owasp.org/index.php/Insufficient_Session-ID_Length
|
// OWASP recommends at least 128 bits of entropy for tokens: https://www.owasp.org/index.php/Insufficient_Session-ID_Length
|
||||||
|
@ -37,51 +35,6 @@ type AccountDatabase interface {
|
||||||
GetAccountByPassword(ctx context.Context, localpart, password string) (*api.Account, error)
|
GetAccountByPassword(ctx context.Context, localpart, password string) (*api.Account, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyUserFromRequest authenticates the HTTP request,
|
|
||||||
// on success returns Device of the requester.
|
|
||||||
// Finds local user or an application service user.
|
|
||||||
// Note: For an AS user, AS dummy device is returned.
|
|
||||||
// On failure returns an JSON error response which can be sent to the client.
|
|
||||||
func VerifyUserFromRequest(
|
|
||||||
req *http.Request, userAPI api.QueryAcccessTokenAPI,
|
|
||||||
) (*api.Device, *util.JSONResponse) {
|
|
||||||
// Try to find the Application Service user
|
|
||||||
token, err := ExtractAccessToken(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &util.JSONResponse{
|
|
||||||
Code: http.StatusUnauthorized,
|
|
||||||
JSON: spec.MissingToken(err.Error()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var res api.QueryAccessTokenResponse
|
|
||||||
err = userAPI.QueryAccessToken(req.Context(), &api.QueryAccessTokenRequest{
|
|
||||||
AccessToken: token,
|
|
||||||
AppServiceUserID: req.URL.Query().Get("user_id"),
|
|
||||||
}, &res)
|
|
||||||
if err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("userAPI.QueryAccessToken failed")
|
|
||||||
return nil, &util.JSONResponse{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
JSON: spec.InternalServerError{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if res.Err != "" {
|
|
||||||
if strings.HasPrefix(strings.ToLower(res.Err), "forbidden:") { // TODO: use actual error and no string comparison
|
|
||||||
return nil, &util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: spec.Forbidden(res.Err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if res.Device == nil {
|
|
||||||
return nil, &util.JSONResponse{
|
|
||||||
Code: http.StatusUnauthorized,
|
|
||||||
JSON: spec.UnknownToken("Unknown token"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res.Device, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateAccessToken creates a new access token. Returns an error if failed to generate
|
// GenerateAccessToken creates a new access token. Returns an error if failed to generate
|
||||||
// random bytes.
|
// random bytes.
|
||||||
func GenerateAccessToken() (string, error) {
|
func GenerateAccessToken() (string, error) {
|
||||||
|
|
|
@ -11,4 +11,5 @@ const (
|
||||||
LoginTypeRecaptcha = "m.login.recaptcha"
|
LoginTypeRecaptcha = "m.login.recaptcha"
|
||||||
LoginTypeApplicationService = "m.login.application_service"
|
LoginTypeApplicationService = "m.login.application_service"
|
||||||
LoginTypeToken = "m.login.token"
|
LoginTypeToken = "m.login.token"
|
||||||
|
LoginTypeCrossSigningReset = "org.matrix.cross_signing_reset"
|
||||||
)
|
)
|
||||||
|
|
59
clientapi/auth/default_user_verifier.go
Normal file
59
clientapi/auth/default_user_verifier.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/element-hq/dendrite/userapi/api"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultUserVerifier implements UserVerifier interface
|
||||||
|
type DefaultUserVerifier struct {
|
||||||
|
UserAPI api.QueryAcccessTokenAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserFromRequest authenticates the HTTP request,
|
||||||
|
// on success returns Device of the requester.
|
||||||
|
// Finds local user or an application service user.
|
||||||
|
// Note: For an AS user, AS dummy device is returned.
|
||||||
|
// On failure returns an JSON error response which can be sent to the client.
|
||||||
|
func (d *DefaultUserVerifier) VerifyUserFromRequest(req *http.Request) (*api.Device, *util.JSONResponse) {
|
||||||
|
util.GetLogger(req.Context()).Debug("Default VerifyUserFromRequest")
|
||||||
|
// Try to find the Application Service user
|
||||||
|
token, err := ExtractAccessToken(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: spec.MissingToken(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var res api.QueryAccessTokenResponse
|
||||||
|
err = d.UserAPI.QueryAccessToken(req.Context(), &api.QueryAccessTokenRequest{
|
||||||
|
AccessToken: token,
|
||||||
|
AppServiceUserID: req.URL.Query().Get("user_id"),
|
||||||
|
}, &res)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Error("userAPI.QueryAccessToken failed")
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.InternalServerError{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.Err != "" {
|
||||||
|
if strings.HasPrefix(strings.ToLower(res.Err), "forbidden:") { // TODO: use actual error and no string comparison
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: spec.Forbidden(res.Err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.Device == nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: spec.UnknownToken("Unknown token"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.Device, nil
|
||||||
|
}
|
|
@ -36,7 +36,9 @@ func AddPublicRoutes(
|
||||||
fsAPI federationAPI.ClientFederationAPI,
|
fsAPI federationAPI.ClientFederationAPI,
|
||||||
userAPI userapi.ClientUserAPI,
|
userAPI userapi.ClientUserAPI,
|
||||||
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
||||||
extRoomsProvider api.ExtraPublicRoomsProvider, enableMetrics bool,
|
extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
|
enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
js, natsClient := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
|
js, natsClient := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ func AddPublicRoutes(
|
||||||
cfg, rsAPI, asAPI,
|
cfg, rsAPI, asAPI,
|
||||||
userAPI, userDirectoryProvider, federation,
|
userAPI, userDirectoryProvider, federation,
|
||||||
syncProducer, transactionsCache, fsAPI,
|
syncProducer, transactionsCache, fsAPI,
|
||||||
extRoomsProvider, natsClient, enableMetrics,
|
extRoomsProvider, natsClient,
|
||||||
|
userVerifier, enableMetrics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
|
|
||||||
clientapi "github.com/element-hq/dendrite/clientapi/api"
|
clientapi "github.com/element-hq/dendrite/clientapi/api"
|
||||||
|
clienthttputil "github.com/element-hq/dendrite/clientapi/httputil"
|
||||||
"github.com/element-hq/dendrite/internal/httputil"
|
"github.com/element-hq/dendrite/internal/httputil"
|
||||||
roomserverAPI "github.com/element-hq/dendrite/roomserver/api"
|
roomserverAPI "github.com/element-hq/dendrite/roomserver/api"
|
||||||
"github.com/element-hq/dendrite/setup/config"
|
"github.com/element-hq/dendrite/setup/config"
|
||||||
|
@ -517,6 +518,166 @@ func AdminCheckUsernameAvailable(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AdminHandleUserDeviceByUserID(
|
||||||
|
req *http.Request,
|
||||||
|
userAPI userapi.ClientUserAPI,
|
||||||
|
) util.JSONResponse {
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
userID, ok := vars["userID"]
|
||||||
|
if !ok {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.MissingParam("Expecting user ID."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := util.GetLogger(req.Context())
|
||||||
|
|
||||||
|
switch req.Method {
|
||||||
|
case http.MethodPost:
|
||||||
|
local, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.InvalidParam(userID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var payload struct {
|
||||||
|
DeviceID string `json:"device_id"`
|
||||||
|
}
|
||||||
|
if resErr := clienthttputil.UnmarshalJSONRequest(req, &payload); resErr != nil {
|
||||||
|
return *resErr
|
||||||
|
}
|
||||||
|
|
||||||
|
var rs userapi.PerformDeviceCreationResponse
|
||||||
|
if err := userAPI.PerformDeviceCreation(req.Context(), &userapi.PerformDeviceCreationRequest{
|
||||||
|
Localpart: local,
|
||||||
|
ServerName: domain,
|
||||||
|
DeviceID: &payload.DeviceID,
|
||||||
|
IPAddr: "",
|
||||||
|
UserAgent: req.UserAgent(),
|
||||||
|
NoDeviceListUpdate: false,
|
||||||
|
FromRegistration: false,
|
||||||
|
}, &rs); err != nil {
|
||||||
|
logger.WithError(err).Debug("PerformDeviceCreation failed")
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.WithError(err).Debug("PerformDeviceCreation succeeded")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusCreated,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
case http.MethodGet:
|
||||||
|
var res userapi.QueryDevicesResponse
|
||||||
|
if err := userAPI.QueryDevices(req.Context(), &userapi.QueryDevicesRequest{UserID: userID}, &res); err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonDevices := make([]deviceJSON, 0, len(res.Devices))
|
||||||
|
for i := range res.Devices {
|
||||||
|
d := &res.Devices[i]
|
||||||
|
jsonDevices = append(jsonDevices, deviceJSON{
|
||||||
|
DeviceID: d.ID,
|
||||||
|
DisplayName: d.DisplayName,
|
||||||
|
LastSeenIP: d.LastSeenIP,
|
||||||
|
LastSeenTS: d.LastSeenTS,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct {
|
||||||
|
Devices []deviceJSON `json:"devices"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}{
|
||||||
|
Devices: jsonDevices,
|
||||||
|
Total: len(res.Devices),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusMethodNotAllowed,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type adminExternalID struct {
|
||||||
|
AuthProvider string `json:"auth_provider"`
|
||||||
|
ExternalID string `json:"external_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type adminCreateOrModifyAccountRequest struct {
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
AvatarURL string `json:"avatar_url"`
|
||||||
|
// TODO: the following fields are not used here, but they are used in Synapse. Probably we should reproduce the logic of the
|
||||||
|
// endpoint fully compatible.
|
||||||
|
// Password string `json:"password"`
|
||||||
|
// LogoutDevices bool `json:"logout_devices"`
|
||||||
|
// Threepids json.RawMessage `json:"threepids"`
|
||||||
|
// ExternalIDs []adminExternalID `json:"external_ids"`
|
||||||
|
// Admin bool `json:"admin"`
|
||||||
|
// Deactivated bool `json:"deactivated"`
|
||||||
|
// Locked bool `json:"locked"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func AdminCreateOrModifyAccount(req *http.Request, userAPI userapi.ClientUserAPI) util.JSONResponse {
|
||||||
|
logger := util.GetLogger(req.Context())
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
userID, ok := vars["userID"]
|
||||||
|
if !ok {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.MissingParam("Expecting user ID."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: spec.InvalidParam(userID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var r adminCreateOrModifyAccountRequest
|
||||||
|
if resErr := clienthttputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
||||||
|
logger.Debugf("UnmarshalJSONRequest failed: %+v", *resErr)
|
||||||
|
return *resErr
|
||||||
|
}
|
||||||
|
logger.Debugf("adminCreateOrModifyAccountRequest is: %+v", r)
|
||||||
|
statusCode := http.StatusOK
|
||||||
|
{
|
||||||
|
var res userapi.PerformAccountCreationResponse
|
||||||
|
err = userAPI.PerformAccountCreation(req.Context(), &userapi.PerformAccountCreationRequest{
|
||||||
|
AccountType: userapi.AccountTypeUser,
|
||||||
|
Localpart: local,
|
||||||
|
ServerName: domain,
|
||||||
|
OnConflict: api.ConflictUpdate,
|
||||||
|
AvatarURL: r.AvatarURL,
|
||||||
|
DisplayName: r.DisplayName,
|
||||||
|
}, &res)
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Debugln("Failed creating account")
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
if res.AccountCreated {
|
||||||
|
statusCode = http.StatusCreated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: statusCode,
|
||||||
|
JSON: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetEventReports returns reported events for a given user/room.
|
// GetEventReports returns reported events for a given user/room.
|
||||||
func GetEventReports(
|
func GetEventReports(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
|
|
|
@ -8,6 +8,8 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/element-hq/dendrite/clientapi/auth"
|
"github.com/element-hq/dendrite/clientapi/auth"
|
||||||
"github.com/element-hq/dendrite/clientapi/auth/authtypes"
|
"github.com/element-hq/dendrite/clientapi/auth/authtypes"
|
||||||
|
@ -39,6 +41,58 @@ func UploadCrossSigningDeviceKeys(
|
||||||
if sessionID == "" {
|
if sessionID == "" {
|
||||||
sessionID = util.RandomString(sessionIDLength)
|
sessionID = util.RandomString(sessionIDLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isCrossSigningSetup := false
|
||||||
|
masterKeyUpdatableWithoutUIA := false
|
||||||
|
{
|
||||||
|
var keysResp api.QueryMasterKeysResponse
|
||||||
|
keyserverAPI.QueryMasterKeys(req.Context(), &api.QueryMasterKeysRequest{UserID: device.UserID}, &keysResp)
|
||||||
|
if err := keysResp.Error; err != nil {
|
||||||
|
return convertKeyError(err)
|
||||||
|
}
|
||||||
|
if k := keysResp.Key; k != nil {
|
||||||
|
isCrossSigningSetup = true
|
||||||
|
if k.UpdatableWithoutUIABeforeMs != nil {
|
||||||
|
masterKeyUpdatableWithoutUIA = time.Now().UnixMilli() < *k.UpdatableWithoutUIABeforeMs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isCrossSigningSetup {
|
||||||
|
// With MSC3861, UIA is not possible. Instead, the auth service has to explicitly mark the master key as replaceable.
|
||||||
|
if cfg.MSCs.MSC3861Enabled() {
|
||||||
|
if !masterKeyUpdatableWithoutUIA {
|
||||||
|
url := ""
|
||||||
|
if m := cfg.MSCs.MSC3861; m.AccountManagementURL != "" {
|
||||||
|
url = strings.Join([]string{m.AccountManagementURL, "?action=", authtypes.LoginTypeCrossSigningReset}, "")
|
||||||
|
} else {
|
||||||
|
url = m.Issuer
|
||||||
|
}
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: newUserInteractiveResponse(
|
||||||
|
"dummy",
|
||||||
|
[]authtypes.Flow{
|
||||||
|
{
|
||||||
|
Stages: []authtypes.LoginType{authtypes.LoginTypeCrossSigningReset},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
authtypes.LoginTypeCrossSigningReset: map[string]string{
|
||||||
|
"url": url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
strings.Join([]string{
|
||||||
|
"To reset your end-to-end encryption cross-signing, identity, you first need to approve it at",
|
||||||
|
url,
|
||||||
|
"and then try again.",
|
||||||
|
}, " "),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XXX: is it necessary?
|
||||||
|
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypeCrossSigningReset)
|
||||||
|
} else {
|
||||||
if uploadReq.Auth.Type != authtypes.LoginTypePassword {
|
if uploadReq.Auth.Type != authtypes.LoginTypePassword {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusUnauthorized,
|
Code: http.StatusUnauthorized,
|
||||||
|
@ -50,6 +104,7 @@ func UploadCrossSigningDeviceKeys(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
|
"",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +116,8 @@ func UploadCrossSigningDeviceKeys(
|
||||||
return *authErr
|
return *authErr
|
||||||
}
|
}
|
||||||
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
|
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uploadReq.UserID = device.UserID
|
uploadReq.UserID = device.UserID
|
||||||
keyserverAPI.PerformUploadDeviceKeys(req.Context(), &uploadReq.PerformUploadDeviceKeysRequest, uploadRes)
|
keyserverAPI.PerformUploadDeviceKeys(req.Context(), &uploadReq.PerformUploadDeviceKeysRequest, uploadRes)
|
||||||
|
@ -108,6 +165,16 @@ func UploadCrossSigningDeviceSignatures(req *http.Request, keyserverAPI api.Clie
|
||||||
keyserverAPI.PerformUploadDeviceSignatures(req.Context(), uploadReq, uploadRes)
|
keyserverAPI.PerformUploadDeviceSignatures(req.Context(), uploadReq, uploadRes)
|
||||||
|
|
||||||
if err := uploadRes.Error; err != nil {
|
if err := uploadRes.Error; err != nil {
|
||||||
|
return convertKeyError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertKeyError(err *api.KeyError) util.JSONResponse {
|
||||||
switch {
|
switch {
|
||||||
case err.IsInvalidSignature:
|
case err.IsInvalidSignature:
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
@ -130,10 +197,4 @@ func UploadCrossSigningDeviceSignatures(req *http.Request, keyserverAPI api.Clie
|
||||||
JSON: spec.Unknown(err.Error()),
|
JSON: spec.Unknown(err.Error()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
JSON: struct{}{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ func Password(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
|
"",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,6 +234,7 @@ type userInteractiveResponse struct {
|
||||||
Completed []authtypes.LoginType `json:"completed"`
|
Completed []authtypes.LoginType `json:"completed"`
|
||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Session string `json:"session"`
|
Session string `json:"session"`
|
||||||
|
Msg string `json:"msg,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// newUserInteractiveResponse will return a struct to be sent back to the client
|
// newUserInteractiveResponse will return a struct to be sent back to the client
|
||||||
|
@ -242,9 +243,10 @@ func newUserInteractiveResponse(
|
||||||
sessionID string,
|
sessionID string,
|
||||||
fs []authtypes.Flow,
|
fs []authtypes.Flow,
|
||||||
params map[string]interface{},
|
params map[string]interface{},
|
||||||
|
msg string,
|
||||||
) userInteractiveResponse {
|
) userInteractiveResponse {
|
||||||
return userInteractiveResponse{
|
return userInteractiveResponse{
|
||||||
fs, sessions.getCompletedStages(sessionID), params, sessionID,
|
fs, sessions.getCompletedStages(sessionID), params, sessionID, msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,7 +819,7 @@ func checkAndCompleteFlow(
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusUnauthorized,
|
Code: http.StatusUnauthorized,
|
||||||
JSON: newUserInteractiveResponse(sessionID,
|
JSON: newUserInteractiveResponse(sessionID,
|
||||||
cfg.Derived.Registration.Flows, cfg.Derived.Registration.Params),
|
cfg.Derived.Registration.Flows, cfg.Derived.Registration.Params, ""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,9 @@ func Setup(
|
||||||
transactionsCache *transactions.Cache,
|
transactionsCache *transactions.Cache,
|
||||||
federationSender federationAPI.ClientFederationAPI,
|
federationSender federationAPI.ClientFederationAPI,
|
||||||
extRoomsProvider api.ExtraPublicRoomsProvider,
|
extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
natsClient *nats.Conn, enableMetrics bool,
|
natsClient *nats.Conn,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
|
enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
cfg := &dendriteCfg.ClientAPI
|
cfg := &dendriteCfg.ClientAPI
|
||||||
mscCfg := &dendriteCfg.MSCs
|
mscCfg := &dendriteCfg.MSCs
|
||||||
|
@ -171,19 +173,19 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
}
|
}
|
||||||
dendriteAdminRouter.Handle("/admin/registrationTokens/new",
|
dendriteAdminRouter.Handle("/admin/registrationTokens/new",
|
||||||
httputil.MakeAdminAPI("admin_registration_tokens_new", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_registration_tokens_new", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminCreateNewRegistrationToken(req, cfg, userAPI)
|
return AdminCreateNewRegistrationToken(req, cfg, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/registrationTokens",
|
dendriteAdminRouter.Handle("/admin/registrationTokens",
|
||||||
httputil.MakeAdminAPI("admin_list_registration_tokens", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_list_registration_tokens", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminListRegistrationTokens(req, cfg, userAPI)
|
return AdminListRegistrationTokens(req, cfg, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/registrationTokens/{token}",
|
dendriteAdminRouter.Handle("/admin/registrationTokens/{token}",
|
||||||
httputil.MakeAdminAPI("admin_get_registration_token", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_get_registration_token", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
switch req.Method {
|
switch req.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
return AdminGetRegistrationToken(req, cfg, userAPI)
|
return AdminGetRegistrationToken(req, cfg, userAPI)
|
||||||
|
@ -202,43 +204,43 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPut, http.MethodDelete, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPut, http.MethodDelete, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
||||||
httputil.MakeAdminAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_evacuate_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminEvacuateRoom(req, rsAPI)
|
return AdminEvacuateRoom(req, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}",
|
dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}",
|
||||||
httputil.MakeAdminAPI("admin_evacuate_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_evacuate_user", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminEvacuateUser(req, rsAPI)
|
return AdminEvacuateUser(req, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}",
|
dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}",
|
||||||
httputil.MakeAdminAPI("admin_purge_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_purge_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminPurgeRoom(req, rsAPI)
|
return AdminPurgeRoom(req, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/resetPassword/{userID}",
|
dendriteAdminRouter.Handle("/admin/resetPassword/{userID}",
|
||||||
httputil.MakeAdminAPI("admin_reset_password", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_reset_password", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminResetPassword(req, cfg, device, userAPI)
|
return AdminResetPassword(req, cfg, device, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/downloadState/{serverName}/{roomID}",
|
dendriteAdminRouter.Handle("/admin/downloadState/{serverName}/{roomID}",
|
||||||
httputil.MakeAdminAPI("admin_download_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_download_state", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminDownloadState(req, device, rsAPI)
|
return AdminDownloadState(req, device, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/fulltext/reindex",
|
dendriteAdminRouter.Handle("/admin/fulltext/reindex",
|
||||||
httputil.MakeAdminAPI("admin_fultext_reindex", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_fultext_reindex", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminReindex(req, cfg, device, natsClient)
|
return AdminReindex(req, cfg, device, natsClient)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/refreshDevices/{userID}",
|
dendriteAdminRouter.Handle("/admin/refreshDevices/{userID}",
|
||||||
httputil.MakeAdminAPI("admin_refresh_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_refresh_devices", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminMarkAsStale(req, cfg, userAPI)
|
return AdminMarkAsStale(req, cfg, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
@ -252,7 +254,7 @@ func Setup(
|
||||||
}
|
}
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice/{txnID}",
|
synapseAdminRouter.Handle("/admin/v1/send_server_notice/{txnID}",
|
||||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_server_notice", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
@ -273,7 +275,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice",
|
synapseAdminRouter.Handle("/admin/v1/send_server_notice",
|
||||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_server_notice", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
@ -301,12 +303,12 @@ func Setup(
|
||||||
unstableMux := publicAPIMux.PathPrefix("/unstable").Subrouter()
|
unstableMux := publicAPIMux.PathPrefix("/unstable").Subrouter()
|
||||||
|
|
||||||
v3mux.Handle("/createRoom",
|
v3mux.Handle("/createRoom",
|
||||||
httputil.MakeAuthAPI("createRoom", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("createRoom", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return CreateRoom(req, device, cfg, userAPI, rsAPI, asAPI)
|
return CreateRoom(req, device, cfg, userAPI, rsAPI, asAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/join/{roomIDOrAlias}",
|
v3mux.Handle("/join/{roomIDOrAlias}",
|
||||||
httputil.MakeAuthAPI(spec.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI(spec.Join, userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -340,11 +342,21 @@ func Setup(
|
||||||
httputil.MakeServiceAdminAPI("admin_username_available", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
httputil.MakeServiceAdminAPI("admin_username_available", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
||||||
return AdminCheckUsernameAvailable(r, userAPI, cfg)
|
return AdminCheckUsernameAvailable(r, userAPI, cfg)
|
||||||
})).Methods(http.MethodGet)
|
})).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
synapseAdminRouter.Handle("/admin/v2/users/{userID}",
|
||||||
|
httputil.MakeServiceAdminAPI("admin_provision_user", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
||||||
|
return AdminCreateOrModifyAccount(r, userAPI)
|
||||||
|
})).Methods(http.MethodPut)
|
||||||
|
|
||||||
|
synapseAdminRouter.Handle("/admin/v2/users/{userID}/devices",
|
||||||
|
httputil.MakeServiceAdminAPI("admin_user_devices", m.AdminToken, func(r *http.Request) util.JSONResponse {
|
||||||
|
return AdminHandleUserDeviceByUserID(r, userAPI)
|
||||||
|
})).Methods(http.MethodPost, http.MethodGet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mscCfg.Enabled("msc2753") {
|
if mscCfg.Enabled("msc2753") {
|
||||||
v3mux.Handle("/peek/{roomIDOrAlias}",
|
v3mux.Handle("/peek/{roomIDOrAlias}",
|
||||||
httputil.MakeAuthAPI(spec.Peek, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI(spec.Peek, userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -359,12 +371,12 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
}
|
}
|
||||||
v3mux.Handle("/joined_rooms",
|
v3mux.Handle("/joined_rooms",
|
||||||
httputil.MakeAuthAPI("joined_rooms", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("joined_rooms", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetJoinedRooms(req, device, rsAPI)
|
return GetJoinedRooms(req, device, rsAPI)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/join",
|
v3mux.Handle("/rooms/{roomID}/join",
|
||||||
httputil.MakeAuthAPI(spec.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI(spec.Join, userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -386,7 +398,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/leave",
|
v3mux.Handle("/rooms/{roomID}/leave",
|
||||||
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("membership", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -400,7 +412,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/unpeek",
|
v3mux.Handle("/rooms/{roomID}/unpeek",
|
||||||
httputil.MakeAuthAPI("unpeek", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("unpeek", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -411,7 +423,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/ban",
|
v3mux.Handle("/rooms/{roomID}/ban",
|
||||||
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("membership", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -420,7 +432,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/invite",
|
v3mux.Handle("/rooms/{roomID}/invite",
|
||||||
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("membership", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -432,7 +444,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/kick",
|
v3mux.Handle("/rooms/{roomID}/kick",
|
||||||
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("membership", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -441,7 +453,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/unban",
|
v3mux.Handle("/rooms/{roomID}/unban",
|
||||||
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("membership", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -450,7 +462,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/send/{eventType}",
|
v3mux.Handle("/rooms/{roomID}/send/{eventType}",
|
||||||
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_message", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -459,7 +471,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}",
|
v3mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}",
|
||||||
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_message", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -470,7 +482,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/state", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/rooms/{roomID}/state", httputil.MakeAuthAPI("room_state", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -478,7 +490,7 @@ func Setup(
|
||||||
return OnIncomingStateRequest(req.Context(), device, rsAPI, vars["roomID"])
|
return OnIncomingStateRequest(req.Context(), device, rsAPI, vars["roomID"])
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/aliases", httputil.MakeAuthAPI("aliases", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/rooms/{roomID}/aliases", httputil.MakeAuthAPI("aliases", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -486,7 +498,7 @@ func Setup(
|
||||||
return GetAliases(req, rsAPI, device, vars["roomID"])
|
return GetAliases(req, rsAPI, device, vars["roomID"])
|
||||||
})).Methods(http.MethodGet, http.MethodOptions)
|
})).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/state/{type:[^/]+/?}", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/rooms/{roomID}/state/{type:[^/]+/?}", httputil.MakeAuthAPI("room_state", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -497,7 +509,7 @@ func Setup(
|
||||||
return OnIncomingStateTypeRequest(req.Context(), device, rsAPI, vars["roomID"], eventType, "", eventFormat)
|
return OnIncomingStateTypeRequest(req.Context(), device, rsAPI, vars["roomID"], eventType, "", eventFormat)
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", httputil.MakeAuthAPI("room_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/rooms/{roomID}/state/{type}/{stateKey}", httputil.MakeAuthAPI("room_state", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -507,7 +519,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/state/{eventType:[^/]+/?}",
|
v3mux.Handle("/rooms/{roomID}/state/{eventType:[^/]+/?}",
|
||||||
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_message", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -519,7 +531,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}",
|
v3mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}",
|
||||||
httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_message", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -533,7 +545,7 @@ func Setup(
|
||||||
// TODO: clear based on some criteria
|
// TODO: clear based on some criteria
|
||||||
roomHierarchyPaginationCache := NewRoomHierarchyPaginationCache()
|
roomHierarchyPaginationCache := NewRoomHierarchyPaginationCache()
|
||||||
v1mux.Handle("/rooms/{roomID}/hierarchy",
|
v1mux.Handle("/rooms/{roomID}/hierarchy",
|
||||||
httputil.MakeAuthAPI("spaces", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("spaces", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -567,7 +579,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/directory/room/{roomAlias}",
|
v3mux.Handle("/directory/room/{roomAlias}",
|
||||||
httputil.MakeAuthAPI("directory_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("directory_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -577,7 +589,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/directory/room/{roomAlias}",
|
v3mux.Handle("/directory/room/{roomAlias}",
|
||||||
httputil.MakeAuthAPI("directory_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("directory_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -596,7 +608,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/directory/list/room/{roomID}",
|
v3mux.Handle("/directory/list/room/{roomID}",
|
||||||
httputil.MakeAuthAPI("directory_list", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("directory_list", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -605,7 +617,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
v3mux.Handle("/directory/list/appservice/{networkID}/{roomID}",
|
v3mux.Handle("/directory/list/appservice/{networkID}/{roomID}",
|
||||||
httputil.MakeAuthAPI("directory_list", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("directory_list", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -616,7 +628,7 @@ func Setup(
|
||||||
|
|
||||||
// Undocumented endpoint
|
// Undocumented endpoint
|
||||||
v3mux.Handle("/directory/list/appservice/{networkID}/{roomID}",
|
v3mux.Handle("/directory/list/appservice/{networkID}/{roomID}",
|
||||||
httputil.MakeAuthAPI("directory_list", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("directory_list", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -632,19 +644,19 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/logout",
|
v3mux.Handle("/logout",
|
||||||
httputil.MakeAuthAPI("logout", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("logout", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return Logout(req, userAPI, device)
|
return Logout(req, userAPI, device)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/logout/all",
|
v3mux.Handle("/logout/all",
|
||||||
httputil.MakeAuthAPI("logout", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("logout", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return LogoutAll(req, userAPI, device)
|
return LogoutAll(req, userAPI, device)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/typing/{userID}",
|
v3mux.Handle("/rooms/{roomID}/typing/{userID}",
|
||||||
httputil.MakeAuthAPI("rooms_typing", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_typing", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -656,7 +668,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/redact/{eventID}",
|
v3mux.Handle("/rooms/{roomID}/redact/{eventID}",
|
||||||
httputil.MakeAuthAPI("rooms_redact", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_redact", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -665,7 +677,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomID}/redact/{eventID}/{txnId}",
|
v3mux.Handle("/rooms/{roomID}/redact/{eventID}/{txnId}",
|
||||||
httputil.MakeAuthAPI("rooms_redact", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_redact", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -676,7 +688,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/sendToDevice/{eventType}/{txnID}",
|
v3mux.Handle("/sendToDevice/{eventType}/{txnID}",
|
||||||
httputil.MakeAuthAPI("send_to_device", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_to_device", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -690,7 +702,7 @@ func Setup(
|
||||||
// rather than r0. It's an exact duplicate of the above handler.
|
// rather than r0. It's an exact duplicate of the above handler.
|
||||||
// TODO: Remove this if/when sytest is fixed!
|
// TODO: Remove this if/when sytest is fixed!
|
||||||
unstableMux.Handle("/sendToDevice/{eventType}/{txnID}",
|
unstableMux.Handle("/sendToDevice/{eventType}/{txnID}",
|
||||||
httputil.MakeAuthAPI("send_to_device", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_to_device", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -701,7 +713,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/account/whoami",
|
v3mux.Handle("/account/whoami",
|
||||||
httputil.MakeAuthAPI("whoami", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("whoami", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -710,7 +722,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/account/password",
|
v3mux.Handle("/account/password",
|
||||||
httputil.MakeAuthAPI("password", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("password", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -719,7 +731,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/account/deactivate",
|
v3mux.Handle("/account/deactivate",
|
||||||
httputil.MakeAuthAPI("deactivate", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("deactivate", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -739,7 +751,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/auth/{authType}/fallback/web",
|
v3mux.Handle("/auth/{authType}/fallback/web",
|
||||||
httputil.MakeHTTPAPI("auth_fallback", userAPI, enableMetrics, func(w http.ResponseWriter, req *http.Request) {
|
httputil.MakeHTTPAPI("auth_fallback", userVerifier, enableMetrics, func(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
AuthFallback(w, req, vars["authType"], cfg)
|
AuthFallback(w, req, vars["authType"], cfg)
|
||||||
}),
|
}),
|
||||||
|
@ -748,7 +760,7 @@ func Setup(
|
||||||
// Push rules
|
// Push rules
|
||||||
|
|
||||||
v3mux.Handle("/pushrules",
|
v3mux.Handle("/pushrules",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("missing trailing slash"),
|
JSON: spec.InvalidParam("missing trailing slash"),
|
||||||
|
@ -757,13 +769,13 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/",
|
v3mux.Handle("/pushrules/",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetAllPushRules(req.Context(), device, userAPI)
|
return GetAllPushRules(req.Context(), device, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/",
|
v3mux.Handle("/pushrules/",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("scope, kind and rule ID must be specified"),
|
JSON: spec.InvalidParam("scope, kind and rule ID must be specified"),
|
||||||
|
@ -772,7 +784,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut)
|
).Methods(http.MethodPut)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/",
|
v3mux.Handle("/pushrules/{scope}/",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -782,7 +794,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}",
|
v3mux.Handle("/pushrules/{scope}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("missing trailing slash after scope"),
|
JSON: spec.InvalidParam("missing trailing slash after scope"),
|
||||||
|
@ -791,7 +803,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope:[^/]+/?}",
|
v3mux.Handle("/pushrules/{scope:[^/]+/?}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("kind and rule ID must be specified"),
|
JSON: spec.InvalidParam("kind and rule ID must be specified"),
|
||||||
|
@ -800,7 +812,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut)
|
).Methods(http.MethodPut)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/",
|
v3mux.Handle("/pushrules/{scope}/{kind}/",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -810,7 +822,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}",
|
v3mux.Handle("/pushrules/{scope}/{kind}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("missing trailing slash after kind"),
|
JSON: spec.InvalidParam("missing trailing slash after kind"),
|
||||||
|
@ -819,7 +831,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind:[^/]+/?}",
|
v3mux.Handle("/pushrules/{scope}/{kind:[^/]+/?}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
JSON: spec.InvalidParam("rule ID must be specified"),
|
JSON: spec.InvalidParam("rule ID must be specified"),
|
||||||
|
@ -828,7 +840,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut)
|
).Methods(http.MethodPut)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -838,7 +850,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -852,7 +864,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut)
|
).Methods(http.MethodPut)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -862,7 +874,7 @@ func Setup(
|
||||||
).Methods(http.MethodDelete)
|
).Methods(http.MethodDelete)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}/{attr}",
|
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}/{attr}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -872,7 +884,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}/{attr}",
|
v3mux.Handle("/pushrules/{scope}/{kind}/{ruleID}/{attr}",
|
||||||
httputil.MakeAuthAPI("push_rules", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("push_rules", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -904,7 +916,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/profile/{userID}/avatar_url",
|
v3mux.Handle("/profile/{userID}/avatar_url",
|
||||||
httputil.MakeAuthAPI("profile_avatar_url", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("profile_avatar_url", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -929,7 +941,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/profile/{userID}/displayname",
|
v3mux.Handle("/profile/{userID}/displayname",
|
||||||
httputil.MakeAuthAPI("profile_displayname", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("profile_displayname", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -946,19 +958,19 @@ func Setup(
|
||||||
threePIDClient := base.CreateClient(dendriteCfg, nil) // TODO: Move this somewhere else, e.g. pass in as parameter
|
threePIDClient := base.CreateClient(dendriteCfg, nil) // TODO: Move this somewhere else, e.g. pass in as parameter
|
||||||
|
|
||||||
v3mux.Handle("/account/3pid",
|
v3mux.Handle("/account/3pid",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetAssociated3PIDs(req, userAPI, device)
|
return GetAssociated3PIDs(req, userAPI, device)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/account/3pid",
|
v3mux.Handle("/account/3pid",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return CheckAndSave3PIDAssociation(req, userAPI, device, cfg, threePIDClient)
|
return CheckAndSave3PIDAssociation(req, userAPI, device, cfg, threePIDClient)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/account/3pid/delete",
|
v3mux.Handle("/account/3pid/delete",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return Forget3PID(req, userAPI)
|
return Forget3PID(req, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
@ -970,7 +982,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/voip/turnServer",
|
v3mux.Handle("/voip/turnServer",
|
||||||
httputil.MakeAuthAPI("turn_server", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("turn_server", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -979,13 +991,13 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/protocols",
|
v3mux.Handle("/thirdparty/protocols",
|
||||||
httputil.MakeAuthAPI("thirdparty_protocols", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_protocols", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return Protocols(req, asAPI, device, "")
|
return Protocols(req, asAPI, device, "")
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/protocol/{protocolID}",
|
v3mux.Handle("/thirdparty/protocol/{protocolID}",
|
||||||
httputil.MakeAuthAPI("thirdparty_protocols", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_protocols", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -995,7 +1007,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/user/{protocolID}",
|
v3mux.Handle("/thirdparty/user/{protocolID}",
|
||||||
httputil.MakeAuthAPI("thirdparty_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_user", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1005,13 +1017,13 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/user",
|
v3mux.Handle("/thirdparty/user",
|
||||||
httputil.MakeAuthAPI("thirdparty_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_user", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return User(req, asAPI, device, "", req.URL.Query())
|
return User(req, asAPI, device, "", req.URL.Query())
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/location/{protocolID}",
|
v3mux.Handle("/thirdparty/location/{protocolID}",
|
||||||
httputil.MakeAuthAPI("thirdparty_location", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_location", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1021,7 +1033,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/thirdparty/location",
|
v3mux.Handle("/thirdparty/location",
|
||||||
httputil.MakeAuthAPI("thirdparty_location", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("thirdparty_location", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return Location(req, asAPI, device, "", req.URL.Query())
|
return Location(req, asAPI, device, "", req.URL.Query())
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
@ -1037,7 +1049,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userID}/account_data/{type}",
|
v3mux.Handle("/user/{userID}/account_data/{type}",
|
||||||
httputil.MakeAuthAPI("user_account_data", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("user_account_data", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1047,7 +1059,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userID}/rooms/{roomID}/account_data/{type}",
|
v3mux.Handle("/user/{userID}/rooms/{roomID}/account_data/{type}",
|
||||||
httputil.MakeAuthAPI("user_account_data", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("user_account_data", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1057,7 +1069,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userID}/account_data/{type}",
|
v3mux.Handle("/user/{userID}/account_data/{type}",
|
||||||
httputil.MakeAuthAPI("user_account_data", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("user_account_data", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1067,7 +1079,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet)
|
).Methods(http.MethodGet)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userID}/rooms/{roomID}/account_data/{type}",
|
v3mux.Handle("/user/{userID}/rooms/{roomID}/account_data/{type}",
|
||||||
httputil.MakeAuthAPI("user_account_data", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("user_account_data", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1077,7 +1089,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet)
|
).Methods(http.MethodGet)
|
||||||
|
|
||||||
v3mux.Handle("/admin/whois/{userID}",
|
v3mux.Handle("/admin/whois/{userID}",
|
||||||
httputil.MakeAuthAPI("admin_whois", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("admin_whois", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1087,7 +1099,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet)
|
).Methods(http.MethodGet)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userID}/openid/request_token",
|
v3mux.Handle("/user/{userID}/openid/request_token",
|
||||||
httputil.MakeAuthAPI("openid_request_token", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("openid_request_token", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1100,7 +1112,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user_directory/search",
|
v3mux.Handle("/user_directory/search",
|
||||||
httputil.MakeAuthAPI("userdirectory_search", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("userdirectory_search", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1126,7 +1138,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/read_markers",
|
v3mux.Handle("/rooms/{roomID}/read_markers",
|
||||||
httputil.MakeAuthAPI("rooms_read_markers", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_read_markers", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1139,7 +1151,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/forget",
|
v3mux.Handle("/rooms/{roomID}/forget",
|
||||||
httputil.MakeAuthAPI("rooms_forget", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_forget", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1164,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/upgrade",
|
v3mux.Handle("/rooms/{roomID}/upgrade",
|
||||||
httputil.MakeAuthAPI("rooms_upgrade", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_upgrade", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1162,13 +1174,13 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/devices",
|
v3mux.Handle("/devices",
|
||||||
httputil.MakeAuthAPI("get_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_devices", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetDevicesByLocalpart(req, userAPI, device)
|
return GetDevicesByLocalpart(req, userAPI, device)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/devices/{deviceID}",
|
v3mux.Handle("/devices/{deviceID}",
|
||||||
httputil.MakeAuthAPI("get_device", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_device", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1178,7 +1190,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/devices/{deviceID}",
|
v3mux.Handle("/devices/{deviceID}",
|
||||||
httputil.MakeAuthAPI("device_data", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("device_data", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1188,7 +1200,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/devices/{deviceID}",
|
v3mux.Handle("/devices/{deviceID}",
|
||||||
httputil.MakeAuthAPI("delete_device", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("delete_device", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1198,25 +1210,25 @@ func Setup(
|
||||||
).Methods(http.MethodDelete, http.MethodOptions)
|
).Methods(http.MethodDelete, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/delete_devices",
|
v3mux.Handle("/delete_devices",
|
||||||
httputil.MakeAuthAPI("delete_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("delete_devices", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return DeleteDevices(req, userInteractiveAuth, userAPI, device)
|
return DeleteDevices(req, userInteractiveAuth, userAPI, device)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/notifications",
|
v3mux.Handle("/notifications",
|
||||||
httputil.MakeAuthAPI("get_notifications", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_notifications", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetNotifications(req, device, userAPI)
|
return GetNotifications(req, device, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushers",
|
v3mux.Handle("/pushers",
|
||||||
httputil.MakeAuthAPI("get_pushers", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_pushers", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetPushers(req, device, userAPI)
|
return GetPushers(req, device, userAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/pushers/set",
|
v3mux.Handle("/pushers/set",
|
||||||
httputil.MakeAuthAPI("set_pushers", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("set_pushers", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1226,7 +1238,7 @@ func Setup(
|
||||||
|
|
||||||
// Stub implementations for sytest
|
// Stub implementations for sytest
|
||||||
v3mux.Handle("/events",
|
v3mux.Handle("/events",
|
||||||
httputil.MakeAuthAPI("events", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("events", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
|
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
|
||||||
"chunk": []interface{}{},
|
"chunk": []interface{}{},
|
||||||
"start": "",
|
"start": "",
|
||||||
|
@ -1236,7 +1248,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/initialSync",
|
v3mux.Handle("/initialSync",
|
||||||
httputil.MakeAuthAPI("initial_sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("initial_sync", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
|
return util.JSONResponse{Code: http.StatusOK, JSON: map[string]interface{}{
|
||||||
"end": "",
|
"end": "",
|
||||||
}}
|
}}
|
||||||
|
@ -1244,7 +1256,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags",
|
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags",
|
||||||
httputil.MakeAuthAPI("get_tags", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_tags", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1254,7 +1266,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags/{tag}",
|
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags/{tag}",
|
||||||
httputil.MakeAuthAPI("put_tag", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("put_tag", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1264,7 +1276,7 @@ func Setup(
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags/{tag}",
|
v3mux.Handle("/user/{userId}/rooms/{roomId}/tags/{tag}",
|
||||||
httputil.MakeAuthAPI("delete_tag", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("delete_tag", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1274,7 +1286,7 @@ func Setup(
|
||||||
).Methods(http.MethodDelete, http.MethodOptions)
|
).Methods(http.MethodDelete, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/capabilities",
|
v3mux.Handle("/capabilities",
|
||||||
httputil.MakeAuthAPI("capabilities", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("capabilities", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1284,7 +1296,7 @@ func Setup(
|
||||||
|
|
||||||
// Key Backup Versions (Metadata)
|
// Key Backup Versions (Metadata)
|
||||||
|
|
||||||
getBackupKeysVersion := httputil.MakeAuthAPI("get_backup_keys_version", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
getBackupKeysVersion := httputil.MakeAuthAPI("get_backup_keys_version", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1292,11 +1304,11 @@ func Setup(
|
||||||
return KeyBackupVersion(req, userAPI, device, vars["version"])
|
return KeyBackupVersion(req, userAPI, device, vars["version"])
|
||||||
})
|
})
|
||||||
|
|
||||||
getLatestBackupKeysVersion := httputil.MakeAuthAPI("get_latest_backup_keys_version", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
getLatestBackupKeysVersion := httputil.MakeAuthAPI("get_latest_backup_keys_version", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return KeyBackupVersion(req, userAPI, device, "")
|
return KeyBackupVersion(req, userAPI, device, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
putBackupKeysVersion := httputil.MakeAuthAPI("put_backup_keys_version", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
putBackupKeysVersion := httputil.MakeAuthAPI("put_backup_keys_version", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1304,7 +1316,7 @@ func Setup(
|
||||||
return ModifyKeyBackupVersionAuthData(req, userAPI, device, vars["version"])
|
return ModifyKeyBackupVersionAuthData(req, userAPI, device, vars["version"])
|
||||||
})
|
})
|
||||||
|
|
||||||
deleteBackupKeysVersion := httputil.MakeAuthAPI("delete_backup_keys_version", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
deleteBackupKeysVersion := httputil.MakeAuthAPI("delete_backup_keys_version", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1312,7 +1324,7 @@ func Setup(
|
||||||
return DeleteKeyBackupVersion(req, userAPI, device, vars["version"])
|
return DeleteKeyBackupVersion(req, userAPI, device, vars["version"])
|
||||||
})
|
})
|
||||||
|
|
||||||
postNewBackupKeysVersion := httputil.MakeAuthAPI("post_new_backup_keys_version", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
postNewBackupKeysVersion := httputil.MakeAuthAPI("post_new_backup_keys_version", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return CreateKeyBackupVersion(req, userAPI, device)
|
return CreateKeyBackupVersion(req, userAPI, device)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1331,7 +1343,7 @@ func Setup(
|
||||||
// Inserting E2E Backup Keys
|
// Inserting E2E Backup Keys
|
||||||
|
|
||||||
// Bulk room and session
|
// Bulk room and session
|
||||||
putBackupKeys := httputil.MakeAuthAPI("put_backup_keys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
putBackupKeys := httputil.MakeAuthAPI("put_backup_keys", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
version := req.URL.Query().Get("version")
|
version := req.URL.Query().Get("version")
|
||||||
if version == "" {
|
if version == "" {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
@ -1348,7 +1360,7 @@ func Setup(
|
||||||
})
|
})
|
||||||
|
|
||||||
// Single room bulk session
|
// Single room bulk session
|
||||||
putBackupKeysRoom := httputil.MakeAuthAPI("put_backup_keys_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
putBackupKeysRoom := httputil.MakeAuthAPI("put_backup_keys_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1380,7 +1392,7 @@ func Setup(
|
||||||
})
|
})
|
||||||
|
|
||||||
// Single room, single session
|
// Single room, single session
|
||||||
putBackupKeysRoomSession := httputil.MakeAuthAPI("put_backup_keys_room_session", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
putBackupKeysRoomSession := httputil.MakeAuthAPI("put_backup_keys_room_session", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1422,11 +1434,11 @@ func Setup(
|
||||||
|
|
||||||
// Querying E2E Backup Keys
|
// Querying E2E Backup Keys
|
||||||
|
|
||||||
getBackupKeys := httputil.MakeAuthAPI("get_backup_keys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
getBackupKeys := httputil.MakeAuthAPI("get_backup_keys", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetBackupKeys(req, userAPI, device, req.URL.Query().Get("version"), "", "")
|
return GetBackupKeys(req, userAPI, device, req.URL.Query().Get("version"), "", "")
|
||||||
})
|
})
|
||||||
|
|
||||||
getBackupKeysRoom := httputil.MakeAuthAPI("get_backup_keys_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
getBackupKeysRoom := httputil.MakeAuthAPI("get_backup_keys_room", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1434,7 +1446,7 @@ func Setup(
|
||||||
return GetBackupKeys(req, userAPI, device, req.URL.Query().Get("version"), vars["roomID"], "")
|
return GetBackupKeys(req, userAPI, device, req.URL.Query().Get("version"), vars["roomID"], "")
|
||||||
})
|
})
|
||||||
|
|
||||||
getBackupKeysRoomSession := httputil.MakeAuthAPI("get_backup_keys_room_session", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
getBackupKeysRoomSession := httputil.MakeAuthAPI("get_backup_keys_room_session", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1454,11 +1466,11 @@ func Setup(
|
||||||
|
|
||||||
// Cross-signing device keys
|
// Cross-signing device keys
|
||||||
|
|
||||||
postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return UploadCrossSigningDeviceKeys(req, userInteractiveAuth, userAPI, device, userAPI, cfg)
|
return UploadCrossSigningDeviceKeys(req, userInteractiveAuth, userAPI, device, userAPI, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return UploadCrossSigningDeviceSignatures(req, userAPI, device)
|
return UploadCrossSigningDeviceSignatures(req, userAPI, device)
|
||||||
}, httputil.WithAllowGuests())
|
}, httputil.WithAllowGuests())
|
||||||
|
|
||||||
|
@ -1470,27 +1482,27 @@ func Setup(
|
||||||
|
|
||||||
// Supplying a device ID is deprecated.
|
// Supplying a device ID is deprecated.
|
||||||
v3mux.Handle("/keys/upload/{deviceID}",
|
v3mux.Handle("/keys/upload/{deviceID}",
|
||||||
httputil.MakeAuthAPI("keys_upload", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("keys_upload", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return UploadKeys(req, userAPI, device)
|
return UploadKeys(req, userAPI, device)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/keys/upload",
|
v3mux.Handle("/keys/upload",
|
||||||
httputil.MakeAuthAPI("keys_upload", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("keys_upload", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return UploadKeys(req, userAPI, device)
|
return UploadKeys(req, userAPI, device)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/keys/query",
|
v3mux.Handle("/keys/query",
|
||||||
httputil.MakeAuthAPI("keys_query", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("keys_query", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return QueryKeys(req, userAPI, device)
|
return QueryKeys(req, userAPI, device)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/keys/claim",
|
v3mux.Handle("/keys/claim",
|
||||||
httputil.MakeAuthAPI("keys_claim", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("keys_claim", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return ClaimKeys(req, userAPI)
|
return ClaimKeys(req, userAPI)
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/rooms/{roomId}/receipt/{receiptType}/{eventId}",
|
v3mux.Handle("/rooms/{roomId}/receipt/{receiptType}/{eventId}",
|
||||||
httputil.MakeAuthAPI(spec.Join, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI(spec.Join, userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -1503,7 +1515,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
v3mux.Handle("/presence/{userId}/status",
|
v3mux.Handle("/presence/{userId}/status",
|
||||||
httputil.MakeAuthAPI("set_presence", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("set_presence", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1512,7 +1524,7 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPut, http.MethodOptions)
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
v3mux.Handle("/presence/{userId}/status",
|
v3mux.Handle("/presence/{userId}/status",
|
||||||
httputil.MakeAuthAPI("get_presence", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_presence", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1522,7 +1534,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/joined_members",
|
v3mux.Handle("/rooms/{roomID}/joined_members",
|
||||||
httputil.MakeAuthAPI("rooms_members", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_members", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1532,7 +1544,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/report/{eventID}",
|
v3mux.Handle("/rooms/{roomID}/report/{eventID}",
|
||||||
httputil.MakeAuthAPI("report_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("report_event", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1542,7 +1554,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/event_reports",
|
synapseAdminRouter.Handle("/admin/v1/event_reports",
|
||||||
httputil.MakeAdminAPI("admin_report_events", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_report_events", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
from := parseUint64OrDefault(req.URL.Query().Get("from"), 0)
|
from := parseUint64OrDefault(req.URL.Query().Get("from"), 0)
|
||||||
limit := parseUint64OrDefault(req.URL.Query().Get("limit"), 100)
|
limit := parseUint64OrDefault(req.URL.Query().Get("limit"), 100)
|
||||||
dir := req.URL.Query().Get("dir")
|
dir := req.URL.Query().Get("dir")
|
||||||
|
@ -1556,7 +1568,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
||||||
httputil.MakeAdminAPI("admin_report_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_report_event", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -1566,7 +1578,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
synapseAdminRouter.Handle("/admin/v1/event_reports/{reportID}",
|
||||||
httputil.MakeAdminAPI("admin_report_event_delete", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_report_event_delete", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
|
|
@ -58,17 +58,23 @@ func WithAuth() AuthAPIOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserVerifier interface {
|
||||||
|
// VerifyUserFromRequest authenticates the HTTP request,
|
||||||
|
// on success returns Device of the requester.
|
||||||
|
VerifyUserFromRequest(req *http.Request) (*userapi.Device, *util.JSONResponse)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which authenticates the request.
|
// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which authenticates the request.
|
||||||
func MakeAuthAPI(
|
func MakeAuthAPI(
|
||||||
metricsName string, userAPI userapi.QueryAcccessTokenAPI,
|
metricsName string, userVerifier UserVerifier,
|
||||||
f func(*http.Request, *userapi.Device) util.JSONResponse,
|
f func(*http.Request, *userapi.Device) util.JSONResponse,
|
||||||
checks ...AuthAPIOption,
|
checks ...AuthAPIOption,
|
||||||
) http.Handler {
|
) http.Handler {
|
||||||
h := func(req *http.Request) util.JSONResponse {
|
h := func(req *http.Request) util.JSONResponse {
|
||||||
logger := util.GetLogger(req.Context())
|
logger := util.GetLogger(req.Context())
|
||||||
device, err := auth.VerifyUserFromRequest(req, userAPI)
|
device, err := userVerifier.VerifyUserFromRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debugf("VerifyUserFromRequest %s -> HTTP %d", req.RemoteAddr, err.Code)
|
logger.Debugf("VerifyUserFromRequest %s -> HTTP %d: JSON %+v", req.RemoteAddr, err.Code, err.JSON)
|
||||||
return *err
|
return *err
|
||||||
}
|
}
|
||||||
// add the user ID to the logger
|
// add the user ID to the logger
|
||||||
|
@ -122,11 +128,11 @@ func MakeAuthAPI(
|
||||||
// MakeAdminAPI is a wrapper around MakeAuthAPI which enforces that the request can only be
|
// MakeAdminAPI is a wrapper around MakeAuthAPI which enforces that the request can only be
|
||||||
// completed by a user that is a server administrator.
|
// completed by a user that is a server administrator.
|
||||||
func MakeAdminAPI(
|
func MakeAdminAPI(
|
||||||
metricsName string, userAPI userapi.QueryAcccessTokenAPI,
|
metricsName string, userVerifier UserVerifier,
|
||||||
f func(*http.Request, *userapi.Device) util.JSONResponse,
|
f func(*http.Request, *userapi.Device) util.JSONResponse,
|
||||||
) http.Handler {
|
) http.Handler {
|
||||||
return MakeAuthAPI(metricsName, userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
return MakeAuthAPI(metricsName, userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if device.AccountType != userapi.AccountTypeAdmin {
|
if device == nil || device.AccountType != userapi.AccountTypeAdmin {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
JSON: spec.Forbidden("This API can only be used by admin users."),
|
JSON: spec.Forbidden("This API can only be used by admin users."),
|
||||||
|
@ -136,8 +142,8 @@ func MakeAdminAPI(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeServiceAdminAPI is a wrapper around MakeAuthAPI which enforces that the request can only be
|
// MakeServiceAdminAPI is a wrapper around MakeExternalAPI which enforces that the request can only be
|
||||||
// completed by a trusted service e.g. Matrix Auth Service.
|
// completed by a trusted service e.g. Matrix Auth Service (MAS).
|
||||||
func MakeServiceAdminAPI(
|
func MakeServiceAdminAPI(
|
||||||
metricsName, serviceToken string,
|
metricsName, serviceToken string,
|
||||||
f func(*http.Request) util.JSONResponse,
|
f func(*http.Request) util.JSONResponse,
|
||||||
|
@ -232,7 +238,7 @@ func MakeExternalAPI(metricsName string, f func(*http.Request) util.JSONResponse
|
||||||
|
|
||||||
// MakeHTTPAPI adds Span metrics to the HTML Handler function
|
// MakeHTTPAPI adds Span metrics to the HTML Handler function
|
||||||
// This is used to serve HTML alongside JSON error messages
|
// This is used to serve HTML alongside JSON error messages
|
||||||
func MakeHTTPAPI(metricsName string, userAPI userapi.QueryAcccessTokenAPI, enableMetrics bool, f func(http.ResponseWriter, *http.Request), checks ...AuthAPIOption) http.Handler {
|
func MakeHTTPAPI(metricsName string, userVerifier UserVerifier, enableMetrics bool, f func(http.ResponseWriter, *http.Request), checks ...AuthAPIOption) http.Handler {
|
||||||
withSpan := func(w http.ResponseWriter, req *http.Request) {
|
withSpan := func(w http.ResponseWriter, req *http.Request) {
|
||||||
if req.Method == http.MethodOptions {
|
if req.Method == http.MethodOptions {
|
||||||
util.SetCORSHeaders(w)
|
util.SetCORSHeaders(w)
|
||||||
|
@ -252,7 +258,7 @@ func MakeHTTPAPI(metricsName string, userAPI userapi.QueryAcccessTokenAPI, enabl
|
||||||
|
|
||||||
if opts.WithAuth {
|
if opts.WithAuth {
|
||||||
logger := util.GetLogger(req.Context())
|
logger := util.GetLogger(req.Context())
|
||||||
_, jsonErr := auth.VerifyUserFromRequest(req, userAPI)
|
_, jsonErr := userVerifier.VerifyUserFromRequest(req)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
w.WriteHeader(jsonErr.Code)
|
w.WriteHeader(jsonErr.Code)
|
||||||
if err := json.NewEncoder(w).Encode(jsonErr.JSON); err != nil {
|
if err := json.NewEncoder(w).Encode(jsonErr.JSON); err != nil {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/element-hq/dendrite/mediaapi/routing"
|
"github.com/element-hq/dendrite/mediaapi/routing"
|
||||||
"github.com/element-hq/dendrite/mediaapi/storage"
|
"github.com/element-hq/dendrite/mediaapi/storage"
|
||||||
"github.com/element-hq/dendrite/setup/config"
|
"github.com/element-hq/dendrite/setup/config"
|
||||||
userapi "github.com/element-hq/dendrite/userapi/api"
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/fclient"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -23,10 +22,10 @@ func AddPublicRoutes(
|
||||||
routers httputil.Routers,
|
routers httputil.Routers,
|
||||||
cm *sqlutil.Connections,
|
cm *sqlutil.Connections,
|
||||||
cfg *config.Dendrite,
|
cfg *config.Dendrite,
|
||||||
userAPI userapi.MediaUserAPI,
|
|
||||||
client *fclient.Client,
|
client *fclient.Client,
|
||||||
fedClient fclient.FederationClient,
|
fedClient fclient.FederationClient,
|
||||||
keyRing gomatrixserverlib.JSONVerifier,
|
keyRing gomatrixserverlib.JSONVerifier,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
) {
|
) {
|
||||||
mediaDB, err := storage.NewMediaAPIDatasource(cm, &cfg.MediaAPI.Database)
|
mediaDB, err := storage.NewMediaAPIDatasource(cm, &cfg.MediaAPI.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,6 +33,6 @@ func AddPublicRoutes(
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
routers, cfg, mediaDB, userAPI, client, fedClient, keyRing,
|
routers, cfg, mediaDB, client, fedClient, keyRing, userVerifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,10 @@ func Setup(
|
||||||
routers httputil.Routers,
|
routers httputil.Routers,
|
||||||
cfg *config.Dendrite,
|
cfg *config.Dendrite,
|
||||||
db storage.Database,
|
db storage.Database,
|
||||||
userAPI userapi.MediaUserAPI,
|
|
||||||
client *fclient.Client,
|
client *fclient.Client,
|
||||||
federationClient fclient.FederationClient,
|
federationClient fclient.FederationClient,
|
||||||
keyRing gomatrixserverlib.JSONVerifier,
|
keyRing gomatrixserverlib.JSONVerifier,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
) {
|
) {
|
||||||
rateLimits := httputil.NewRateLimits(&cfg.ClientAPI.RateLimiting)
|
rateLimits := httputil.NewRateLimits(&cfg.ClientAPI.RateLimiting)
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ func Setup(
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadHandler := httputil.MakeAuthAPI(
|
uploadHandler := httputil.MakeAuthAPI(
|
||||||
"upload", userAPI,
|
"upload", userVerifier,
|
||||||
func(req *http.Request, dev *userapi.Device) util.JSONResponse {
|
func(req *http.Request, dev *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, dev); r != nil {
|
if r := rateLimits.Limit(req, dev); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
@ -67,7 +67,7 @@ func Setup(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
configHandler := httputil.MakeAuthAPI("config", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
configHandler := httputil.MakeAuthAPI("config", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
@ -97,13 +97,13 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
// v1 client endpoints requiring auth
|
// v1 client endpoints requiring auth
|
||||||
downloadHandlerAuthed := httputil.MakeHTTPAPI("download", userAPI, cfg.Global.Metrics.Enabled, makeDownloadAPI("download_authed_client", &cfg.MediaAPI, rateLimits, db, client, federationClient, activeRemoteRequests, activeThumbnailGeneration, false), httputil.WithAuth())
|
downloadHandlerAuthed := httputil.MakeHTTPAPI("download", userVerifier, cfg.Global.Metrics.Enabled, makeDownloadAPI("download_authed_client", &cfg.MediaAPI, rateLimits, db, client, federationClient, activeRemoteRequests, activeThumbnailGeneration, false), httputil.WithAuth())
|
||||||
v1mux.Handle("/config", configHandler).Methods(http.MethodGet, http.MethodOptions)
|
v1mux.Handle("/config", configHandler).Methods(http.MethodGet, http.MethodOptions)
|
||||||
v1mux.Handle("/download/{serverName}/{mediaId}", downloadHandlerAuthed).Methods(http.MethodGet, http.MethodOptions)
|
v1mux.Handle("/download/{serverName}/{mediaId}", downloadHandlerAuthed).Methods(http.MethodGet, http.MethodOptions)
|
||||||
v1mux.Handle("/download/{serverName}/{mediaId}/{downloadName}", downloadHandlerAuthed).Methods(http.MethodGet, http.MethodOptions)
|
v1mux.Handle("/download/{serverName}/{mediaId}/{downloadName}", downloadHandlerAuthed).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v1mux.Handle("/thumbnail/{serverName}/{mediaId}",
|
v1mux.Handle("/thumbnail/{serverName}/{mediaId}",
|
||||||
httputil.MakeHTTPAPI("thumbnail", userAPI, cfg.Global.Metrics.Enabled, makeDownloadAPI("thumbnail_authed_client", &cfg.MediaAPI, rateLimits, db, client, federationClient, activeRemoteRequests, activeThumbnailGeneration, false), httputil.WithAuth()),
|
httputil.MakeHTTPAPI("thumbnail", userVerifier, cfg.Global.Metrics.Enabled, makeDownloadAPI("thumbnail_authed_client", &cfg.MediaAPI, rateLimits, db, client, federationClient, activeRemoteRequests, activeThumbnailGeneration, false), httputil.WithAuth()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
// same, but for federation
|
// same, but for federation
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
type MSCs struct {
|
type MSCs struct {
|
||||||
Matrix *Global `yaml:"-"`
|
Matrix *Global `yaml:"-"`
|
||||||
|
|
||||||
// The MSCs to enable. Supported MSCs include:
|
// The MSCs to enable. Supported MSCs include:
|
||||||
|
// 'msc3861': Delegate auth to an OIDC provider. This line MUST always go first if the msc is used https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||||
// 'msc2444': Peeking over federation - https://github.com/matrix-org/matrix-doc/pull/2444
|
// 'msc2444': Peeking over federation - https://github.com/matrix-org/matrix-doc/pull/2444
|
||||||
// 'msc2753': Peeking via /sync - https://github.com/matrix-org/matrix-doc/pull/2753
|
// 'msc2753': Peeking via /sync - https://github.com/matrix-org/matrix-doc/pull/2753
|
||||||
// 'msc2836': Threading - https://github.com/matrix-org/matrix-doc/pull/2836
|
// 'msc2836': Threading - https://github.com/matrix-org/matrix-doc/pull/2836
|
||||||
// 'msc3861': Delegate auth to an OIDC provider https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
|
||||||
MSCs []string `yaml:"mscs"`
|
MSCs []string `yaml:"mscs"`
|
||||||
|
|
||||||
|
// MSC3861 contains config related to the experimental feature MSC3861. It takes effect only if 'msc3861' is included in 'MSCs' array
|
||||||
MSC3861 *MSC3861 `yaml:"msc3861,omitempty"`
|
MSC3861 *MSC3861 `yaml:"msc3861,omitempty"`
|
||||||
|
|
||||||
Database DatabaseOptions `yaml:"database,omitempty"`
|
Database DatabaseOptions `yaml:"database,omitempty"`
|
||||||
|
@ -42,6 +45,10 @@ func (c *MSCs) Verify(configErrs *ConfigErrors) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MSCs) MSC3861Enabled() bool {
|
||||||
|
return slices.Contains(c.MSCs, "msc3861") && c.MSC3861 != nil && c.MSC3861.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
type MSC3861 struct {
|
type MSC3861 struct {
|
||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled"`
|
||||||
Issuer string `yaml:"issuer"`
|
Issuer string `yaml:"issuer"`
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
|
appserviceAPI "github.com/element-hq/dendrite/appservice/api"
|
||||||
"github.com/element-hq/dendrite/clientapi"
|
"github.com/element-hq/dendrite/clientapi"
|
||||||
"github.com/element-hq/dendrite/clientapi/api"
|
"github.com/element-hq/dendrite/clientapi/api"
|
||||||
|
"github.com/element-hq/dendrite/clientapi/auth"
|
||||||
"github.com/element-hq/dendrite/federationapi"
|
"github.com/element-hq/dendrite/federationapi"
|
||||||
federationAPI "github.com/element-hq/dendrite/federationapi/api"
|
federationAPI "github.com/element-hq/dendrite/federationapi/api"
|
||||||
"github.com/element-hq/dendrite/internal/caching"
|
"github.com/element-hq/dendrite/internal/caching"
|
||||||
|
@ -27,6 +30,7 @@ import (
|
||||||
userapi "github.com/element-hq/dendrite/userapi/api"
|
userapi "github.com/element-hq/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/fclient"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Monolith represents an instantiation of all dependencies required to build
|
// Monolith represents an instantiation of all dependencies required to build
|
||||||
|
@ -46,6 +50,8 @@ type Monolith struct {
|
||||||
// Optional
|
// Optional
|
||||||
ExtPublicRoomsProvider api.ExtraPublicRoomsProvider
|
ExtPublicRoomsProvider api.ExtraPublicRoomsProvider
|
||||||
ExtUserDirectoryProvider userapi.QuerySearchProfilesAPI
|
ExtUserDirectoryProvider userapi.QuerySearchProfilesAPI
|
||||||
|
|
||||||
|
UserVerifierProvider *UserVerifierProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAllPublicRoutes attaches all public paths to the given router
|
// AddAllPublicRoutes attaches all public paths to the given router
|
||||||
|
@ -58,6 +64,10 @@ func (m *Monolith) AddAllPublicRoutes(
|
||||||
caches *caching.Caches,
|
caches *caching.Caches,
|
||||||
enableMetrics bool,
|
enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
|
if m.UserVerifierProvider == nil {
|
||||||
|
m.UserVerifierProvider = NewUserVerifierProvider(&auth.DefaultUserVerifier{UserAPI: m.UserAPI})
|
||||||
|
}
|
||||||
|
|
||||||
userDirectoryProvider := m.ExtUserDirectoryProvider
|
userDirectoryProvider := m.ExtUserDirectoryProvider
|
||||||
if userDirectoryProvider == nil {
|
if userDirectoryProvider == nil {
|
||||||
userDirectoryProvider = m.UserAPI
|
userDirectoryProvider = m.UserAPI
|
||||||
|
@ -65,15 +75,29 @@ func (m *Monolith) AddAllPublicRoutes(
|
||||||
clientapi.AddPublicRoutes(
|
clientapi.AddPublicRoutes(
|
||||||
processCtx, routers, cfg, natsInstance, m.FedClient, m.RoomserverAPI, m.AppserviceAPI, transactions.New(),
|
processCtx, routers, cfg, natsInstance, m.FedClient, m.RoomserverAPI, m.AppserviceAPI, transactions.New(),
|
||||||
m.FederationAPI, m.UserAPI, userDirectoryProvider,
|
m.FederationAPI, m.UserAPI, userDirectoryProvider,
|
||||||
m.ExtPublicRoomsProvider, enableMetrics,
|
m.ExtPublicRoomsProvider, m.UserVerifierProvider, enableMetrics,
|
||||||
)
|
)
|
||||||
federationapi.AddPublicRoutes(
|
federationapi.AddPublicRoutes(
|
||||||
processCtx, routers, cfg, natsInstance, m.UserAPI, m.FedClient, m.KeyRing, m.RoomserverAPI, m.FederationAPI, enableMetrics,
|
processCtx, routers, cfg, natsInstance, m.UserAPI, m.FedClient, m.KeyRing, m.RoomserverAPI, m.FederationAPI, enableMetrics,
|
||||||
)
|
)
|
||||||
mediaapi.AddPublicRoutes(routers, cm, cfg, m.UserAPI, m.Client, m.FedClient, m.KeyRing)
|
mediaapi.AddPublicRoutes(routers, cm, cfg, m.Client, m.FedClient, m.KeyRing, m.UserVerifierProvider)
|
||||||
syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, natsInstance, m.UserAPI, m.RoomserverAPI, caches, enableMetrics)
|
syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, natsInstance, m.UserAPI, m.RoomserverAPI, caches, m.UserVerifierProvider, enableMetrics)
|
||||||
|
|
||||||
if m.RelayAPI != nil {
|
if m.RelayAPI != nil {
|
||||||
relayapi.AddPublicRoutes(routers, cfg, m.KeyRing, m.RelayAPI)
|
relayapi.AddPublicRoutes(routers, cfg, m.KeyRing, m.RelayAPI)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserVerifierProvider struct {
|
||||||
|
UserVerifier httputil.UserVerifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserVerifierProvider) VerifyUserFromRequest(req *http.Request) (*userapi.Device, *util.JSONResponse) {
|
||||||
|
return u.UserVerifier.VerifyUserFromRequest(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserVerifierProvider(userVerifier httputil.UserVerifier) *UserVerifierProvider {
|
||||||
|
return &UserVerifierProvider{
|
||||||
|
UserVerifier: userVerifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ func toClientResponse(ctx context.Context, res *MSC2836EventRelationshipsRespons
|
||||||
// Enable this MSC
|
// Enable this MSC
|
||||||
func Enable(
|
func Enable(
|
||||||
cfg *config.Dendrite, cm *sqlutil.Connections, routers httputil.Routers, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationInternalAPI,
|
cfg *config.Dendrite, cm *sqlutil.Connections, routers httputil.Routers, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationInternalAPI,
|
||||||
userAPI userapi.UserInternalAPI, keyRing gomatrixserverlib.JSONVerifier,
|
userVerifier httputil.UserVerifier, keyRing gomatrixserverlib.JSONVerifier,
|
||||||
) error {
|
) error {
|
||||||
db, err := NewDatabase(cm, &cfg.MSCs.Database)
|
db, err := NewDatabase(cm, &cfg.MSCs.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -124,7 +124,7 @@ func Enable(
|
||||||
})
|
})
|
||||||
|
|
||||||
routers.Client.Handle("/unstable/event_relationships",
|
routers.Client.Handle("/unstable/event_relationships",
|
||||||
httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI, fsAPI)),
|
httputil.MakeAuthAPI("eventRelationships", userVerifier, eventRelationshipHandler(db, rsAPI, fsAPI)),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
routers.Federation.Handle("/unstable/event_relationships", httputil.MakeExternalAPI(
|
routers.Federation.Handle("/unstable/event_relationships", httputil.MakeExternalAPI(
|
||||||
|
|
17
setup/mscs/msc3861/msc3861.go
Normal file
17
setup/mscs/msc3861/msc3861.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package msc3861
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/element-hq/dendrite/setup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Enable(m *setup.Monolith) error {
|
||||||
|
userVerifier, err := newMSC3861UserVerifier(
|
||||||
|
m.UserAPI, m.Config.Global.ServerName,
|
||||||
|
m.Config.MSCs.MSC3861, !m.Config.ClientAPI.GuestsDisabled,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.UserVerifierProvider.UserVerifier = userVerifier
|
||||||
|
return nil
|
||||||
|
}
|
444
setup/mscs/msc3861/msc3861_user_verifier.go
Normal file
444
setup/mscs/msc3861/msc3861_user_verifier.go
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
package msc3861
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/element-hq/dendrite/clientapi/auth"
|
||||||
|
"github.com/element-hq/dendrite/setup/config"
|
||||||
|
"github.com/element-hq/dendrite/userapi/api"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const externalAuthProvider string = "oauth-delegated"
|
||||||
|
|
||||||
|
// Scopes as defined by MSC2967
|
||||||
|
// https://github.com/matrix-org/matrix-spec-proposals/pull/2967
|
||||||
|
const (
|
||||||
|
scopeMatrixAPI string = "urn:matrix:org.matrix.msc2967.client:api:*"
|
||||||
|
scopeMatrixGuest string = "urn:matrix:org.matrix.msc2967.client:api:guest"
|
||||||
|
scopeMatrixDevicePrefix string = "urn:matrix:org.matrix.msc2967.client:device:"
|
||||||
|
)
|
||||||
|
|
||||||
|
type errCode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
codeIntrospectionNot2xx errCode = "introspectionIsNot2xx"
|
||||||
|
codeInvalidClientToken errCode = "invalidClientToken"
|
||||||
|
codeAuthError errCode = "authError"
|
||||||
|
codeMxidError errCode = "mxidError"
|
||||||
|
codeOpenidConfigEndpointNon2xx errCode = "openidConfigEndpointNon2xx"
|
||||||
|
codeOpenidConfigDecodingFailed errCode = "openidConfigDecodingFailed"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MSC3861UserVerifier implements UserVerifier interface
|
||||||
|
type MSC3861UserVerifier struct {
|
||||||
|
userAPI api.UserInternalAPI
|
||||||
|
serverName spec.ServerName
|
||||||
|
cfg *config.MSC3861
|
||||||
|
httpClient *http.Client
|
||||||
|
openIdConfig *OpenIDConfiguration
|
||||||
|
allowGuest bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMSC3861UserVerifier(
|
||||||
|
userAPI api.UserInternalAPI,
|
||||||
|
serverName spec.ServerName,
|
||||||
|
cfg *config.MSC3861,
|
||||||
|
allowGuest bool,
|
||||||
|
) (*MSC3861UserVerifier, error) {
|
||||||
|
openIdConfig, err := fetchOpenIDConfiguration(&http.Client{}, cfg.Issuer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &MSC3861UserVerifier{
|
||||||
|
userAPI: userAPI,
|
||||||
|
serverName: serverName,
|
||||||
|
cfg: cfg,
|
||||||
|
openIdConfig: openIdConfig,
|
||||||
|
allowGuest: allowGuest,
|
||||||
|
httpClient: http.DefaultClient,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type mscError struct {
|
||||||
|
Code errCode
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mscError) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s", r.Code, r.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserFromRequest authenticates the HTTP request, on success returns Device of the requester.
|
||||||
|
func (m *MSC3861UserVerifier) VerifyUserFromRequest(req *http.Request) (*api.Device, *util.JSONResponse) {
|
||||||
|
util.GetLogger(req.Context()).Debug("MSC3861.VerifyUserFromRequest")
|
||||||
|
// Try to find the Application Service user
|
||||||
|
token, err := auth.ExtractAccessToken(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: spec.MissingToken(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: try to get appservice user first. See https://github.com/element-hq/synapse/blob/develop/synapse/api/auth/msc3861_delegated.py#L273
|
||||||
|
userData, err := m.getUserByAccessToken(req.Context(), token)
|
||||||
|
if err != nil {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case (*mscError):
|
||||||
|
switch e.Code {
|
||||||
|
case codeIntrospectionNot2xx, codeOpenidConfigDecodingFailed, codeOpenidConfigEndpointNon2xx:
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusServiceUnavailable,
|
||||||
|
JSON: spec.Unknown(e.Error()),
|
||||||
|
}
|
||||||
|
case codeInvalidClientToken:
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Forbidden(e.Error()),
|
||||||
|
}
|
||||||
|
case codeAuthError:
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(e.Error()),
|
||||||
|
}
|
||||||
|
case codeMxidError:
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: spec.Unknown(e.Error()),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
r := util.ErrorResponse(err)
|
||||||
|
return nil, &r
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
r := util.ErrorResponse(err)
|
||||||
|
return nil, &r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not record requests from MAS using the virtual `__oidc_admin` user.
|
||||||
|
if token != m.cfg.AdminToken {
|
||||||
|
// TODO: not sure which exact data we should record here. See the link for reference
|
||||||
|
// https://github.com/element-hq/synapse/blob/develop/synapse/api/auth/base.py#L365
|
||||||
|
}
|
||||||
|
|
||||||
|
if !m.allowGuest && userData.IsGuest {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: spec.Forbidden(strings.Join([]string{"Insufficient scope: ", scopeMatrixAPI}, "")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userData.Device, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type requester struct {
|
||||||
|
Device *api.Device
|
||||||
|
UserID *spec.UserID
|
||||||
|
Scope []string
|
||||||
|
IsGuest bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MSC3861UserVerifier) getUserByAccessToken(ctx context.Context, token string) (*requester, error) {
|
||||||
|
var userID *spec.UserID
|
||||||
|
logger := util.GetLogger(ctx)
|
||||||
|
|
||||||
|
if adminToken := m.cfg.AdminToken; adminToken != "" && token == adminToken {
|
||||||
|
// XXX: This is a temporary solution so that the admin API can be called by
|
||||||
|
// the OIDC provider. This will be removed once we have OIDC client
|
||||||
|
// credentials grant support in matrix-authentication-service.
|
||||||
|
logger.Info("Admin token used")
|
||||||
|
// XXX: that user doesn't exist and won't be provisioned.
|
||||||
|
adminUser, err := createUserID("__oidc_admin", m.serverName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &requester{
|
||||||
|
UserID: adminUser,
|
||||||
|
Scope: []string{"urn:synapse:admin:*"},
|
||||||
|
Device: &api.Device{UserID: adminUser.Local(), AccountType: api.AccountTypeAdmin},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
introspectionResult, err := m.introspectToken(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("MSC3861UserVerifier:introspectToken")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logger.Debugf("Introspection result: %+v", *introspectionResult)
|
||||||
|
|
||||||
|
if !introspectionResult.Active {
|
||||||
|
return nil, &mscError{Code: codeInvalidClientToken, Msg: "Token is not active"}
|
||||||
|
}
|
||||||
|
|
||||||
|
scopes := introspectionResult.Scopes()
|
||||||
|
hasUserScope, hasGuestScope := slices.Contains(scopes, scopeMatrixAPI), slices.Contains(scopes, scopeMatrixGuest)
|
||||||
|
if !hasUserScope && !hasGuestScope {
|
||||||
|
return nil, &mscError{Code: codeInvalidClientToken, Msg: "No scope in token granting user rights"}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := introspectionResult.Sub
|
||||||
|
if sub == "" {
|
||||||
|
return nil, &mscError{Code: codeInvalidClientToken, Msg: "Invalid sub claim in the introspection result"}
|
||||||
|
}
|
||||||
|
|
||||||
|
localpart := ""
|
||||||
|
{
|
||||||
|
var rs api.QueryLocalpartExternalIDResponse
|
||||||
|
if err = m.userAPI.QueryExternalUserIDByLocalpartAndProvider(ctx, &api.QueryLocalpartExternalIDRequest{
|
||||||
|
ExternalID: sub,
|
||||||
|
AuthProvider: externalAuthProvider,
|
||||||
|
}, &rs); err != nil && err != sql.ErrNoRows {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if l := rs.LocalpartExternalID; l != nil {
|
||||||
|
localpart = l.Localpart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if localpart == "" {
|
||||||
|
// If we could not find a user via the external_id, it either does not exist,
|
||||||
|
// or the external_id was never recorded
|
||||||
|
username := introspectionResult.Username
|
||||||
|
if username == "" {
|
||||||
|
return nil, &mscError{Code: codeAuthError, Msg: "Invalid username claim in the introspection result"}
|
||||||
|
}
|
||||||
|
userID, err = createUserID(username, m.serverName)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("getUserByAccessToken:createUserID")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// First try to find a user from the username claim
|
||||||
|
var account *api.Account
|
||||||
|
{
|
||||||
|
var rs api.QueryAccountByLocalpartResponse
|
||||||
|
err := m.userAPI.QueryAccountByLocalpart(ctx, &api.QueryAccountByLocalpartRequest{Localpart: userID.Local(), ServerName: userID.Domain()}, &rs)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
logger.WithError(err).Error("QueryAccountByLocalpart")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
account = rs.Account
|
||||||
|
}
|
||||||
|
|
||||||
|
if account == nil {
|
||||||
|
// If the user does not exist, we should create it on the fly
|
||||||
|
var rs api.PerformAccountCreationResponse
|
||||||
|
if err = m.userAPI.PerformAccountCreation(ctx, &api.PerformAccountCreationRequest{
|
||||||
|
AccountType: api.AccountTypeUser,
|
||||||
|
Localpart: userID.Local(),
|
||||||
|
ServerName: userID.Domain(),
|
||||||
|
}, &rs); err != nil {
|
||||||
|
logger.WithError(err).Error("PerformAccountCreation")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.userAPI.PerformLocalpartExternalUserIDCreation(ctx, &api.PerformLocalpartExternalUserIDCreationRequest{
|
||||||
|
Localpart: userID.Local(),
|
||||||
|
ExternalID: sub,
|
||||||
|
AuthProvider: externalAuthProvider,
|
||||||
|
}); err != nil {
|
||||||
|
logger.WithError(err).Error("PerformLocalpartExternalUserIDCreation")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
localpart = userID.Local()
|
||||||
|
}
|
||||||
|
|
||||||
|
if userID == nil {
|
||||||
|
userID, err = createUserID(localpart, m.serverName)
|
||||||
|
if err != nil {
|
||||||
|
logger.WithError(err).Error("getUserByAccessToken:createUserID")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceIDs := make([]string, 0, 1)
|
||||||
|
for i := range scopes {
|
||||||
|
if s := scopes[i]; strings.HasPrefix(s, scopeMatrixDevicePrefix) {
|
||||||
|
deviceIDs = append(deviceIDs, s[len(scopeMatrixDevicePrefix):])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deviceIDs) != 1 {
|
||||||
|
logger.Errorf("Invalid device IDs in scope: %+v", deviceIDs)
|
||||||
|
return nil, &mscError{Code: codeAuthError, Msg: "Invalid device IDs in scope"}
|
||||||
|
}
|
||||||
|
|
||||||
|
var device *api.Device
|
||||||
|
|
||||||
|
deviceID := deviceIDs[0]
|
||||||
|
if len(deviceID) > 255 || len(deviceID) < 1 {
|
||||||
|
return nil, &mscError{
|
||||||
|
Code: codeAuthError,
|
||||||
|
Msg: strings.Join([]string{"Invalid device ID in scope: ", deviceID}, ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debugf("deviceID is: %s", deviceID)
|
||||||
|
logger.Debugf("scope is: %+v", scopes)
|
||||||
|
|
||||||
|
userDeviceExists := false
|
||||||
|
{
|
||||||
|
var rs api.QueryDevicesResponse
|
||||||
|
err := m.userAPI.QueryDevices(ctx, &api.QueryDevicesRequest{UserID: userID.String()}, &rs)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range rs.Devices {
|
||||||
|
if d := &rs.Devices[i]; d.ID == deviceID {
|
||||||
|
userDeviceExists = true
|
||||||
|
device = d
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.Debugf("userDeviceExists is: %t", userDeviceExists)
|
||||||
|
if !userDeviceExists {
|
||||||
|
var rs api.PerformDeviceCreationResponse
|
||||||
|
deviceDisplayName := "OIDC-native client"
|
||||||
|
if err := m.userAPI.PerformDeviceCreation(ctx, &api.PerformDeviceCreationRequest{
|
||||||
|
Localpart: localpart,
|
||||||
|
ServerName: m.serverName,
|
||||||
|
AccessToken: token,
|
||||||
|
DeviceID: &deviceID,
|
||||||
|
DeviceDisplayName: &deviceDisplayName,
|
||||||
|
// TODO: Cannot add IPAddr and Useragent values here. Should we care about it here?
|
||||||
|
}, &rs); err != nil {
|
||||||
|
logger.WithError(err).Error("PerformDeviceCreation")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
device = rs.Device
|
||||||
|
logger.Debugf("PerformDeviceCreationResponse is: %+v", rs)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return &requester{
|
||||||
|
Device: device,
|
||||||
|
UserID: userID,
|
||||||
|
Scope: scopes,
|
||||||
|
IsGuest: hasGuestScope && !hasUserScope,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUserID(local string, serverName spec.ServerName) (*spec.UserID, error) {
|
||||||
|
userID, err := spec.NewUserID(strings.Join([]string{"@", local, ":", string(serverName)}, ""), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &mscError{Code: codeMxidError, Msg: err.Error()}
|
||||||
|
}
|
||||||
|
return userID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MSC3861UserVerifier) introspectToken(ctx context.Context, token string) (*introspectionResponse, error) {
|
||||||
|
formBody := url.Values{"token": []string{token}}
|
||||||
|
encoded := formBody.Encode()
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, m.openIdConfig.IntrospectionEndpoint, strings.NewReader(encoded))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.SetBasicAuth(m.cfg.ClientID, m.cfg.ClientSecret)
|
||||||
|
|
||||||
|
resp, err := m.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body := resp.Body
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if c := resp.StatusCode; c < 200 || c >= 300 {
|
||||||
|
return nil, errors.New(strings.Join([]string{"The introspection endpoint returned a '", resp.Status ,"' response"}, ""))
|
||||||
|
}
|
||||||
|
var ir introspectionResponse
|
||||||
|
if err := json.NewDecoder(body).Decode(&ir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ir, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenIDConfiguration struct {
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
AuthorizationEndpoint string `json:"authorization_endpoint"`
|
||||||
|
TokenEndpoint string `json:"token_endpoint"`
|
||||||
|
JWKsURI string `json:"jwks_uri"`
|
||||||
|
RegistrationEndpoint string `json:"registration_endpoint"`
|
||||||
|
ScopesSupported []string `json:"scopes_supported"`
|
||||||
|
ResponseTypesSupported []string `json:"response_types_supported"`
|
||||||
|
ResponseModesSupported []string `json:"response_modes_supported"`
|
||||||
|
GrantTypesSupported []string `json:"grant_types_supported"`
|
||||||
|
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
|
||||||
|
TokenEndpointAuthSigningAlgCaluesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported"`
|
||||||
|
RevocationEnpoint string `json:"revocation_endpoint"`
|
||||||
|
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported"`
|
||||||
|
RevocationEndpointAuthSigningAlgValues []string `json:"revocation_endpoint_auth_signing_alg_values_supported"`
|
||||||
|
IntrospectionEndpoint string `json:"introspection_endpoint"`
|
||||||
|
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported"`
|
||||||
|
IntrospectionEndpointAuthSigningAlgValues []string `json:"introspection_endpoint_auth_signing_alg_values_supported"`
|
||||||
|
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
|
||||||
|
UserinfoEndpoint string `json:"userinfo_endpoint"`
|
||||||
|
SubjectTypesSupported []string `json:"subject_types_supported"`
|
||||||
|
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
|
||||||
|
UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported"`
|
||||||
|
DisplayValuesSupported []string `json:"display_values_supported"`
|
||||||
|
ClaimTypesSupported []string `json:"claim_types_supported"`
|
||||||
|
ClaimsSupported []string `json:"claims_supported"`
|
||||||
|
ClaimsParameterSupported bool `json:"claims_parameter_supported"`
|
||||||
|
RequestParameterSupported bool `json:"request_parameter_supported"`
|
||||||
|
RequestURIParameterSupported bool `json:"request_uri_parameter_supported"`
|
||||||
|
PromptValuesSupported []string `json:"prompt_values_supported"`
|
||||||
|
DeviceAuthorizaEndpoint string `json:"device_authorization_endpoint"`
|
||||||
|
AccountManagementURI string `json:"account_management_uri"`
|
||||||
|
AccountManagementActionsSupported []string `json:"account_management_actions_supported"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchOpenIDConfiguration(httpClient *http.Client, authHostURL string) (*
|
||||||
|
OpenIDConfiguration, error) {
|
||||||
|
u, err := url.Parse(authHostURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u = u.JoinPath(".well-known/openid-configuration")
|
||||||
|
resp, err := httpClient.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, &mscError{Code: codeOpenidConfigEndpointNon2xx, Msg: ".well-known/openid-configuration endpoint returned non-200 response"}
|
||||||
|
}
|
||||||
|
var oic OpenIDConfiguration
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&oic); err != nil {
|
||||||
|
return nil, &mscError{Code: codeOpenidConfigDecodingFailed, Msg: err.Error()}
|
||||||
|
}
|
||||||
|
return &oic, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// introspectionResponse as described in the RFC https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
|
||||||
|
type introspectionResponse struct {
|
||||||
|
Active bool `json:"active"` // required
|
||||||
|
Scope string `json:"scope"` // optional
|
||||||
|
Username string `json:"username"` // optional
|
||||||
|
TokenType string `json:"token_type"` // optional
|
||||||
|
Exp *int64 `json:"exp"` // optional
|
||||||
|
Iat *int64 `json:"iat"` // optional
|
||||||
|
Nfb *int64 `json:"nfb"` // optional
|
||||||
|
Sub string `json:"sub"` // optional
|
||||||
|
Jti string `json:"jti"` // optional
|
||||||
|
Aud string `json:"aud"` // optional
|
||||||
|
Iss string `json:"iss"` // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *introspectionResponse) Scopes() []string {
|
||||||
|
return strings.Split(i.Scope, " ")
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/element-hq/dendrite/setup"
|
"github.com/element-hq/dendrite/setup"
|
||||||
"github.com/element-hq/dendrite/setup/config"
|
"github.com/element-hq/dendrite/setup/config"
|
||||||
"github.com/element-hq/dendrite/setup/mscs/msc2836"
|
"github.com/element-hq/dendrite/setup/mscs/msc2836"
|
||||||
|
"github.com/element-hq/dendrite/setup/mscs/msc3861"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -34,10 +35,11 @@ func Enable(cfg *config.Dendrite, cm *sqlutil.Connections, routers httputil.Rout
|
||||||
func EnableMSC(cfg *config.Dendrite, cm *sqlutil.Connections, routers httputil.Routers, monolith *setup.Monolith, msc string, caches *caching.Caches) error {
|
func EnableMSC(cfg *config.Dendrite, cm *sqlutil.Connections, routers httputil.Routers, monolith *setup.Monolith, msc string, caches *caching.Caches) error {
|
||||||
switch msc {
|
switch msc {
|
||||||
case "msc2836":
|
case "msc2836":
|
||||||
return msc2836.Enable(cfg, cm, routers, monolith.RoomserverAPI, monolith.FederationAPI, monolith.UserAPI, monolith.KeyRing)
|
return msc2836.Enable(cfg, cm, routers, monolith.RoomserverAPI, monolith.FederationAPI, monolith.UserVerifierProvider, monolith.KeyRing)
|
||||||
case "msc2444": // enabled inside federationapi
|
case "msc2444": // enabled inside federationapi
|
||||||
case "msc2753": // enabled inside clientapi
|
case "msc2753": // enabled inside clientapi
|
||||||
case "msc3861": // enabled inside clientapi
|
case "msc3861":
|
||||||
|
return msc3861.Enable(monolith)
|
||||||
default:
|
default:
|
||||||
logrus.Warnf("EnableMSC: unknown MSC '%s', this MSC is either not supported or is natively supported by Dendrite", msc)
|
logrus.Warnf("EnableMSC: unknown MSC '%s', this MSC is either not supported or is natively supported by Dendrite", msc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,17 @@ func Setup(
|
||||||
lazyLoadCache caching.LazyLoadCache,
|
lazyLoadCache caching.LazyLoadCache,
|
||||||
fts fulltext.Indexer,
|
fts fulltext.Indexer,
|
||||||
rateLimits *httputil.RateLimits,
|
rateLimits *httputil.RateLimits,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
) {
|
) {
|
||||||
v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter()
|
v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter()
|
||||||
v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter()
|
v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter()
|
||||||
|
|
||||||
// TODO: Add AS support for all handlers below.
|
// TODO: Add AS support for all handlers below.
|
||||||
v3mux.Handle("/sync", httputil.MakeAuthAPI("sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/sync", httputil.MakeAuthAPI("sync", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return srp.OnIncomingSyncRequest(req, device)
|
return srp.OnIncomingSyncRequest(req, device)
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/messages", httputil.MakeAuthAPI("room_messages", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/rooms/{roomID}/messages", httputil.MakeAuthAPI("room_messages", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
@ -58,7 +59,7 @@ func Setup(
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/event/{eventID}",
|
v3mux.Handle("/rooms/{roomID}/event/{eventID}",
|
||||||
httputil.MakeAuthAPI("rooms_get_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_get_event", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -68,7 +69,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userId}/filter",
|
v3mux.Handle("/user/{userId}/filter",
|
||||||
httputil.MakeAuthAPI("put_filter", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("put_filter", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -78,7 +79,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/user/{userId}/filter/{filterId}",
|
v3mux.Handle("/user/{userId}/filter/{filterId}",
|
||||||
httputil.MakeAuthAPI("get_filter", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("get_filter", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -87,12 +88,12 @@ func Setup(
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/keys/changes", httputil.MakeAuthAPI("keys_changes", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
v3mux.Handle("/keys/changes", httputil.MakeAuthAPI("keys_changes", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return srp.OnIncomingKeyChangeRequest(req, device)
|
return srp.OnIncomingKeyChangeRequest(req, device)
|
||||||
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
}, httputil.WithAllowGuests())).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomId}/context/{eventId}",
|
v3mux.Handle("/rooms/{roomId}/context/{eventId}",
|
||||||
httputil.MakeAuthAPI("context", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("context", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -108,7 +109,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}",
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}",
|
||||||
httputil.MakeAuthAPI("relations", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("relations", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -122,7 +123,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}",
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}",
|
||||||
httputil.MakeAuthAPI("relation_type", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("relation_type", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -136,7 +137,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}",
|
v1unstablemux.Handle("/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}",
|
||||||
httputil.MakeAuthAPI("relation_type_event", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("relation_type_event", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
@ -150,7 +151,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/search",
|
v3mux.Handle("/search",
|
||||||
httputil.MakeAuthAPI("search", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("search", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if !cfg.Fulltext.Enabled {
|
if !cfg.Fulltext.Enabled {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusNotImplemented,
|
Code: http.StatusNotImplemented,
|
||||||
|
@ -173,7 +174,7 @@ func Setup(
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/rooms/{roomID}/members",
|
v3mux.Handle("/rooms/{roomID}/members",
|
||||||
httputil.MakeAuthAPI("rooms_members", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("rooms_members", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
|
|
|
@ -42,6 +42,7 @@ func AddPublicRoutes(
|
||||||
userAPI userapi.SyncUserAPI,
|
userAPI userapi.SyncUserAPI,
|
||||||
rsAPI api.SyncRoomserverAPI,
|
rsAPI api.SyncRoomserverAPI,
|
||||||
caches caching.LazyLoadCache,
|
caches caching.LazyLoadCache,
|
||||||
|
userVerifier httputil.UserVerifier,
|
||||||
enableMetrics bool,
|
enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
js, natsClient := natsInstance.Prepare(processContext, &dendriteCfg.Global.JetStream)
|
js, natsClient := natsInstance.Prepare(processContext, &dendriteCfg.Global.JetStream)
|
||||||
|
@ -149,5 +150,6 @@ func AddPublicRoutes(
|
||||||
routers.Client, requestPool, syncDB, userAPI,
|
routers.Client, requestPool, syncDB, userAPI,
|
||||||
rsAPI, &dendriteCfg.SyncAPI, caches, fts,
|
rsAPI, &dendriteCfg.SyncAPI, caches, fts,
|
||||||
rateLimits,
|
rateLimits,
|
||||||
|
userVerifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ type UserInternalAPI interface {
|
||||||
|
|
||||||
QuerySearchProfilesAPI // used by p2p demos
|
QuerySearchProfilesAPI // used by p2p demos
|
||||||
QueryAccountByLocalpart(ctx context.Context, req *QueryAccountByLocalpartRequest, res *QueryAccountByLocalpartResponse) (err error)
|
QueryAccountByLocalpart(ctx context.Context, req *QueryAccountByLocalpartRequest, res *QueryAccountByLocalpartResponse) (err error)
|
||||||
|
QueryExternalUserIDByLocalpartAndProvider(ctx context.Context, req *QueryLocalpartExternalIDRequest, res *QueryLocalpartExternalIDResponse) (err error)
|
||||||
|
PerformLocalpartExternalUserIDCreation(ctx context.Context, req *PerformLocalpartExternalUserIDCreationRequest) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// api functions required by the appservice api
|
// api functions required by the appservice api
|
||||||
|
@ -129,6 +131,7 @@ type QuerySearchProfilesAPI interface {
|
||||||
QuerySearchProfiles(ctx context.Context, req *QuerySearchProfilesRequest, res *QuerySearchProfilesResponse) error
|
QuerySearchProfiles(ctx context.Context, req *QuerySearchProfilesRequest, res *QuerySearchProfilesResponse) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: typo in Acccess
|
||||||
// common function for creating authenticated endpoints (used in client/media/sync api)
|
// common function for creating authenticated endpoints (used in client/media/sync api)
|
||||||
type QueryAcccessTokenAPI interface {
|
type QueryAcccessTokenAPI interface {
|
||||||
QueryAccessToken(ctx context.Context, req *QueryAccessTokenRequest, res *QueryAccessTokenResponse) error
|
QueryAccessToken(ctx context.Context, req *QueryAccessTokenRequest, res *QueryAccessTokenResponse) error
|
||||||
|
@ -316,6 +319,9 @@ type PerformAccountCreationRequest struct {
|
||||||
Localpart string // Required: The localpart for this account. Ignored if account type is guest.
|
Localpart string // Required: The localpart for this account. Ignored if account type is guest.
|
||||||
ServerName spec.ServerName // optional: if not specified, default server name used instead
|
ServerName spec.ServerName // optional: if not specified, default server name used instead
|
||||||
|
|
||||||
|
DisplayName string // optional: this is populated only by MAS. In the legacy flow it's not used
|
||||||
|
AvatarURL string // optional: this is populated only by MAS. In the legacy flow it's not used
|
||||||
|
|
||||||
AppServiceID string // optional: the application service ID (not user ID) creating this account, if any.
|
AppServiceID string // optional: the application service ID (not user ID) creating this account, if any.
|
||||||
Password string // optional: if missing then this account will be a passwordless account
|
Password string // optional: if missing then this account will be a passwordless account
|
||||||
OnConflict Conflict
|
OnConflict Conflict
|
||||||
|
@ -653,10 +659,26 @@ type QueryAccountByLocalpartResponse struct {
|
||||||
Account *Account
|
Account *Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryLocalpartExternalIDRequest struct {
|
||||||
|
ExternalID string
|
||||||
|
AuthProvider string
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryLocalpartExternalIDResponse struct {
|
||||||
|
LocalpartExternalID *LocalpartExternalID
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerformLocalpartExternalUserIDCreationRequest struct {
|
||||||
|
Localpart string
|
||||||
|
ExternalID string
|
||||||
|
AuthProvider string
|
||||||
|
}
|
||||||
|
|
||||||
// API functions required by the clientapi
|
// API functions required by the clientapi
|
||||||
type ClientKeyAPI interface {
|
type ClientKeyAPI interface {
|
||||||
UploadDeviceKeysAPI
|
UploadDeviceKeysAPI
|
||||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse)
|
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse)
|
||||||
|
QueryMasterKeys(ctx context.Context, req *QueryMasterKeysRequest, res *QueryMasterKeysResponse)
|
||||||
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse) error
|
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse) error
|
||||||
|
|
||||||
PerformUploadDeviceSignatures(ctx context.Context, req *PerformUploadDeviceSignaturesRequest, res *PerformUploadDeviceSignaturesResponse)
|
PerformUploadDeviceSignatures(ctx context.Context, req *PerformUploadDeviceSignaturesRequest, res *PerformUploadDeviceSignaturesResponse)
|
||||||
|
@ -918,6 +940,16 @@ type QueryKeysResponse struct {
|
||||||
Error *KeyError
|
Error *KeyError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryMasterKeysRequest struct {
|
||||||
|
UserID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryMasterKeysResponse struct {
|
||||||
|
Key *types.CrossSigningKey
|
||||||
|
// Set if there was a fatal error processing this query
|
||||||
|
Error *KeyError
|
||||||
|
}
|
||||||
|
|
||||||
type QueryKeyChangesRequest struct {
|
type QueryKeyChangesRequest struct {
|
||||||
// The offset of the last received key event, or sarama.OffsetOldest if this is from the beginning
|
// The offset of the last received key event, or sarama.OffsetOldest if this is from the beginning
|
||||||
Offset int64
|
Offset int64
|
||||||
|
|
|
@ -114,7 +114,9 @@ func (a *UserInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.
|
||||||
|
|
||||||
byPurpose[fclient.CrossSigningKeyPurposeMaster] = req.MasterKey
|
byPurpose[fclient.CrossSigningKeyPurposeMaster] = req.MasterKey
|
||||||
for _, key := range req.MasterKey.Keys { // iterates once, see sanityCheckKey
|
for _, key := range req.MasterKey.Keys { // iterates once, see sanityCheckKey
|
||||||
toStore[fclient.CrossSigningKeyPurposeMaster] = key
|
toStore[fclient.CrossSigningKeyPurposeMaster] = types.CrossSigningKey{
|
||||||
|
KeyData: key,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hasMasterKey = true
|
hasMasterKey = true
|
||||||
}
|
}
|
||||||
|
@ -130,7 +132,9 @@ func (a *UserInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.
|
||||||
|
|
||||||
byPurpose[fclient.CrossSigningKeyPurposeSelfSigning] = req.SelfSigningKey
|
byPurpose[fclient.CrossSigningKeyPurposeSelfSigning] = req.SelfSigningKey
|
||||||
for _, key := range req.SelfSigningKey.Keys { // iterates once, see sanityCheckKey
|
for _, key := range req.SelfSigningKey.Keys { // iterates once, see sanityCheckKey
|
||||||
toStore[fclient.CrossSigningKeyPurposeSelfSigning] = key
|
toStore[fclient.CrossSigningKeyPurposeSelfSigning] = types.CrossSigningKey{
|
||||||
|
KeyData: key,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +149,9 @@ func (a *UserInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.
|
||||||
|
|
||||||
byPurpose[fclient.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey
|
byPurpose[fclient.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey
|
||||||
for _, key := range req.UserSigningKey.Keys { // iterates once, see sanityCheckKey
|
for _, key := range req.UserSigningKey.Keys { // iterates once, see sanityCheckKey
|
||||||
toStore[fclient.CrossSigningKeyPurposeUserSigning] = key
|
toStore[fclient.CrossSigningKeyPurposeUserSigning] = types.CrossSigningKey{
|
||||||
|
KeyData: key,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +204,7 @@ func (a *UserInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.
|
||||||
changed = true
|
changed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !bytes.Equal(old, new) {
|
if !bytes.Equal(old.KeyData, new.KeyData) {
|
||||||
// One of the existing keys for a purpose we already knew about has
|
// One of the existing keys for a purpose we already knew about has
|
||||||
// changed.
|
// changed.
|
||||||
changed = true
|
changed = true
|
||||||
|
@ -210,7 +216,7 @@ func (a *UserInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the keys.
|
// Store the keys.
|
||||||
if err := a.KeyDatabase.StoreCrossSigningKeysForUser(ctx, req.UserID, toStore); err != nil {
|
if err := a.KeyDatabase.StoreCrossSigningKeysForUser(ctx, req.UserID, toStore, nil); err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: fmt.Sprintf("a.DB.StoreCrossSigningKeysForUser: %s", err),
|
Err: fmt.Sprintf("a.DB.StoreCrossSigningKeysForUser: %s", err),
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,6 +234,19 @@ func (a *UserInternalAPI) PerformMarkAsStaleIfNeeded(ctx context.Context, req *a
|
||||||
return a.Updater.ManualUpdate(ctx, req.Domain, req.UserID)
|
return a.Updater.ManualUpdate(ctx, req.Domain, req.UserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *UserInternalAPI) QueryMasterKeys(ctx context.Context, req *api.QueryMasterKeysRequest, res *api.QueryMasterKeysResponse) {
|
||||||
|
crossSigningKeyMap, err := a.KeyDatabase.CrossSigningKeysDataForUserAndKeyType(ctx, req.UserID, fclient.CrossSigningKeyPurposeMaster)
|
||||||
|
if err != nil {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: fmt.Sprintf("failed to query user cross signing master keys: %s", err),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if key, ok := crossSigningKeyMap[fclient.CrossSigningKeyPurposeMaster]; ok {
|
||||||
|
res.Key = &key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nolint:gocyclo
|
// nolint:gocyclo
|
||||||
func (a *UserInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) {
|
func (a *UserInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) {
|
||||||
var respMu sync.Mutex
|
var respMu sync.Mutex
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -247,10 +248,17 @@ func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.P
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err = a.DB.SetDisplayName(ctx, req.Localpart, serverName, req.Localpart); err != nil {
|
displayName := cmp.Or(req.DisplayName, req.Localpart)
|
||||||
|
if _, _, err = a.DB.SetDisplayName(ctx, req.Localpart, serverName, displayName); err != nil {
|
||||||
return fmt.Errorf("a.DB.SetDisplayName: %w", err)
|
return fmt.Errorf("a.DB.SetDisplayName: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.AvatarURL != "" {
|
||||||
|
if _, _, err := a.DB.SetAvatarURL(ctx, req.Localpart, serverName, req.AvatarURL); err != nil {
|
||||||
|
return fmt.Errorf("a.DB.SetAvatarURL: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
postRegisterJoinRooms(a.Config, acc, a.RSAPI)
|
postRegisterJoinRooms(a.Config, acc, a.RSAPI)
|
||||||
|
|
||||||
res.AccountCreated = true
|
res.AccountCreated = true
|
||||||
|
@ -594,6 +602,15 @@ func (a *UserInternalAPI) QueryAccountByLocalpart(ctx context.Context, req *api.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *UserInternalAPI) PerformLocalpartExternalUserIDCreation(ctx context.Context, req *api.PerformLocalpartExternalUserIDCreationRequest) (err error) {
|
||||||
|
return a.DB.CreateLocalpartExternalID(ctx, req.Localpart, req.ExternalID, req.AuthProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *UserInternalAPI) QueryExternalUserIDByLocalpartAndProvider(ctx context.Context, req *api.QueryLocalpartExternalIDRequest, res *api.QueryLocalpartExternalIDResponse) (err error) {
|
||||||
|
res.LocalpartExternalID, err = a.DB.GetLocalpartForExternalID(ctx, req.ExternalID, req.AuthProvider)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Return the appservice 'device' or nil if the token is not an appservice. Returns an error if there was a problem
|
// Return the appservice 'device' or nil if the token is not an appservice. Returns an error if there was a problem
|
||||||
// creating a 'device'.
|
// creating a 'device'.
|
||||||
func (a *UserInternalAPI) queryAppServiceToken(ctx context.Context, token, appServiceUserID string) (*api.Device, error) {
|
func (a *UserInternalAPI) queryAppServiceToken(ctx context.Context, token, appServiceUserID string) (*api.Device, error) {
|
||||||
|
|
|
@ -226,9 +226,10 @@ type KeyDatabase interface {
|
||||||
|
|
||||||
CrossSigningKeysForUser(ctx context.Context, userID string) (map[fclient.CrossSigningKeyPurpose]fclient.CrossSigningKey, error)
|
CrossSigningKeysForUser(ctx context.Context, userID string) (map[fclient.CrossSigningKeyPurpose]fclient.CrossSigningKey, error)
|
||||||
CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error)
|
CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error)
|
||||||
|
CrossSigningKeysDataForUserAndKeyType(ctx context.Context, userID string, keyType fclient.CrossSigningKeyPurpose) (types.CrossSigningKeyMap, error)
|
||||||
CrossSigningSigsForTarget(ctx context.Context, originUserID, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error)
|
CrossSigningSigsForTarget(ctx context.Context, originUserID, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error)
|
||||||
|
|
||||||
StoreCrossSigningKeysForUser(ctx context.Context, userID string, keyMap types.CrossSigningKeyMap) error
|
StoreCrossSigningKeysForUser(ctx context.Context, userID string, keyMap types.CrossSigningKeyMap, updatableWithoutUIABeforeMs *int64) error
|
||||||
StoreCrossSigningSigsForTarget(ctx context.Context, originUserID string, originKeyID gomatrixserverlib.KeyID, targetUserID string, targetKeyID gomatrixserverlib.KeyID, signature spec.Base64Bytes) error
|
StoreCrossSigningSigsForTarget(ctx context.Context, originUserID string, originKeyID gomatrixserverlib.KeyID, targetUserID string, targetKeyID gomatrixserverlib.KeyID, signature spec.Base64Bytes) error
|
||||||
|
|
||||||
DeleteStaleDeviceLists(
|
DeleteStaleDeviceLists(
|
||||||
|
|
|
@ -24,14 +24,19 @@ CREATE TABLE IF NOT EXISTS keyserver_cross_signing_keys (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
key_type SMALLINT NOT NULL,
|
key_type SMALLINT NOT NULL,
|
||||||
key_data TEXT NOT NULL,
|
key_data TEXT NOT NULL,
|
||||||
|
updatable_without_uia_before_ms BIGINT DEFAULT NULL,
|
||||||
PRIMARY KEY (user_id, key_type)
|
PRIMARY KEY (user_id, key_type)
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectCrossSigningKeysForUserSQL = "" +
|
const selectCrossSigningKeysForUserSQL = "" +
|
||||||
"SELECT key_type, key_data FROM keyserver_cross_signing_keys" +
|
"SELECT key_type, key_data, updatable_without_uia_before_ms FROM keyserver_cross_signing_keys" +
|
||||||
" WHERE user_id = $1"
|
" WHERE user_id = $1"
|
||||||
|
|
||||||
|
const selectCrossSigningKeysForUserAndKeyTypeSQL = "" +
|
||||||
|
"SELECT key_type, key_data, updatable_without_uia_before_ms FROM keyserver_cross_signing_keys" +
|
||||||
|
" WHERE user_id = $1 AND key_type = $2"
|
||||||
|
|
||||||
const upsertCrossSigningKeysForUserSQL = "" +
|
const upsertCrossSigningKeysForUserSQL = "" +
|
||||||
"INSERT INTO keyserver_cross_signing_keys (user_id, key_type, key_data)" +
|
"INSERT INTO keyserver_cross_signing_keys (user_id, key_type, key_data)" +
|
||||||
" VALUES($1, $2, $3)" +
|
" VALUES($1, $2, $3)" +
|
||||||
|
@ -40,6 +45,7 @@ const upsertCrossSigningKeysForUserSQL = "" +
|
||||||
type crossSigningKeysStatements struct {
|
type crossSigningKeysStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
selectCrossSigningKeysForUserStmt *sql.Stmt
|
selectCrossSigningKeysForUserStmt *sql.Stmt
|
||||||
|
selectCrossSigningKeysForUserAndKeyTypeStmt *sql.Stmt
|
||||||
upsertCrossSigningKeysForUserStmt *sql.Stmt
|
upsertCrossSigningKeysForUserStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +59,7 @@ func NewPostgresCrossSigningKeysTable(db *sql.DB) (tables.CrossSigningKeys, erro
|
||||||
}
|
}
|
||||||
return s, sqlutil.StatementList{
|
return s, sqlutil.StatementList{
|
||||||
{&s.selectCrossSigningKeysForUserStmt, selectCrossSigningKeysForUserSQL},
|
{&s.selectCrossSigningKeysForUserStmt, selectCrossSigningKeysForUserSQL},
|
||||||
|
{&s.selectCrossSigningKeysForUserAndKeyTypeStmt, selectCrossSigningKeysForUserAndKeyTypeSQL},
|
||||||
{&s.upsertCrossSigningKeysForUserStmt, upsertCrossSigningKeysForUserSQL},
|
{&s.upsertCrossSigningKeysForUserStmt, upsertCrossSigningKeysForUserSQL},
|
||||||
}.Prepare(db)
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
@ -69,27 +76,64 @@ func (s *crossSigningKeysStatements) SelectCrossSigningKeysForUser(
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var keyTypeInt int16
|
var keyTypeInt int16
|
||||||
var keyData spec.Base64Bytes
|
var keyData spec.Base64Bytes
|
||||||
if err = rows.Scan(&keyTypeInt, &keyData); err != nil {
|
var updatableWithoutUIABeforeMs *int64
|
||||||
|
if err = rows.Scan(&keyTypeInt, &keyData, &updatableWithoutUIABeforeMs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
||||||
}
|
}
|
||||||
r[keyType] = keyData
|
r[keyType] = types.CrossSigningKey{
|
||||||
|
UpdatableWithoutUIABeforeMs: updatableWithoutUIABeforeMs,
|
||||||
|
KeyData: keyData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *crossSigningKeysStatements) SelectCrossSigningKeysForUserAndKeyType(
|
||||||
|
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose,
|
||||||
|
) (r types.CrossSigningKeyMap, err error) {
|
||||||
|
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown key purpose %q", keyType)
|
||||||
|
}
|
||||||
|
rows, err := sqlutil.TxStmt(txn, s.selectCrossSigningKeysForUserAndKeyTypeStmt).QueryContext(ctx, userID, keyTypeInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer internal.CloseAndLogIfError(ctx, rows, "SelectCrossSigningKeysForUserAndKeyType: rows.close() failed")
|
||||||
|
r = types.CrossSigningKeyMap{}
|
||||||
|
for rows.Next() {
|
||||||
|
var keyTypeInt int16
|
||||||
|
var keyData spec.Base64Bytes
|
||||||
|
var updatableWithoutUIABeforeMs *int64
|
||||||
|
if err = rows.Scan(&keyTypeInt, &keyData, &updatableWithoutUIABeforeMs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
||||||
|
}
|
||||||
|
r[keyType] = types.CrossSigningKey{
|
||||||
|
UpdatableWithoutUIABeforeMs: updatableWithoutUIABeforeMs,
|
||||||
|
KeyData: keyData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *crossSigningKeysStatements) UpsertCrossSigningKeysForUser(
|
func (s *crossSigningKeysStatements) UpsertCrossSigningKeysForUser(
|
||||||
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes,
|
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes, updatableWithoutUIABeforeMs *int64,
|
||||||
) error {
|
) error {
|
||||||
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown key purpose %q", keyType)
|
return fmt.Errorf("unknown key purpose %q", keyType)
|
||||||
}
|
}
|
||||||
if _, err := sqlutil.TxStmt(txn, s.upsertCrossSigningKeysForUserStmt).ExecContext(ctx, userID, keyTypeInt, keyData); err != nil {
|
if _, err := sqlutil.TxStmt(txn, s.upsertCrossSigningKeysForUserStmt).ExecContext(ctx, userID, keyTypeInt, keyData, updatableWithoutUIABeforeMs); err != nil {
|
||||||
return fmt.Errorf("s.upsertCrossSigningKeysForUserStmt: %w", err)
|
return fmt.Errorf("s.upsertCrossSigningKeysForUserStmt: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1101,12 +1101,12 @@ func (d *KeyDatabase) CrossSigningKeysForUser(ctx context.Context, userID string
|
||||||
}
|
}
|
||||||
results := map[fclient.CrossSigningKeyPurpose]fclient.CrossSigningKey{}
|
results := map[fclient.CrossSigningKeyPurpose]fclient.CrossSigningKey{}
|
||||||
for purpose, key := range keyMap {
|
for purpose, key := range keyMap {
|
||||||
keyID := gomatrixserverlib.KeyID("ed25519:" + key.Encode())
|
keyID := gomatrixserverlib.KeyID("ed25519:" + key.KeyData.Encode())
|
||||||
result := fclient.CrossSigningKey{
|
result := fclient.CrossSigningKey{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Usage: []fclient.CrossSigningKeyPurpose{purpose},
|
Usage: []fclient.CrossSigningKeyPurpose{purpose},
|
||||||
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{
|
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{
|
||||||
keyID: key,
|
keyID: key.KeyData,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
sigMap, err := d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, userID, userID, keyID)
|
sigMap, err := d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, userID, userID, keyID)
|
||||||
|
@ -1137,16 +1137,21 @@ func (d *KeyDatabase) CrossSigningKeysDataForUser(ctx context.Context, userID st
|
||||||
return d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID)
|
return d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CrossSigningKeysForUserAndKeyType returns the latest known cross-signing keys for a user and key type, if any.
|
||||||
|
func (d *KeyDatabase) CrossSigningKeysDataForUserAndKeyType(ctx context.Context, userID string, keyType fclient.CrossSigningKeyPurpose) (types.CrossSigningKeyMap, error) {
|
||||||
|
return d.CrossSigningKeysTable.SelectCrossSigningKeysForUserAndKeyType(ctx, nil, userID, keyType)
|
||||||
|
}
|
||||||
|
|
||||||
// CrossSigningSigsForTarget returns the signatures for a given user's key ID, if any.
|
// CrossSigningSigsForTarget returns the signatures for a given user's key ID, if any.
|
||||||
func (d *KeyDatabase) CrossSigningSigsForTarget(ctx context.Context, originUserID, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error) {
|
func (d *KeyDatabase) CrossSigningSigsForTarget(ctx context.Context, originUserID, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error) {
|
||||||
return d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, originUserID, targetUserID, targetKeyID)
|
return d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, originUserID, targetUserID, targetKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreCrossSigningKeysForUser stores the latest known cross-signing keys for a user.
|
// StoreCrossSigningKeysForUser stores the latest known cross-signing keys for a user.
|
||||||
func (d *KeyDatabase) StoreCrossSigningKeysForUser(ctx context.Context, userID string, keyMap types.CrossSigningKeyMap) error {
|
func (d *KeyDatabase) StoreCrossSigningKeysForUser(ctx context.Context, userID string, keyMap types.CrossSigningKeyMap, updatableWithoutUIABeforeMs *int64) error {
|
||||||
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
||||||
for keyType, keyData := range keyMap {
|
for keyType, key := range keyMap {
|
||||||
if err := d.CrossSigningKeysTable.UpsertCrossSigningKeysForUser(ctx, txn, userID, keyType, keyData); err != nil {
|
if err := d.CrossSigningKeysTable.UpsertCrossSigningKeysForUser(ctx, txn, userID, keyType, key.KeyData, key.UpdatableWithoutUIABeforeMs); err != nil {
|
||||||
return fmt.Errorf("d.CrossSigningKeysTable.InsertCrossSigningKeysForUser: %w", err)
|
return fmt.Errorf("d.CrossSigningKeysTable.InsertCrossSigningKeysForUser: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,21 +24,27 @@ CREATE TABLE IF NOT EXISTS keyserver_cross_signing_keys (
|
||||||
user_id TEXT NOT NULL,
|
user_id TEXT NOT NULL,
|
||||||
key_type INTEGER NOT NULL,
|
key_type INTEGER NOT NULL,
|
||||||
key_data TEXT NOT NULL,
|
key_data TEXT NOT NULL,
|
||||||
|
updatable_without_uia_before_ms BIGINT DEFAULT NULL,
|
||||||
PRIMARY KEY (user_id, key_type)
|
PRIMARY KEY (user_id, key_type)
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
const selectCrossSigningKeysForUserSQL = "" +
|
const selectCrossSigningKeysForUserSQL = "" +
|
||||||
"SELECT key_type, key_data FROM keyserver_cross_signing_keys" +
|
"SELECT key_type, key_data, updatable_without_uia_before_ms FROM keyserver_cross_signing_keys" +
|
||||||
" WHERE user_id = $1"
|
" WHERE user_id = $1"
|
||||||
|
|
||||||
|
const selectCrossSigningKeysForUserAndKeyTypeSQL = "" +
|
||||||
|
"SELECT key_type, key_data, updatable_without_uia_before_ms FROM keyserver_cross_signing_keys" +
|
||||||
|
" WHERE user_id = $1 AND key_type = $2"
|
||||||
|
|
||||||
const upsertCrossSigningKeysForUserSQL = "" +
|
const upsertCrossSigningKeysForUserSQL = "" +
|
||||||
"INSERT OR REPLACE INTO keyserver_cross_signing_keys (user_id, key_type, key_data)" +
|
"INSERT OR REPLACE INTO keyserver_cross_signing_keys (user_id, key_type, key_data, updatable_without_uia_before_ms)" +
|
||||||
" VALUES($1, $2, $3)"
|
" VALUES($1, $2, $3, $4)"
|
||||||
|
|
||||||
type crossSigningKeysStatements struct {
|
type crossSigningKeysStatements struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
selectCrossSigningKeysForUserStmt *sql.Stmt
|
selectCrossSigningKeysForUserStmt *sql.Stmt
|
||||||
|
selectCrossSigningKeysForUserAndKeyTypeStmt *sql.Stmt
|
||||||
upsertCrossSigningKeysForUserStmt *sql.Stmt
|
upsertCrossSigningKeysForUserStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +58,7 @@ func NewSqliteCrossSigningKeysTable(db *sql.DB) (tables.CrossSigningKeys, error)
|
||||||
}
|
}
|
||||||
return s, sqlutil.StatementList{
|
return s, sqlutil.StatementList{
|
||||||
{&s.selectCrossSigningKeysForUserStmt, selectCrossSigningKeysForUserSQL},
|
{&s.selectCrossSigningKeysForUserStmt, selectCrossSigningKeysForUserSQL},
|
||||||
|
{&s.selectCrossSigningKeysForUserAndKeyTypeStmt, selectCrossSigningKeysForUserAndKeyTypeSQL},
|
||||||
{&s.upsertCrossSigningKeysForUserStmt, upsertCrossSigningKeysForUserSQL},
|
{&s.upsertCrossSigningKeysForUserStmt, upsertCrossSigningKeysForUserSQL},
|
||||||
}.Prepare(db)
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
@ -68,27 +75,64 @@ func (s *crossSigningKeysStatements) SelectCrossSigningKeysForUser(
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var keyTypeInt int16
|
var keyTypeInt int16
|
||||||
var keyData spec.Base64Bytes
|
var keyData spec.Base64Bytes
|
||||||
if err = rows.Scan(&keyTypeInt, &keyData); err != nil {
|
var updatableWithoutUiaBeforeMs *int64
|
||||||
|
if err = rows.Scan(&keyTypeInt, &keyData, &updatableWithoutUiaBeforeMs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
||||||
}
|
}
|
||||||
r[keyType] = keyData
|
r[keyType] = types.CrossSigningKey{
|
||||||
|
UpdatableWithoutUIABeforeMs: updatableWithoutUiaBeforeMs,
|
||||||
|
KeyData: keyData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *crossSigningKeysStatements) SelectCrossSigningKeysForUserAndKeyType(
|
||||||
|
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose,
|
||||||
|
) (r types.CrossSigningKeyMap, err error) {
|
||||||
|
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown key purpose %q", keyType)
|
||||||
|
}
|
||||||
|
rows, err := sqlutil.TxStmt(txn, s.selectCrossSigningKeysForUserAndKeyTypeStmt).QueryContext(ctx, userID, keyTypeInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer internal.CloseAndLogIfError(ctx, rows, "SelectCrossSigningKeysForUserAndKeyType: rows.close() failed")
|
||||||
|
r = types.CrossSigningKeyMap{}
|
||||||
|
for rows.Next() {
|
||||||
|
var keyTypeInt int16
|
||||||
|
var keyData spec.Base64Bytes
|
||||||
|
var updatableWithoutUIABeforeMs *int64
|
||||||
|
if err = rows.Scan(&keyTypeInt, &keyData, &updatableWithoutUIABeforeMs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keyType, ok := types.KeyTypeIntToPurpose[keyTypeInt]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown key purpose int %d", keyTypeInt)
|
||||||
|
}
|
||||||
|
r[keyType] = types.CrossSigningKey{
|
||||||
|
UpdatableWithoutUIABeforeMs: updatableWithoutUIABeforeMs,
|
||||||
|
KeyData: keyData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *crossSigningKeysStatements) UpsertCrossSigningKeysForUser(
|
func (s *crossSigningKeysStatements) UpsertCrossSigningKeysForUser(
|
||||||
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes,
|
ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes, updatableWithoutUIABeforeMs *int64,
|
||||||
) error {
|
) error {
|
||||||
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
keyTypeInt, ok := types.KeyTypePurposeToInt[keyType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown key purpose %q", keyType)
|
return fmt.Errorf("unknown key purpose %q", keyType)
|
||||||
}
|
}
|
||||||
if _, err := sqlutil.TxStmt(txn, s.upsertCrossSigningKeysForUserStmt).ExecContext(ctx, userID, keyTypeInt, keyData); err != nil {
|
if _, err := sqlutil.TxStmt(txn, s.upsertCrossSigningKeysForUserStmt).ExecContext(ctx, userID, keyTypeInt, keyData, updatableWithoutUIABeforeMs); err != nil {
|
||||||
return fmt.Errorf("s.upsertCrossSigningKeysForUserStmt: %w", err)
|
return fmt.Errorf("s.upsertCrossSigningKeysForUserStmt: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -133,10 +133,6 @@ type LocalpartExternalIDsTable interface {
|
||||||
Delete(ctx context.Context, txn *sql.Tx, externalID, authProvider string) error
|
Delete(ctx context.Context, txn *sql.Tx, externalID, authProvider string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type UIAuthSessionsTable interface {
|
|
||||||
SelectByID(ctx context.Context, txn *sql.Tx, sessionID int) (*api.UIAuthSession, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotificationFilter uint32
|
type NotificationFilter uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -202,7 +198,8 @@ type StaleDeviceLists interface {
|
||||||
|
|
||||||
type CrossSigningKeys interface {
|
type CrossSigningKeys interface {
|
||||||
SelectCrossSigningKeysForUser(ctx context.Context, txn *sql.Tx, userID string) (r types.CrossSigningKeyMap, err error)
|
SelectCrossSigningKeysForUser(ctx context.Context, txn *sql.Tx, userID string) (r types.CrossSigningKeyMap, err error)
|
||||||
UpsertCrossSigningKeysForUser(ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes) error
|
SelectCrossSigningKeysForUserAndKeyType(ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose) (r types.CrossSigningKeyMap, err error)
|
||||||
|
UpsertCrossSigningKeysForUser(ctx context.Context, txn *sql.Tx, userID string, keyType fclient.CrossSigningKeyPurpose, keyData spec.Base64Bytes, updatableWithoutUIABeforeMs *int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type CrossSigningSigs interface {
|
type CrossSigningSigs interface {
|
||||||
|
|
|
@ -37,8 +37,13 @@ var KeyTypeIntToPurpose = map[int16]fclient.CrossSigningKeyPurpose{
|
||||||
3: fclient.CrossSigningKeyPurposeUserSigning,
|
3: fclient.CrossSigningKeyPurposeUserSigning,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CrossSigningKey struct {
|
||||||
|
UpdatableWithoutUIABeforeMs *int64
|
||||||
|
KeyData spec.Base64Bytes
|
||||||
|
}
|
||||||
|
|
||||||
// Map of purpose -> public key
|
// Map of purpose -> public key
|
||||||
type CrossSigningKeyMap map[fclient.CrossSigningKeyPurpose]spec.Base64Bytes
|
type CrossSigningKeyMap map[fclient.CrossSigningKeyPurpose]CrossSigningKey
|
||||||
|
|
||||||
// Map of user ID -> key ID -> signature
|
// Map of user ID -> key ID -> signature
|
||||||
type CrossSigningSigMap map[string]map[gomatrixserverlib.KeyID]spec.Base64Bytes
|
type CrossSigningSigMap map[string]map[gomatrixserverlib.KeyID]spec.Base64Bytes
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue