mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-16 14:12:24 +03:00
mas: cross signing fixes after merge
This commit is contained in:
parent
6833e99558
commit
b44f899637
1 changed files with 87 additions and 58 deletions
|
@ -9,10 +9,9 @@ package routing
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/element-hq/dendrite/clientapi/httputil"
|
"github.com/element-hq/dendrite/clientapi/httputil"
|
||||||
|
@ -32,6 +31,7 @@ type crossSigningRequest struct {
|
||||||
|
|
||||||
type UploadKeysAPI interface {
|
type UploadKeysAPI interface {
|
||||||
QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse)
|
QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse)
|
||||||
|
QueryMasterKeys(ctx context.Context, req *api.QueryMasterKeysRequest, res *api.QueryMasterKeysResponse)
|
||||||
api.UploadDeviceKeysAPI
|
api.UploadDeviceKeysAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ func UploadCrossSigningDeviceKeys(
|
||||||
keyserverAPI UploadKeysAPI, device *api.Device,
|
keyserverAPI UploadKeysAPI, device *api.Device,
|
||||||
accountAPI auth.GetAccountByPassword, cfg *config.ClientAPI,
|
accountAPI auth.GetAccountByPassword, cfg *config.ClientAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
|
logger := util.GetLogger(req.Context())
|
||||||
uploadReq := &crossSigningRequest{}
|
uploadReq := &crossSigningRequest{}
|
||||||
uploadRes := &api.PerformUploadDeviceKeysResponse{}
|
uploadRes := &api.PerformUploadDeviceKeysResponse{}
|
||||||
|
|
||||||
|
@ -48,6 +49,11 @@ func UploadCrossSigningDeviceKeys(
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionID := uploadReq.Auth.Session
|
||||||
|
if sessionID == "" {
|
||||||
|
sessionID = util.RandomString(sessionIDLength)
|
||||||
|
}
|
||||||
|
|
||||||
// Query existing keys to determine if UIA is required
|
// Query existing keys to determine if UIA is required
|
||||||
keyResp := api.QueryKeysResponse{}
|
keyResp := api.QueryKeysResponse{}
|
||||||
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
|
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
|
||||||
|
@ -57,26 +63,68 @@ func UploadCrossSigningDeviceKeys(
|
||||||
}, &keyResp)
|
}, &keyResp)
|
||||||
|
|
||||||
if keyResp.Error != nil {
|
if keyResp.Error != nil {
|
||||||
logrus.WithError(keyResp.Error).Error("Failed to query keys")
|
logger.WithError(keyResp.Error).Error("Failed to query keys")
|
||||||
return util.JSONResponse{
|
return convertKeyError(keyResp.Error)
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.Unknown(keyResp.Error.Error()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
existingMasterKey, hasMasterKey := keyResp.MasterKeys[device.UserID]
|
existingMasterKey, hasMasterKey := keyResp.MasterKeys[device.UserID]
|
||||||
requireUIA := false
|
requireUIA := true
|
||||||
|
|
||||||
if hasMasterKey {
|
if hasMasterKey {
|
||||||
// If we have a master key, check if any of the existing keys differ. If they do,
|
if !keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID) {
|
||||||
// we need to re-authenticate the user.
|
// If we have a master key, check if any of the existing keys differ. If they don't
|
||||||
requireUIA = keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID)
|
// we return 200 as keys are still valid and there's nothing to do.
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// With MSC3861, UIA is not possible. Instead, the auth service has to explicitly mark the master key as replaceable.
|
||||||
|
if cfg.MSCs.MSC3861Enabled() {
|
||||||
|
masterKeyResp := api.QueryMasterKeysResponse{}
|
||||||
|
keyserverAPI.QueryMasterKeys(req.Context(), &api.QueryMasterKeysRequest{UserID: device.UserID}, &masterKeyResp)
|
||||||
|
|
||||||
|
if masterKeyResp.Error != nil {
|
||||||
|
logger.WithError(masterKeyResp.Error).Error("Failed to query master key")
|
||||||
|
return convertKeyError(masterKeyResp.Error)
|
||||||
|
}
|
||||||
|
if k := masterKeyResp.Key; k != nil && k.UpdatableWithoutUIABeforeMs != nil {
|
||||||
|
requireUIA = !(time.Now().UnixMilli() < *k.UpdatableWithoutUIABeforeMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if requireUIA {
|
if requireUIA {
|
||||||
sessionID := uploadReq.Auth.Session
|
url := ""
|
||||||
if sessionID == "" {
|
if m := cfg.MSCs.MSC3861; m.AccountManagementURL != "" {
|
||||||
sessionID = util.RandomString(sessionIDLength)
|
url = strings.Join([]string{m.AccountManagementURL, "?action=", CrossSigningResetStage}, "")
|
||||||
|
} else {
|
||||||
|
url = m.Issuer
|
||||||
}
|
}
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: newUserInteractiveResponse(
|
||||||
|
"dummy",
|
||||||
|
[]authtypes.Flow{
|
||||||
|
{
|
||||||
|
Stages: []authtypes.LoginType{CrossSigningResetStage},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
CrossSigningResetStage: 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, CrossSigningResetStage)
|
||||||
|
} 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,
|
||||||
|
@ -88,6 +136,7 @@ func UploadCrossSigningDeviceKeys(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
|
"",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,33 +149,13 @@ func UploadCrossSigningDeviceKeys(
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
|
||||||
if err := uploadRes.Error; err != nil {
|
if err := uploadRes.Error; err != nil {
|
||||||
switch {
|
return convertKeyError(err)
|
||||||
case err.IsInvalidSignature:
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.InvalidSignature(err.Error()),
|
|
||||||
}
|
|
||||||
case err.IsMissingParam:
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.MissingParam(err.Error()),
|
|
||||||
}
|
|
||||||
case err.IsInvalidParam:
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.InvalidParam(err.Error()),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.Unknown(err.Error()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue