mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-29 01:33:10 -06:00
Merge branch 'master' of https://github.com/matrix-org/dendrite into add-presence
This commit is contained in:
commit
2b0261cd70
|
|
@ -120,6 +120,11 @@ func main() {
|
||||||
Impl: userAPI,
|
Impl: userAPI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// needs to be after the SetUserAPI call above
|
||||||
|
if base.UseHTTPAPIs {
|
||||||
|
keyserver.AddInternalRoutes(base.InternalAPIMux, keyAPI)
|
||||||
|
keyAPI = base.KeyServerHTTPClient()
|
||||||
|
}
|
||||||
|
|
||||||
eduInputAPI := eduserver.NewInternalAPI(
|
eduInputAPI := eduserver.NewInternalAPI(
|
||||||
base, cache.New(), userAPI,
|
base, cache.New(), userAPI,
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,27 @@ func GetUserDevices(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sigReq := &keyapi.QuerySignaturesRequest{
|
||||||
|
TargetIDs: map[string][]gomatrixserverlib.KeyID{
|
||||||
|
userID: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sigRes := &keyapi.QuerySignaturesResponse{}
|
||||||
|
keyAPI.QuerySignatures(req.Context(), sigReq, sigRes)
|
||||||
|
|
||||||
response := gomatrixserverlib.RespUserDevices{
|
response := gomatrixserverlib.RespUserDevices{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
StreamID: res.StreamID,
|
StreamID: res.StreamID,
|
||||||
Devices: []gomatrixserverlib.RespUserDevice{},
|
Devices: []gomatrixserverlib.RespUserDevice{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if masterKey, ok := sigRes.MasterKeys[userID]; ok {
|
||||||
|
response.MasterKey = &masterKey
|
||||||
|
}
|
||||||
|
if selfSigningKey, ok := sigRes.SelfSigningKeys[userID]; ok {
|
||||||
|
response.SelfSigningKey = &selfSigningKey
|
||||||
|
}
|
||||||
|
|
||||||
for _, dev := range res.Devices {
|
for _, dev := range res.Devices {
|
||||||
var key gomatrixserverlib.RespUserDeviceKeys
|
var key gomatrixserverlib.RespUserDeviceKeys
|
||||||
err := json.Unmarshal(dev.DeviceKeys.KeyJSON, &key)
|
err := json.Unmarshal(dev.DeviceKeys.KeyJSON, &key)
|
||||||
|
|
@ -56,6 +71,20 @@ func GetUserDevices(
|
||||||
DisplayName: dev.DisplayName,
|
DisplayName: dev.DisplayName,
|
||||||
Keys: key,
|
Keys: key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if targetUser, ok := sigRes.Signatures[userID]; ok {
|
||||||
|
if targetKey, ok := targetUser[gomatrixserverlib.KeyID(dev.DeviceID)]; ok {
|
||||||
|
for sourceUserID, forSourceUser := range targetKey {
|
||||||
|
for sourceKeyID, sourceKey := range forSourceUser {
|
||||||
|
if _, ok := device.Keys.Signatures[sourceUserID]; !ok {
|
||||||
|
device.Keys.Signatures[sourceUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{}
|
||||||
|
}
|
||||||
|
device.Keys.Signatures[sourceUserID][sourceKeyID] = sourceKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
response.Devices = append(response.Devices, device)
|
response.Devices = append(response.Devices, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,13 @@ func QueryDeviceKeys(
|
||||||
Code: 200,
|
Code: 200,
|
||||||
JSON: struct {
|
JSON: struct {
|
||||||
DeviceKeys interface{} `json:"device_keys"`
|
DeviceKeys interface{} `json:"device_keys"`
|
||||||
}{queryRes.DeviceKeys},
|
MasterKeys interface{} `json:"master_keys"`
|
||||||
|
SelfSigningKeys interface{} `json:"self_signing_keys"`
|
||||||
|
}{
|
||||||
|
queryRes.DeviceKeys,
|
||||||
|
queryRes.MasterKeys,
|
||||||
|
queryRes.SelfSigningKeys,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -31,7 +31,7 @@ require (
|
||||||
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4
|
github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b
|
||||||
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0
|
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0
|
||||||
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b
|
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b
|
||||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -994,8 +994,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d/go.mod h1
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83 h1:fkUmeKj/U5TnWXTsJnVjEL0FQiVhf1r9WL4VWI00q2k=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b h1:8St1B8QmlvMLsOmGqW3++0akUs0250IAi+AGcr5faxw=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU=
|
||||||
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 h1:HZCzy4oVzz55e+cOMiX/JtSF2UOY1evBl2raaE7ACcU=
|
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 h1:HZCzy4oVzz55e+cOMiX/JtSF2UOY1evBl2raaE7ACcU=
|
||||||
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0/go.mod h1:sjyPyRxKM5uw1nD2cJ6O2OxI6GOqyVBfNXqKjBZTBZE=
|
github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0/go.mod h1:sjyPyRxKM5uw1nD2cJ6O2OxI6GOqyVBfNXqKjBZTBZE=
|
||||||
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b h1:5X5vdWQ13xrNkJVqaJHPsrt7rKkMJH5iac0EtfOuxSg=
|
github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b h1:5X5vdWQ13xrNkJVqaJHPsrt7rKkMJH5iac0EtfOuxSg=
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/keyserver/types"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
@ -38,6 +39,7 @@ type KeyInternalAPI interface {
|
||||||
QueryKeyChanges(ctx context.Context, req *QueryKeyChangesRequest, res *QueryKeyChangesResponse)
|
QueryKeyChanges(ctx context.Context, req *QueryKeyChangesRequest, res *QueryKeyChangesResponse)
|
||||||
QueryOneTimeKeys(ctx context.Context, req *QueryOneTimeKeysRequest, res *QueryOneTimeKeysResponse)
|
QueryOneTimeKeys(ctx context.Context, req *QueryOneTimeKeysRequest, res *QueryOneTimeKeysResponse)
|
||||||
QueryDeviceMessages(ctx context.Context, req *QueryDeviceMessagesRequest, res *QueryDeviceMessagesResponse)
|
QueryDeviceMessages(ctx context.Context, req *QueryDeviceMessagesRequest, res *QueryDeviceMessagesResponse)
|
||||||
|
QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyError is returned if there was a problem performing/querying the server
|
// KeyError is returned if there was a problem performing/querying the server
|
||||||
|
|
@ -158,7 +160,7 @@ type PerformClaimKeysResponse struct {
|
||||||
type PerformUploadDeviceKeysRequest struct {
|
type PerformUploadDeviceKeysRequest struct {
|
||||||
gomatrixserverlib.CrossSigningKeys
|
gomatrixserverlib.CrossSigningKeys
|
||||||
// The user that uploaded the key, should be populated by the clientapi.
|
// The user that uploaded the key, should be populated by the clientapi.
|
||||||
UserID string `json:"user_id"`
|
UserID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformUploadDeviceKeysResponse struct {
|
type PerformUploadDeviceKeysResponse struct {
|
||||||
|
|
@ -168,7 +170,7 @@ type PerformUploadDeviceKeysResponse struct {
|
||||||
type PerformUploadDeviceSignaturesRequest struct {
|
type PerformUploadDeviceSignaturesRequest struct {
|
||||||
Signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice
|
Signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice
|
||||||
// The user that uploaded the sig, should be populated by the clientapi.
|
// The user that uploaded the sig, should be populated by the clientapi.
|
||||||
UserID string `json:"user_id"`
|
UserID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformUploadDeviceSignaturesResponse struct {
|
type PerformUploadDeviceSignaturesResponse struct {
|
||||||
|
|
@ -242,6 +244,24 @@ type QueryDeviceMessagesResponse struct {
|
||||||
Error *KeyError
|
Error *KeyError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QuerySignaturesRequest struct {
|
||||||
|
// A map of target user ID -> target key/device IDs to retrieve signatures for
|
||||||
|
TargetIDs map[string][]gomatrixserverlib.KeyID `json:"target_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QuerySignaturesResponse struct {
|
||||||
|
// A map of target user ID -> target key/device ID -> origin user ID -> origin key/device ID -> signatures
|
||||||
|
Signatures map[string]map[gomatrixserverlib.KeyID]types.CrossSigningSigMap
|
||||||
|
// A map of target user ID -> cross-signing master key
|
||||||
|
MasterKeys map[string]gomatrixserverlib.CrossSigningKey
|
||||||
|
// A map of target user ID -> cross-signing self-signing key
|
||||||
|
SelfSigningKeys map[string]gomatrixserverlib.CrossSigningKey
|
||||||
|
// A map of target user ID -> cross-signing user-signing key
|
||||||
|
UserSigningKeys map[string]gomatrixserverlib.CrossSigningKey
|
||||||
|
// The request error, if any
|
||||||
|
Error *KeyError
|
||||||
|
}
|
||||||
|
|
||||||
type InputDeviceListUpdateRequest struct {
|
type InputDeviceListUpdateRequest struct {
|
||||||
Event gomatrixserverlib.DeviceListUpdateEvent
|
Event gomatrixserverlib.DeviceListUpdateEvent
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,10 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -77,8 +79,8 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hasMasterKey = true
|
|
||||||
for _, keyData := range req.MasterKey.Keys { // iterates once, because sanityCheckKey requires one key
|
for _, keyData := range req.MasterKey.Keys { // iterates once, because sanityCheckKey requires one key
|
||||||
|
hasMasterKey = true
|
||||||
masterKey = keyData
|
masterKey = keyData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +106,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
// If the user hasn't given a new master key, then let's go and get their
|
// If the user hasn't given a new master key, then let's go and get their
|
||||||
// existing keys from the database.
|
// existing keys from the database.
|
||||||
if !hasMasterKey {
|
if !hasMasterKey {
|
||||||
existingKeys, err := a.DB.CrossSigningKeysForUser(ctx, req.UserID)
|
existingKeys, err := a.DB.CrossSigningKeysDataForUser(ctx, req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: "Retrieving cross-signing keys from database failed: " + err.Error(),
|
Err: "Retrieving cross-signing keys from database failed: " + err.Error(),
|
||||||
|
|
@ -115,46 +117,11 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
masterKey, hasMasterKey = existingKeys[gomatrixserverlib.CrossSigningKeyPurposeMaster]
|
masterKey, hasMasterKey = existingKeys[gomatrixserverlib.CrossSigningKeyPurposeMaster]
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user isn't a local user and we haven't successfully found a key
|
|
||||||
// through any local means then ask over federation.
|
|
||||||
if !hasMasterKey {
|
|
||||||
_, host, err := gomatrixserverlib.SplitID('@', req.UserID)
|
|
||||||
if err != nil {
|
|
||||||
res.Error = &api.KeyError{
|
|
||||||
Err: "Retrieving cross-signing keys from federation failed: " + err.Error(),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keys, err := a.FedClient.QueryKeys(ctx, host, map[string][]string{
|
|
||||||
req.UserID: {},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
res.Error = &api.KeyError{
|
|
||||||
Err: "Retrieving cross-signing keys from federation failed: " + err.Error(),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch k := keys.MasterKeys[req.UserID].CrossSigningBody.(type) {
|
|
||||||
case *gomatrixserverlib.CrossSigningKey:
|
|
||||||
if err := sanityCheckKey(*k, req.UserID, gomatrixserverlib.CrossSigningKeyPurposeMaster); err != nil {
|
|
||||||
res.Error = &api.KeyError{
|
|
||||||
Err: "Master key sanity check failed: " + err.Error(),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
res.Error = &api.KeyError{
|
|
||||||
Err: "Unexpected type for master key retrieved from federation",
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we still don't have a master key at this point then there's nothing else
|
// If we still don't have a master key at this point then there's nothing else
|
||||||
// we can do - we've checked both the request and the database.
|
// we can do - we've checked both the request and the database.
|
||||||
if !hasMasterKey {
|
if !hasMasterKey {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: "No master key was found, either in the database or in the request!",
|
Err: "No master key was found either in the database or in the request!",
|
||||||
IsMissingParam: true,
|
IsMissingParam: true,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
@ -175,14 +142,18 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
if len(req.UserSigningKey.Keys) > 0 {
|
if len(req.UserSigningKey.Keys) > 0 {
|
||||||
toVerify[gomatrixserverlib.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey
|
toVerify[gomatrixserverlib.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(toVerify) == 0 {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: "No supplied keys available for verification",
|
||||||
|
IsMissingParam: true,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for purpose, key := range toVerify {
|
for purpose, key := range toVerify {
|
||||||
// Collect together the key IDs we need to verify with. This will include
|
// Collect together the key IDs we need to verify with. This will include
|
||||||
// all of the key IDs specified in the signatures. We don't do this for
|
// all of the key IDs specified in the signatures.
|
||||||
// the master key because we have no means to verify the signatures - we
|
|
||||||
// instead just need to store them.
|
|
||||||
if purpose != gomatrixserverlib.CrossSigningKeyPurposeMaster {
|
|
||||||
// Marshal the specific key back into JSON so that we can verify the
|
|
||||||
// signature of it.
|
|
||||||
keyJSON, err := json.Marshal(key)
|
keyJSON, err := json.Marshal(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
|
|
@ -191,7 +162,15 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now check if the subkey is signed by the master key.
|
switch purpose {
|
||||||
|
case gomatrixserverlib.CrossSigningKeyPurposeMaster:
|
||||||
|
// The master key might have a signature attached to it from the
|
||||||
|
// previous key, or from a device key, but there's no real need
|
||||||
|
// to verify it. Clients will perform key checks when the master
|
||||||
|
// key changes.
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Sub-keys should be signed by the master key.
|
||||||
if err := gomatrixserverlib.VerifyJSON(req.UserID, masterKeyID, ed25519.PublicKey(masterKey), keyJSON); err != nil {
|
if err := gomatrixserverlib.VerifyJSON(req.UserID, masterKeyID, ed25519.PublicKey(masterKey), keyJSON); err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: fmt.Sprintf("The %q sub-key failed master key signature verification: %s", purpose, err.Error()),
|
Err: fmt.Sprintf("The %q sub-key failed master key signature verification: %s", purpose, err.Error()),
|
||||||
|
|
@ -208,17 +187,61 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(toStore) == 0 {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: "No supplied keys passed verification",
|
||||||
|
IsMissingParam: true,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := a.DB.StoreCrossSigningKeysForUser(ctx, req.UserID, toStore); err != nil {
|
if err := a.DB.StoreCrossSigningKeysForUser(ctx, req.UserID, toStore); 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),
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now upload any signatures that were included with the keys.
|
||||||
|
for _, key := range toVerify {
|
||||||
|
var targetKeyID gomatrixserverlib.KeyID
|
||||||
|
for targetKey := range key.Keys { // iterates once, see sanityCheckKey
|
||||||
|
targetKeyID = targetKey
|
||||||
|
}
|
||||||
|
for sigUserID, forSigUserID := range key.Signatures {
|
||||||
|
if sigUserID != req.UserID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for sigKeyID, sigBytes := range forSigUserID {
|
||||||
|
if err := a.DB.StoreCrossSigningSigsForTarget(ctx, sigUserID, sigKeyID, req.UserID, targetKeyID, sigBytes); err != nil {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: fmt.Sprintf("a.DB.StoreCrossSigningSigsForTarget: %s", err),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req *api.PerformUploadDeviceSignaturesRequest, res *api.PerformUploadDeviceSignaturesResponse) {
|
func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req *api.PerformUploadDeviceSignaturesRequest, res *api.PerformUploadDeviceSignaturesResponse) {
|
||||||
|
// Before we do anything, we need the master and self-signing keys for this user.
|
||||||
|
// Then we can verify the signatures make sense.
|
||||||
|
queryReq := &api.QueryKeysRequest{
|
||||||
|
UserID: req.UserID,
|
||||||
|
UserToDevices: map[string][]string{},
|
||||||
|
}
|
||||||
|
queryRes := &api.QueryKeysResponse{}
|
||||||
|
for userID := range req.Signatures {
|
||||||
|
queryReq.UserToDevices[userID] = []string{}
|
||||||
|
}
|
||||||
|
a.QueryKeys(ctx, queryReq, queryRes)
|
||||||
|
|
||||||
selfSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
selfSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
||||||
otherSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
otherSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
||||||
|
|
||||||
|
// Sort signatures into two groups: one where people have signed their own
|
||||||
|
// keys and one where people have signed someone elses
|
||||||
for userID, forUserID := range req.Signatures {
|
for userID, forUserID := range req.Signatures {
|
||||||
for keyID, keyOrDevice := range forUserID {
|
for keyID, keyOrDevice := range forUserID {
|
||||||
switch key := keyOrDevice.CrossSigningBody.(type) {
|
switch key := keyOrDevice.CrossSigningBody.(type) {
|
||||||
|
|
@ -254,14 +277,14 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.processSelfSignatures(ctx, req.UserID, selfSignatures); err != nil {
|
if err := a.processSelfSignatures(ctx, req.UserID, queryRes, selfSignatures); err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: fmt.Sprintf("a.processSelfSignatures: %s", err),
|
Err: fmt.Sprintf("a.processSelfSignatures: %s", err),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.processOtherSignatures(ctx, req.UserID, otherSignatures); err != nil {
|
if err := a.processOtherSignatures(ctx, req.UserID, queryRes, otherSignatures); err != nil {
|
||||||
res.Error = &api.KeyError{
|
res.Error = &api.KeyError{
|
||||||
Err: fmt.Sprintf("a.processOtherSignatures: %s", err),
|
Err: fmt.Sprintf("a.processOtherSignatures: %s", err),
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +293,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *KeyInternalAPI) processSelfSignatures(
|
func (a *KeyInternalAPI) processSelfSignatures(
|
||||||
ctx context.Context, _ string,
|
ctx context.Context, _ string, queryRes *api.QueryKeysResponse,
|
||||||
signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice,
|
signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice,
|
||||||
) error {
|
) error {
|
||||||
// Here we will process:
|
// Here we will process:
|
||||||
|
|
@ -281,8 +304,37 @@ func (a *KeyInternalAPI) processSelfSignatures(
|
||||||
for targetKeyID, signature := range forTargetUserID {
|
for targetKeyID, signature := range forTargetUserID {
|
||||||
switch sig := signature.CrossSigningBody.(type) {
|
switch sig := signature.CrossSigningBody.(type) {
|
||||||
case *gomatrixserverlib.CrossSigningKey:
|
case *gomatrixserverlib.CrossSigningKey:
|
||||||
|
// The user is signing their master key with one of their devices
|
||||||
|
// The QueryKeys response should contain the device key hopefully.
|
||||||
|
// First we need to marshal the blob back into JSON so we can verify
|
||||||
|
// it.
|
||||||
|
j, err := json.Marshal(sig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("json.Marshal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
for originUserID, forOriginUserID := range sig.Signatures {
|
for originUserID, forOriginUserID := range sig.Signatures {
|
||||||
|
originDeviceKeys, ok := queryRes.DeviceKeys[originUserID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing device keys for user %q", originUserID)
|
||||||
|
}
|
||||||
|
|
||||||
for originKeyID, originSig := range forOriginUserID {
|
for originKeyID, originSig := range forOriginUserID {
|
||||||
|
var originKey gomatrixserverlib.DeviceKeys
|
||||||
|
if err := json.Unmarshal(originDeviceKeys[string(originKeyID)], &originKey); err != nil {
|
||||||
|
return fmt.Errorf("json.Unmarshal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
originSigningKey, ok := originKey.Keys[originKeyID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing origin signing key %q", originKeyID)
|
||||||
|
}
|
||||||
|
originSigningKeyPublic := ed25519.PublicKey(originSigningKey)
|
||||||
|
|
||||||
|
if err := gomatrixserverlib.VerifyJSON(originUserID, originKeyID, originSigningKeyPublic, j); err != nil {
|
||||||
|
return fmt.Errorf("gomatrixserverlib.VerifyJSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := a.DB.StoreCrossSigningSigsForTarget(
|
if err := a.DB.StoreCrossSigningSigsForTarget(
|
||||||
ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig,
|
ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -292,8 +344,35 @@ func (a *KeyInternalAPI) processSelfSignatures(
|
||||||
}
|
}
|
||||||
|
|
||||||
case *gomatrixserverlib.DeviceKeys:
|
case *gomatrixserverlib.DeviceKeys:
|
||||||
|
// The user is signing one of their devices with their self-signing key
|
||||||
|
// The QueryKeys response should contain the master key hopefully.
|
||||||
|
// First we need to marshal the blob back into JSON so we can verify
|
||||||
|
// it.
|
||||||
|
j, err := json.Marshal(sig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("json.Marshal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
for originUserID, forOriginUserID := range sig.Signatures {
|
for originUserID, forOriginUserID := range sig.Signatures {
|
||||||
for originKeyID, originSig := range forOriginUserID {
|
for originKeyID, originSig := range forOriginUserID {
|
||||||
|
originSelfSigningKeys, ok := queryRes.SelfSigningKeys[originUserID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("missing self-signing key for user %q", originUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var originSelfSigningKeyID gomatrixserverlib.KeyID
|
||||||
|
var originSelfSigningKey gomatrixserverlib.Base64Bytes
|
||||||
|
for keyID, key := range originSelfSigningKeys.Keys {
|
||||||
|
originSelfSigningKeyID, originSelfSigningKey = keyID, key
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
originSelfSigningKeyPublic := ed25519.PublicKey(originSelfSigningKey)
|
||||||
|
|
||||||
|
if err := gomatrixserverlib.VerifyJSON(originUserID, originSelfSigningKeyID, originSelfSigningKeyPublic, j); err != nil {
|
||||||
|
return fmt.Errorf("gomatrixserverlib.VerifyJSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := a.DB.StoreCrossSigningSigsForTarget(
|
if err := a.DB.StoreCrossSigningSigsForTarget(
|
||||||
ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig,
|
ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -312,12 +391,62 @@ func (a *KeyInternalAPI) processSelfSignatures(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *KeyInternalAPI) processOtherSignatures(
|
func (a *KeyInternalAPI) processOtherSignatures(
|
||||||
ctx context.Context, userID string,
|
ctx context.Context, userID string, queryRes *api.QueryKeysResponse,
|
||||||
signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice,
|
signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice,
|
||||||
) error {
|
) error {
|
||||||
// Here we will process:
|
// Here we will process:
|
||||||
// * A user signing someone else's master keys using their user-signing keys
|
// * A user signing someone else's master keys using their user-signing keys
|
||||||
|
|
||||||
|
for targetUserID, forTargetUserID := range signatures {
|
||||||
|
for _, signature := range forTargetUserID {
|
||||||
|
switch sig := signature.CrossSigningBody.(type) {
|
||||||
|
case *gomatrixserverlib.CrossSigningKey:
|
||||||
|
// Find the local copy of the master key. We'll use this to be
|
||||||
|
// sure that the supplied stanza matches the key that we think it
|
||||||
|
// should be.
|
||||||
|
masterKey, ok := queryRes.MasterKeys[targetUserID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("failed to find master key for user %q", targetUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each key ID, write the signatures. Maybe there'll be more
|
||||||
|
// than one algorithm in the future so it's best not to focus on
|
||||||
|
// everything being ed25519:.
|
||||||
|
for targetKeyID, suppliedKeyData := range sig.Keys {
|
||||||
|
// The master key will be supplied in the request, but we should
|
||||||
|
// make sure that it matches what we think the master key should
|
||||||
|
// actually be.
|
||||||
|
localKeyData, lok := masterKey.Keys[targetKeyID]
|
||||||
|
if !lok {
|
||||||
|
return fmt.Errorf("uploaded master key %q for user %q doesn't match local copy", targetKeyID, targetUserID)
|
||||||
|
} else if !bytes.Equal(suppliedKeyData, localKeyData) {
|
||||||
|
return fmt.Errorf("uploaded master key %q for user %q doesn't match local copy", targetKeyID, targetUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only care about the signatures from the uploading user, so
|
||||||
|
// we will ignore anything that didn't originate from them.
|
||||||
|
userSigs, ok := sig.Signatures[userID]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("there are no signatures on master key %q from uploading user %q", targetKeyID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for originKeyID, originSig := range userSigs {
|
||||||
|
if err := a.DB.StoreCrossSigningSigsForTarget(
|
||||||
|
ctx, userID, originKeyID, targetUserID, targetKeyID, originSig,
|
||||||
|
); err != nil {
|
||||||
|
return fmt.Errorf("a.DB.StoreCrossSigningKeysForTarget: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Users should only be signing another person's master key,
|
||||||
|
// so if we're here, it's probably because it's actually a
|
||||||
|
// gomatrixserverlib.DeviceKeys, which doesn't make sense.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,21 +460,15 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for keyType, keyData := range keys {
|
for keyType, key := range keys {
|
||||||
b64 := keyData.Encode()
|
var keyID gomatrixserverlib.KeyID
|
||||||
keyID := gomatrixserverlib.KeyID("ed25519:" + b64)
|
for id := range key.Keys {
|
||||||
key := gomatrixserverlib.CrossSigningKey{
|
keyID = id
|
||||||
UserID: userID,
|
break
|
||||||
Usage: []gomatrixserverlib.CrossSigningKeyPurpose{
|
|
||||||
keyType,
|
|
||||||
},
|
|
||||||
Keys: map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{
|
|
||||||
keyID: keyData,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sigs, err := a.DB.CrossSigningSigsForTarget(ctx, userID, keyID)
|
sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, userID, keyID)
|
||||||
if err != nil {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
logrus.WithError(err).Errorf("Failed to get cross-signing signatures for user %q key %q", userID, keyID)
|
logrus.WithError(err).Errorf("Failed to get cross-signing signatures for user %q key %q", userID, keyID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +483,7 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase(
|
||||||
key.Signatures[originUserID][originKeyID] = signature
|
key.Signatures[originUserID][originKeyID] = signature
|
||||||
}
|
}
|
||||||
|
|
||||||
for originUserID, forOrigin := range sigs {
|
for originUserID, forOrigin := range sigMap {
|
||||||
for originKeyID, signature := range forOrigin {
|
for originKeyID, signature := range forOrigin {
|
||||||
switch {
|
switch {
|
||||||
case req.UserID != "" && originUserID == req.UserID:
|
case req.UserID != "" && originUserID == req.UserID:
|
||||||
|
|
@ -387,3 +510,65 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySignaturesRequest, res *api.QuerySignaturesResponse) {
|
||||||
|
for targetUserID, forTargetUser := range req.TargetIDs {
|
||||||
|
keyMap, err := a.DB.CrossSigningKeysForUser(ctx, targetUserID)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: fmt.Sprintf("a.DB.CrossSigningKeysForUser: %s", err),
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for targetPurpose, targetKey := range keyMap {
|
||||||
|
switch targetPurpose {
|
||||||
|
case gomatrixserverlib.CrossSigningKeyPurposeMaster:
|
||||||
|
if res.MasterKeys == nil {
|
||||||
|
res.MasterKeys = map[string]gomatrixserverlib.CrossSigningKey{}
|
||||||
|
}
|
||||||
|
res.MasterKeys[targetUserID] = targetKey
|
||||||
|
|
||||||
|
case gomatrixserverlib.CrossSigningKeyPurposeSelfSigning:
|
||||||
|
if res.SelfSigningKeys == nil {
|
||||||
|
res.SelfSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{}
|
||||||
|
}
|
||||||
|
res.SelfSigningKeys[targetUserID] = targetKey
|
||||||
|
|
||||||
|
case gomatrixserverlib.CrossSigningKeyPurposeUserSigning:
|
||||||
|
if res.UserSigningKeys == nil {
|
||||||
|
res.UserSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{}
|
||||||
|
}
|
||||||
|
res.UserSigningKeys[targetUserID] = targetKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, targetKeyID := range forTargetUser {
|
||||||
|
sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, targetUserID, targetKeyID)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
res.Error = &api.KeyError{
|
||||||
|
Err: fmt.Sprintf("a.DB.CrossSigningSigsForTarget: %s", err),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for sourceUserID, forSourceUser := range sigMap {
|
||||||
|
for sourceKeyID, sourceSig := range forSourceUser {
|
||||||
|
if res.Signatures == nil {
|
||||||
|
res.Signatures = map[string]map[gomatrixserverlib.KeyID]types.CrossSigningSigMap{}
|
||||||
|
}
|
||||||
|
if _, ok := res.Signatures[targetUserID]; !ok {
|
||||||
|
res.Signatures[targetUserID] = map[gomatrixserverlib.KeyID]types.CrossSigningSigMap{}
|
||||||
|
}
|
||||||
|
if _, ok := res.Signatures[targetUserID][targetKeyID]; !ok {
|
||||||
|
res.Signatures[targetUserID][targetKeyID] = types.CrossSigningSigMap{}
|
||||||
|
}
|
||||||
|
if _, ok := res.Signatures[targetUserID][targetKeyID][sourceUserID]; !ok {
|
||||||
|
res.Signatures[targetUserID][targetKeyID][sourceUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{}
|
||||||
|
}
|
||||||
|
res.Signatures[targetUserID][targetKeyID][sourceUserID][sourceKeyID] = sourceSig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -300,14 +300,40 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques
|
||||||
|
|
||||||
// attempt to satisfy key queries from the local database first as we should get device updates pushed to us
|
// attempt to satisfy key queries from the local database first as we should get device updates pushed to us
|
||||||
domainToDeviceKeys = a.remoteKeysFromDatabase(ctx, res, domainToDeviceKeys)
|
domainToDeviceKeys = a.remoteKeysFromDatabase(ctx, res, domainToDeviceKeys)
|
||||||
if len(domainToDeviceKeys) == 0 && len(domainToCrossSigningKeys) == 0 {
|
if len(domainToDeviceKeys) > 0 || len(domainToCrossSigningKeys) > 0 {
|
||||||
return // nothing to query
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform key queries for remote devices
|
// perform key queries for remote devices
|
||||||
a.queryRemoteKeys(ctx, req.Timeout, res, domainToDeviceKeys, domainToCrossSigningKeys)
|
a.queryRemoteKeys(ctx, req.Timeout, res, domainToDeviceKeys, domainToCrossSigningKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally, append signatures that we know about
|
||||||
|
// TODO: This is horrible because we need to round-trip the signature from
|
||||||
|
// JSON, add the signatures and marshal it again, for some reason?
|
||||||
|
for userID, forUserID := range res.DeviceKeys {
|
||||||
|
for keyID, key := range forUserID {
|
||||||
|
sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, userID, gomatrixserverlib.KeyID(keyID))
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Errorf("a.DB.CrossSigningSigsForTarget failed")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(sigMap) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var deviceKey gomatrixserverlib.DeviceKeys
|
||||||
|
if err = json.Unmarshal(key, &deviceKey); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for sourceUserID, forSourceUser := range sigMap {
|
||||||
|
for sourceKeyID, sourceSig := range forSourceUser {
|
||||||
|
deviceKey.Signatures[sourceUserID][sourceKeyID] = sourceSig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if js, err := json.Marshal(deviceKey); err == nil {
|
||||||
|
res.DeviceKeys[userID][keyID] = js
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *KeyInternalAPI) remoteKeysFromDatabase(
|
func (a *KeyInternalAPI) remoteKeysFromDatabase(
|
||||||
ctx context.Context, res *api.QueryKeysResponse, domainToDeviceKeys map[string]map[string][]string,
|
ctx context.Context, res *api.QueryKeysResponse, domainToDeviceKeys map[string]map[string][]string,
|
||||||
) map[string]map[string][]string {
|
) map[string]map[string][]string {
|
||||||
|
|
@ -346,9 +372,15 @@ func (a *KeyInternalAPI) queryRemoteKeys(
|
||||||
|
|
||||||
domains := map[string]struct{}{}
|
domains := map[string]struct{}{}
|
||||||
for domain := range domainToDeviceKeys {
|
for domain := range domainToDeviceKeys {
|
||||||
|
if domain == string(a.ThisServer) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
domains[domain] = struct{}{}
|
domains[domain] = struct{}{}
|
||||||
}
|
}
|
||||||
for domain := range domainToCrossSigningKeys {
|
for domain := range domainToCrossSigningKeys {
|
||||||
|
if domain == string(a.ThisServer) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
domains[domain] = struct{}{}
|
domains[domain] = struct{}{}
|
||||||
}
|
}
|
||||||
wg.Add(len(domains))
|
wg.Add(len(domains))
|
||||||
|
|
@ -380,17 +412,11 @@ func (a *KeyInternalAPI) queryRemoteKeys(
|
||||||
}
|
}
|
||||||
|
|
||||||
for userID, body := range result.MasterKeys {
|
for userID, body := range result.MasterKeys {
|
||||||
switch b := body.CrossSigningBody.(type) {
|
res.MasterKeys[userID] = body
|
||||||
case *gomatrixserverlib.CrossSigningKey:
|
|
||||||
res.MasterKeys[userID] = *b
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for userID, body := range result.SelfSigningKeys {
|
for userID, body := range result.SelfSigningKeys {
|
||||||
switch b := body.CrossSigningBody.(type) {
|
res.SelfSigningKeys[userID] = body
|
||||||
case *gomatrixserverlib.CrossSigningKey:
|
|
||||||
res.SelfSigningKeys[userID] = *b
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do we want to persist these somewhere now
|
// TODO: do we want to persist these somewhere now
|
||||||
|
|
@ -404,8 +430,12 @@ func (a *KeyInternalAPI) queryRemoteKeysOnServer(
|
||||||
res *api.QueryKeysResponse,
|
res *api.QueryKeysResponse,
|
||||||
) {
|
) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
fedCtx, cancel := context.WithTimeout(ctx, timeout)
|
fedCtx := ctx
|
||||||
|
if timeout > 0 {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
fedCtx, cancel = context.WithTimeout(ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
}
|
||||||
// for users who we do not have any knowledge about, try to start doing device list updates for them
|
// for users who we do not have any knowledge about, try to start doing device list updates for them
|
||||||
// by hitting /users/devices - otherwise fallback to /keys/query which has nicer bulk properties but
|
// by hitting /users/devices - otherwise fallback to /keys/query which has nicer bulk properties but
|
||||||
// lack a stream ID.
|
// lack a stream ID.
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ const (
|
||||||
QueryKeyChangesPath = "/keyserver/queryKeyChanges"
|
QueryKeyChangesPath = "/keyserver/queryKeyChanges"
|
||||||
QueryOneTimeKeysPath = "/keyserver/queryOneTimeKeys"
|
QueryOneTimeKeysPath = "/keyserver/queryOneTimeKeys"
|
||||||
QueryDeviceMessagesPath = "/keyserver/queryDeviceMessages"
|
QueryDeviceMessagesPath = "/keyserver/queryDeviceMessages"
|
||||||
|
QuerySignaturesPath = "/keyserver/querySignatures"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewKeyServerClient creates a KeyInternalAPI implemented by talking to a HTTP POST API.
|
// NewKeyServerClient creates a KeyInternalAPI implemented by talking to a HTTP POST API.
|
||||||
|
|
@ -211,3 +212,20 @@ func (h *httpKeyInternalAPI) PerformUploadDeviceSignatures(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *httpKeyInternalAPI) QuerySignatures(
|
||||||
|
ctx context.Context,
|
||||||
|
request *api.QuerySignaturesRequest,
|
||||||
|
response *api.QuerySignaturesResponse,
|
||||||
|
) {
|
||||||
|
span, ctx := opentracing.StartSpanFromContext(ctx, "QuerySignatures")
|
||||||
|
defer span.Finish()
|
||||||
|
|
||||||
|
apiURL := h.apiURL + QuerySignaturesPath
|
||||||
|
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
|
if err != nil {
|
||||||
|
response.Error = &api.KeyError{
|
||||||
|
Err: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) {
|
||||||
httputil.MakeInternalAPI("performUploadDeviceKeys", func(req *http.Request) util.JSONResponse {
|
httputil.MakeInternalAPI("performUploadDeviceKeys", func(req *http.Request) util.JSONResponse {
|
||||||
request := api.PerformUploadDeviceKeysRequest{}
|
request := api.PerformUploadDeviceKeysRequest{}
|
||||||
response := api.PerformUploadDeviceKeysResponse{}
|
response := api.PerformUploadDeviceKeysResponse{}
|
||||||
if err := json.NewDecoder(req.Body).Decode(&request.CrossSigningKeys); err != nil {
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
s.PerformUploadDeviceKeys(req.Context(), &request, &response)
|
s.PerformUploadDeviceKeys(req.Context(), &request, &response)
|
||||||
|
|
@ -73,7 +73,7 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) {
|
||||||
httputil.MakeInternalAPI("performUploadDeviceSignatures", func(req *http.Request) util.JSONResponse {
|
httputil.MakeInternalAPI("performUploadDeviceSignatures", func(req *http.Request) util.JSONResponse {
|
||||||
request := api.PerformUploadDeviceSignaturesRequest{}
|
request := api.PerformUploadDeviceSignaturesRequest{}
|
||||||
response := api.PerformUploadDeviceSignaturesResponse{}
|
response := api.PerformUploadDeviceSignaturesResponse{}
|
||||||
if err := json.NewDecoder(req.Body).Decode(&request.Signatures); err != nil {
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
s.PerformUploadDeviceSignatures(req.Context(), &request, &response)
|
s.PerformUploadDeviceSignatures(req.Context(), &request, &response)
|
||||||
|
|
@ -124,4 +124,15 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) {
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
internalAPIMux.Handle(QuerySignaturesPath,
|
||||||
|
httputil.MakeInternalAPI("querySignatures", func(req *http.Request) util.JSONResponse {
|
||||||
|
request := api.QuerySignaturesRequest{}
|
||||||
|
response := api.QuerySignaturesResponse{}
|
||||||
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
s.QuerySignatures(req.Context(), &request, &response)
|
||||||
|
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ type Database interface {
|
||||||
// MarkDeviceListStale sets the stale bit for this user to isStale.
|
// MarkDeviceListStale sets the stale bit for this user to isStale.
|
||||||
MarkDeviceListStale(ctx context.Context, userID string, isStale bool) error
|
MarkDeviceListStale(ctx context.Context, userID string, isStale bool) error
|
||||||
|
|
||||||
CrossSigningKeysForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error)
|
CrossSigningKeysForUser(ctx context.Context, userID string) (map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey, error)
|
||||||
|
CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error)
|
||||||
CrossSigningSigsForTarget(ctx context.Context, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error)
|
CrossSigningSigsForTarget(ctx context.Context, 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) error
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,46 @@ func (d *Database) MarkDeviceListStale(ctx context.Context, userID string, isSta
|
||||||
}
|
}
|
||||||
|
|
||||||
// CrossSigningKeysForUser returns the latest known cross-signing keys for a user, if any.
|
// CrossSigningKeysForUser returns the latest known cross-signing keys for a user, if any.
|
||||||
func (d *Database) CrossSigningKeysForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) {
|
func (d *Database) CrossSigningKeysForUser(ctx context.Context, userID string) (map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey, error) {
|
||||||
|
keyMap, err := d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("d.CrossSigningKeysTable.SelectCrossSigningKeysForUser: %w", err)
|
||||||
|
}
|
||||||
|
results := map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey{}
|
||||||
|
for purpose, key := range keyMap {
|
||||||
|
keyID := gomatrixserverlib.KeyID("ed25519:" + key.Encode())
|
||||||
|
result := gomatrixserverlib.CrossSigningKey{
|
||||||
|
UserID: userID,
|
||||||
|
Usage: []gomatrixserverlib.CrossSigningKeyPurpose{purpose},
|
||||||
|
Keys: map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{
|
||||||
|
keyID: key,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sigMap, err := d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, userID, keyID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for sigUserID, forSigUserID := range sigMap {
|
||||||
|
if userID != sigUserID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result.Signatures == nil {
|
||||||
|
result.Signatures = map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{}
|
||||||
|
}
|
||||||
|
if _, ok := result.Signatures[sigUserID]; !ok {
|
||||||
|
result.Signatures[sigUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{}
|
||||||
|
}
|
||||||
|
for sigKeyID, sigBytes := range forSigUserID {
|
||||||
|
result.Signatures[sigUserID][sigKeyID] = sigBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results[purpose] = result
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrossSigningKeysForUser returns the latest known cross-signing keys for a user, if any.
|
||||||
|
func (d *Database) CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) {
|
||||||
return d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID)
|
return d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ func (k *mockKeyAPI) QueryDeviceMessages(ctx context.Context, req *keyapi.QueryD
|
||||||
}
|
}
|
||||||
func (k *mockKeyAPI) InputDeviceListUpdate(ctx context.Context, req *keyapi.InputDeviceListUpdateRequest, res *keyapi.InputDeviceListUpdateResponse) {
|
func (k *mockKeyAPI) InputDeviceListUpdate(ctx context.Context, req *keyapi.InputDeviceListUpdateRequest, res *keyapi.InputDeviceListUpdateResponse) {
|
||||||
|
|
||||||
|
}
|
||||||
|
func (k *mockKeyAPI) QuerySignatures(ctx context.Context, req *keyapi.QuerySignaturesRequest, res *keyapi.QuerySignaturesResponse) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockRoomserverAPI struct {
|
type mockRoomserverAPI struct {
|
||||||
|
|
|
||||||
|
|
@ -556,3 +556,4 @@ Presence change reports an event to myself
|
||||||
Can upload self-signing keys
|
Can upload self-signing keys
|
||||||
Fails to upload self-signing keys with no auth
|
Fails to upload self-signing keys with no auth
|
||||||
Fails to upload self-signing key without master key
|
Fails to upload self-signing key without master key
|
||||||
|
can fetch self-signing keys over federation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue