diff --git a/encryptoapi/routing/keys.go b/encryptoapi/routing/keys.go index d912172d8..69988dca1 100644 --- a/encryptoapi/routing/keys.go +++ b/encryptoapi/routing/keys.go @@ -28,7 +28,6 @@ import ( "github.com/matrix-org/dendrite/common/basecomponent" "github.com/matrix-org/dendrite/encryptoapi/storage" "github.com/matrix-org/dendrite/encryptoapi/types" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" "github.com/pkg/errors" ) @@ -79,6 +78,7 @@ func UploadPKeys( &keySpecific, userID, deviceID) // numMap is algorithm-num map + // this gets the number of unclaimed OTkeys numMap, ok := (queryOneTimeKeys( req.Context(), TYPESUM, @@ -116,13 +116,12 @@ func QueryPKeys( ) util.JSONResponse { var err error var queryRq types.QueryRequest - queryRp := types.QueryResponse{} - queryRp.Failure = make(map[string]interface{}) - queryRp.DeviceKeys = make(map[string]map[string]types.DeviceKeysQuery) if reqErr := httputil.UnmarshalJSONRequest(req, &queryRq); reqErr != nil { return *reqErr } + sendDKToFed := queryRq.DeviceKeys + queryRp.Failure = make(map[string]interface{}) // FED must return the keys from the other user /* federation consideration: when user id is in federation, a @@ -156,44 +155,12 @@ func QueryPKeys( } } - // query one's device key from user corresponding to uid - for uid, arr := range queryRq.DeviceKeys { - queryRp.DeviceKeys[uid] = make(map[string]types.DeviceKeysQuery) - deviceKeysQueryMap := queryRp.DeviceKeys[uid] - // backward compatible to old interface - midArr := []string{} - // figure out device list from devices described as device which is actually deviceID - for device := range arr.(map[string]interface{}) { - midArr = append(midArr, device) - } - // all device keys - dkeys, _ := encryptionDB.QueryInRange(req.Context(), uid, midArr) - // build response for them + // + // + // + // + // Forward the request to the federation server and get the required info - for _, key := range dkeys { - - deviceKeysQueryMap = presetDeviceKeysQueryMap(deviceKeysQueryMap, uid, key) - // load for accomplishment - single := deviceKeysQueryMap[key.DeviceID] - resKey := fmt.Sprintf("%s:%s", key.KeyAlgorithm, key.DeviceID) - resBody := key.Key - single.Keys[resKey] = resBody - single.DeviceID = key.DeviceID - single.UserID = key.UserID - single.Signature[uid][fmt.Sprintf("%s:%s", "ed25519", key.DeviceID)] = key.Signature - single.Algorithm, err = takeAL(req.Context(), *encryptionDB, key.UserID, key.DeviceID) - localpart, _, _ := gomatrixserverlib.SplitID('@', uid) - device, _ := deviceDB.GetDeviceByID(req.Context(), localpart, deviceID) - single.Unsigned.Info = device.DisplayName - deviceKeysQueryMap[key.DeviceID] = single - } - } - if err != nil { - return util.JSONResponse{ - Code: http.StatusInternalServerError, - JSON: queryRp, - } - } return util.JSONResponse{ Code: http.StatusOK, JSON: queryRp, @@ -426,15 +393,6 @@ func persistAl( return } -func takeAL( - ctx context.Context, - encryptDB storage.Database, - uid, device string, -) (al []string, err error) { - al, err = encryptDB.SelectAl(ctx, uid, device) - return -} - func pickOne( ctx context.Context, encryptDB storage.Database, @@ -460,35 +418,6 @@ func InitNotifier(base *basecomponent.BaseDendrite) { keyProducer.ch = pro } -func presetDeviceKeysQueryMap( - deviceKeysQueryMap map[string]types.DeviceKeysQuery, - uid string, - key types.KeyHolder, -) map[string]types.DeviceKeysQuery { - // preset for complicated nested map struct - if _, ok := deviceKeysQueryMap[key.DeviceID]; !ok { - // make consistency - deviceKeysQueryMap[key.DeviceID] = types.DeviceKeysQuery{} - } - if deviceKeysQueryMap[key.DeviceID].Signature == nil { - mid := make(map[string]map[string]string) - midmap := deviceKeysQueryMap[key.DeviceID] - midmap.Signature = mid - deviceKeysQueryMap[key.DeviceID] = midmap - } - if deviceKeysQueryMap[key.DeviceID].Keys == nil { - mid := make(map[string]string) - midmap := deviceKeysQueryMap[key.DeviceID] - midmap.Keys = mid - deviceKeysQueryMap[key.DeviceID] = midmap - } - if _, ok := deviceKeysQueryMap[key.DeviceID].Signature[uid]; !ok { - // make consistency - deviceKeysQueryMap[key.DeviceID].Signature[uid] = make(map[string]string) - } - return deviceKeysQueryMap -} - func persistBothKeys( ctx context.Context, body *types.UploadEncryptSpecific, diff --git a/encryptoapi/storage/storage.go b/encryptoapi/storage/storage.go index eeb90965e..f4e66819e 100644 --- a/encryptoapi/storage/storage.go +++ b/encryptoapi/storage/storage.go @@ -59,7 +59,7 @@ func (d *Database) InsertKey( return } -// SelectOneTimeKeyCount for key upload response usage a map from key algorithm to sum to counterpart +// SelectOneTimeKeyCount provides the number of un-claimed OTKeys func (d *Database) SelectOneTimeKeyCount( ctx context.Context, deviceID, userID string, diff --git a/federationapi/routing/e2ee.go b/federationapi/routing/e2ee.go new file mode 100644 index 000000000..b48ab01ee --- /dev/null +++ b/federationapi/routing/e2ee.go @@ -0,0 +1,137 @@ +// Copyright Sumukha PK 2019 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package routing + +import ( + "context" + "fmt" + "net/http" + + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/encryptoapi/storage" + "github.com/matrix-org/dendrite/federationapi/types" + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/util" +) + +// ClaimKeys provides the e2ee keys of the user +func ClaimKeys( + httpReq *http.Request, + request *gomatrixserverlib.FederationRequest, + encryptionDB *storage.Database, +) util.JSONResponse { + + return util.JSONResponse{ + Code: http.StatusOK, + JSON: struct{}{}, + } +} + +// QueryKeys provides the public identity keys and supported algorithms. +func QueryKeys( + httpReq *http.Request, + request *gomatrixserverlib.FederationRequest, + encryptionDB *storage.Database, +) util.JSONResponse { + var err error + var queryRq types.QueryRequest + if reqErr := httputil.UnmarshalJSONRequest(httpReq, &queryRq); reqErr != nil { + return *reqErr + } + queryRp := types.QueryResponse{} + + queryRp.DeviceKeys = make(map[string]map[string]types.DeviceKeys) + // query one's device key from user corresponding to uid + for uid, arr := range queryRq.DeviceKeys { + queryRp.DeviceKeys[uid] = make(map[string]types.DeviceKeys) + deviceKeysQueryMap := queryRp.DeviceKeys[uid] + // backward compatible to old interface + midArr := []string{} + // figure out device list from devices described as device which is actually deviceID + for device := range arr.(map[string]interface{}) { + midArr = append(midArr, device) + } + // all device keys + dkeys, _ := encryptionDB.QueryInRange(httpReq.Context(), uid, midArr) + // build response for them + + for _, key := range dkeys { + + deviceKeysQueryMap = presetDeviceKeysQueryMap(deviceKeysQueryMap, uid, key) + // load for accomplishment + single := deviceKeysQueryMap[key.DeviceID] + resKey := fmt.Sprintf("%s:%s", key.KeyAlgorithm, key.DeviceID) + resBody := key.Key + single.Keys[resKey] = resBody + single.DeviceID = key.DeviceID + single.UserID = key.UserID + single.Signature[uid][fmt.Sprintf("%s:%s", "ed25519", key.DeviceID)] = key.Signature + single.Algorithm, err = takeAL(httpReq.Context(), *encryptionDB, key.UserID, key.DeviceID) + localpart, _, _ := gomatrixserverlib.SplitID('@', uid) + device, _ := deviceDB.GetDeviceByID(req.Context(), localpart, deviceID) + single.Unsigned.Info = device.DisplayName + deviceKeysQueryMap[key.DeviceID] = single + } + } + if err != nil { + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: struct{}{}, + } + } + + return util.JSONResponse{ + Code: http.StatusOK, + JSON: struct{}{}, + } +} + +func presetDeviceKeysQueryMap( + deviceKeysQueryMap map[string]types.DeviceKeys, + uid string, + key types.KeyHolder, +) map[string]types.DeviceKeys { + // preset for complicated nested map struct + if _, ok := deviceKeysQueryMap[key.DeviceID]; !ok { + // make consistency + deviceKeysQueryMap[key.DeviceID] = types.DeviceKeysQuery{} + } + if deviceKeysQueryMap[key.DeviceID].Signature == nil { + mid := make(map[string]map[string]string) + midmap := deviceKeysQueryMap[key.DeviceID] + midmap.Signature = mid + deviceKeysQueryMap[key.DeviceID] = midmap + } + if deviceKeysQueryMap[key.DeviceID].Keys == nil { + mid := make(map[string]string) + midmap := deviceKeysQueryMap[key.DeviceID] + midmap.Keys = mid + deviceKeysQueryMap[key.DeviceID] = midmap + } + if _, ok := deviceKeysQueryMap[key.DeviceID].Signature[uid]; !ok { + // make consistency + deviceKeysQueryMap[key.DeviceID].Signature[uid] = make(map[string]string) + } + return deviceKeysQueryMap +} + +func takeAL( + ctx context.Context, + encryptDB storage.Database, + uid, device string, +) (al []string, err error) { + al, err = encryptDB.SelectAl(ctx, uid, device) + return +} diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 9f576790b..feefced79 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -271,4 +271,27 @@ func Setup( return Backfill(httpReq, request, query, vars["roomID"], cfg) }, )).Methods(http.MethodGet) + + v1fedmux.Handle("/keys/claim", common.MakeFedAPI( + "federation_claim_e2ee_keys", cfg.Matrix.ServerName, keys, + func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { + // vars, err := common.URLDecodeMapValues(mux.Vars(httpReq)) + // if err != nil { + // return util.ErrorResponse(err) + // } + return ClaimKeys(httpReq, request) + }, + )).Methods(http.MethodPost) + + v1fedmux.Handle("/keys/query", common.MakeFedAPI( + "federation_query_e2ee_keys", cfg.Matrix.ServerName, keys, + func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { + // vars, err := common.URLDecodeMapValues(mux.Vars(httpReq)) + // if err != nil { + // return util.ErrorResponse(err) + // } + return QueryKeys(httpReq, request) + }, + )).Methods(http.MethodPost) + } diff --git a/federationapi/types/types.go b/federationapi/types/types.go index 24838d547..0b2009dda 100644 --- a/federationapi/types/types.go +++ b/federationapi/types/types.go @@ -41,3 +41,39 @@ func NewTransaction() Transaction { return Transaction{OriginServerTS: ts} } + +// QueryRequest is the request for /query +type QueryRequest struct { + DeviceKeys map[string][]string `json:"device_keys"` +} + +// UnsignedDeviceInfo is the struct for UDI +type UnsignedDeviceInfo struct { + DeviceDisplayName string `json:"device_display_name"` +} + +// DeviceKeys has the data of the keys of the device +type DeviceKeys struct { + UserID string `json:"user_id"` + DeviceID string `json:"edvice_id"` + Algorithms []string `json:"algorithms"` + Keys map[string]string `json:"keys"` + Signatures map[string]map[string]string `json:"signatures"` + Unsigned UnsignedDeviceInfo `json:"unsigned"` +} + +// QueryResponse is the response for /query +type QueryResponse struct { + DeviceKeys map[string]DeviceKeys `json:"device_keys"` +} + +// KeyHolder structure +type KeyHolder struct { + UserID, + DeviceID, + Signature, + KeyAlgorithm, + KeyID, + Key, + KeyType string +}