@@ -18,7 +18,8 @@ import debugFunc, { type Debugger } from "debug";
18
18
import fetchMock from "fetch-mock-jest" ;
19
19
20
20
import type { IDeviceKeys , IOneTimeKey } from "../../src/@types/crypto" ;
21
- import type { CrossSigningKeys } from "../../src" ;
21
+ import type { CrossSigningKeys , ISignedKey , KeySignatures } from "../../src" ;
22
+ import type { CrossSigningKeyInfo } from "../../src/crypto-api" ;
22
23
23
24
/** Interface implemented by classes that intercept `/keys/upload` requests from test clients to catch the uploaded keys
24
25
*
@@ -62,10 +63,15 @@ export class E2EKeyReceiver implements IE2EKeyReceiver {
62
63
/**
63
64
* Construct a new E2EKeyReceiver.
64
65
*
65
- * It will immediately register an intercept of `/keys/uploads` and `/keys/device_signing/upload` requests for the given homeserverUrl.
66
+ * It will immediately register an intercept of [`/keys/upload`][1], [`/keys/signatures/upload`][2] and
67
+ * [`/keys/device_signing/upload`][3] requests for the given homeserverUrl.
66
68
* Only requests made to this server will be intercepted: this allows a single test to use more than one
67
69
* client and have the keys collected separately.
68
70
*
71
+ * [1]: https://spec.matrix.org/v1.14/client-server-api/#post_matrixclientv3keysupload
72
+ * [2]: https://spec.matrix.org/v1.14/client-server-api/#post_matrixclientv3keyssignaturesupload
73
+ * [3]: https://spec.matrix.org/v1.14/client-server-api/#post_matrixclientv3keysdevice_signingupload
74
+ *
69
75
* @param homeserverUrl - the Homeserver Url of the client under test.
70
76
*/
71
77
public constructor ( homeserverUrl : string ) {
@@ -79,6 +85,14 @@ export class E2EKeyReceiver implements IE2EKeyReceiver {
79
85
fetchMock . post ( new URL ( "/_matrix/client/v3/keys/upload" , homeserverUrl ) . toString ( ) , listener ) ;
80
86
} ) ;
81
87
88
+ fetchMock . post (
89
+ {
90
+ url : new URL ( "/_matrix/client/v3/keys/signatures/upload" , homeserverUrl ) . toString ( ) ,
91
+ name : "upload-sigs" ,
92
+ } ,
93
+ ( url , options ) => this . onSignaturesUploadRequest ( options ) ,
94
+ ) ;
95
+
82
96
fetchMock . post (
83
97
{
84
98
url : new URL ( "/_matrix/client/v3/keys/device_signing/upload" , homeserverUrl ) . toString ( ) ,
@@ -96,8 +110,10 @@ export class E2EKeyReceiver implements IE2EKeyReceiver {
96
110
if ( this . deviceKeys ) {
97
111
throw new Error ( "Application attempted to upload E2E device keys multiple times" ) ;
98
112
}
99
- this . debug ( `received device keys` ) ;
100
113
this . deviceKeys = content . device_keys ;
114
+ this . debug (
115
+ `received device keys for user ID ${ this . deviceKeys ! . user_id } , device ID ${ this . deviceKeys ! . device_id } ` ,
116
+ ) ;
101
117
}
102
118
103
119
if ( content . one_time_keys && Object . keys ( content . one_time_keys ) . length > 0 ) {
@@ -122,6 +138,35 @@ export class E2EKeyReceiver implements IE2EKeyReceiver {
122
138
} ;
123
139
}
124
140
141
+ private async onSignaturesUploadRequest ( request : RequestInit ) : Promise < object > {
142
+ const content = JSON . parse ( request . body as string ) as KeySignatures ;
143
+ for ( const [ userId , userKeys ] of Object . entries ( content ) ) {
144
+ for ( const [ deviceId , signedKey ] of Object . entries ( userKeys ) ) {
145
+ this . onDeviceSignatureUpload ( userId , deviceId , signedKey ) ;
146
+ }
147
+ }
148
+
149
+ return { } ;
150
+ }
151
+
152
+ private onDeviceSignatureUpload ( userId : string , deviceId : string , signedKey : CrossSigningKeyInfo | ISignedKey ) {
153
+ if ( ! this . deviceKeys || userId != this . deviceKeys . user_id || deviceId != this . deviceKeys . device_id ) {
154
+ this . debug (
155
+ `Ignoring device key signature upload for unknown device user ID ${ userId } , device ID ${ deviceId } ` ,
156
+ ) ;
157
+ return ;
158
+ }
159
+
160
+ this . debug ( `received device key signature for user ID ${ userId } , device ID ${ deviceId } ` ) ;
161
+ this . deviceKeys . signatures ??= { } ;
162
+ for ( const [ signingUser , signatures ] of Object . entries ( signedKey . signatures ! ) ) {
163
+ this . deviceKeys . signatures [ signingUser ] = Object . assign (
164
+ this . deviceKeys . signatures [ signingUser ] ?? { } ,
165
+ signatures ,
166
+ ) ;
167
+ }
168
+ }
169
+
125
170
private async onSigningKeyUploadRequest ( request : RequestInit ) : Promise < object > {
126
171
const content = JSON . parse ( request . body as string ) ;
127
172
if ( this . crossSigningKeys ) {
0 commit comments