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 (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/element-hq/dendrite/clientapi/auth"
|
||||
"github.com/element-hq/dendrite/clientapi/auth/authtypes"
|
||||
"github.com/element-hq/dendrite/clientapi/httputil"
|
||||
|
@ -32,6 +31,7 @@ type crossSigningRequest struct {
|
|||
|
||||
type UploadKeysAPI interface {
|
||||
QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse)
|
||||
QueryMasterKeys(ctx context.Context, req *api.QueryMasterKeysRequest, res *api.QueryMasterKeysResponse)
|
||||
api.UploadDeviceKeysAPI
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ func UploadCrossSigningDeviceKeys(
|
|||
keyserverAPI UploadKeysAPI, device *api.Device,
|
||||
accountAPI auth.GetAccountByPassword, cfg *config.ClientAPI,
|
||||
) util.JSONResponse {
|
||||
logger := util.GetLogger(req.Context())
|
||||
uploadReq := &crossSigningRequest{}
|
||||
uploadRes := &api.PerformUploadDeviceKeysResponse{}
|
||||
|
||||
|
@ -48,6 +49,11 @@ func UploadCrossSigningDeviceKeys(
|
|||
return *resErr
|
||||
}
|
||||
|
||||
sessionID := uploadReq.Auth.Session
|
||||
if sessionID == "" {
|
||||
sessionID = util.RandomString(sessionIDLength)
|
||||
}
|
||||
|
||||
// Query existing keys to determine if UIA is required
|
||||
keyResp := api.QueryKeysResponse{}
|
||||
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
|
||||
|
@ -57,26 +63,68 @@ func UploadCrossSigningDeviceKeys(
|
|||
}, &keyResp)
|
||||
|
||||
if keyResp.Error != nil {
|
||||
logrus.WithError(keyResp.Error).Error("Failed to query keys")
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
JSON: spec.Unknown(keyResp.Error.Error()),
|
||||
}
|
||||
logger.WithError(keyResp.Error).Error("Failed to query keys")
|
||||
return convertKeyError(keyResp.Error)
|
||||
}
|
||||
|
||||
existingMasterKey, hasMasterKey := keyResp.MasterKeys[device.UserID]
|
||||
requireUIA := false
|
||||
requireUIA := true
|
||||
|
||||
if hasMasterKey {
|
||||
// If we have a master key, check if any of the existing keys differ. If they do,
|
||||
// we need to re-authenticate the user.
|
||||
requireUIA = keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID)
|
||||
if !keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID) {
|
||||
// If we have a master key, check if any of the existing keys differ. If they don't
|
||||
// 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 {
|
||||
sessionID := uploadReq.Auth.Session
|
||||
if sessionID == "" {
|
||||
sessionID = util.RandomString(sessionIDLength)
|
||||
url := ""
|
||||
if m := cfg.MSCs.MSC3861; m.AccountManagementURL != "" {
|
||||
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 {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusUnauthorized,
|
||||
|
@ -88,6 +136,7 @@ func UploadCrossSigningDeviceKeys(
|
|||
},
|
||||
},
|
||||
nil,
|
||||
"",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -100,33 +149,13 @@ func UploadCrossSigningDeviceKeys(
|
|||
}
|
||||
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
|
||||
}
|
||||
}
|
||||
|
||||
uploadReq.UserID = device.UserID
|
||||
keyserverAPI.PerformUploadDeviceKeys(req.Context(), &uploadReq.PerformUploadDeviceKeysRequest, uploadRes)
|
||||
|
||||
if err := uploadRes.Error; err != nil {
|
||||
switch {
|
||||
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 convertKeyError(err)
|
||||
}
|
||||
|
||||
return util.JSONResponse{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue