@@ -51,7 +51,9 @@ import { escapeRegExp } from "../../../src/utils";
51
51
import { downloadDeviceToJsDevice } from "../../../src/rust-crypto/device-converter" ;
52
52
import { flushPromises } from "../../test-utils/flushPromises" ;
53
53
import { mockInitialApiRequests } from "../../test-utils/mockEndpoints" ;
54
- import { SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/secret-storage" ;
54
+ import { AddSecretStorageKeyOpts , SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/secret-storage" ;
55
+ import { mockSetupCrossSigningRequests } from "../../test-utils/cross-signing" ;
56
+ import { CryptoCallbacks } from "../../../src/crypto-api" ;
55
57
56
58
const ROOM_ID = "!room:id" ;
57
59
@@ -530,6 +532,27 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
530
532
} ;
531
533
}
532
534
535
+ /**
536
+ * Create the {@link CryptoCallbacks}
537
+ */
538
+ function createCryptoCallbacks ( ) : CryptoCallbacks {
539
+ // Store the cached secret storage key and return it when `getSecretStorageKey` is called
540
+ let cachedKey : { keyId : string ; key : Uint8Array } ;
541
+ const cacheSecretStorageKey = ( keyId : string , keyInfo : AddSecretStorageKeyOpts , key : Uint8Array ) => {
542
+ cachedKey = {
543
+ keyId,
544
+ key,
545
+ } ;
546
+ } ;
547
+
548
+ const getSecretStorageKey = ( ) => Promise . resolve < [ string , Uint8Array ] > ( [ cachedKey . keyId , cachedKey . key ] ) ;
549
+
550
+ return {
551
+ cacheSecretStorageKey,
552
+ getSecretStorageKey,
553
+ } ;
554
+ }
555
+
533
556
beforeEach ( async ( ) => {
534
557
// anything that we don't have a specific matcher for silently returns a 404
535
558
fetchMock . catch ( 404 ) ;
@@ -541,6 +564,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
541
564
userId : "@alice:localhost" ,
542
565
accessToken : "akjgkrgjs" ,
543
566
deviceId : "xzcvb" ,
567
+ cryptoCallbacks : createCryptoCallbacks ( ) ,
544
568
} ) ;
545
569
546
570
/* set up listeners for /keys/upload and /sync */
@@ -2183,16 +2207,16 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2183
2207
} ) ;
2184
2208
2185
2209
/**
2186
- * Create a mock to respond to the PUT request `/_matrix/client/r0/user/:userId/account_data/:type`
2210
+ * Create a mock to respond to the PUT request `/_matrix/client/r0/user/:userId/account_data/:type(m.secret_storage.*) `
2187
2211
* Resolved when a key is uploaded (ie in `body.content.key`)
2188
2212
* https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3useruseridaccount_datatype
2189
2213
*/
2190
- function awaitKeyStoredInAccountData ( ) : Promise < string > {
2214
+ function awaitSecretStorageKeyStoredInAccountData ( ) : Promise < string > {
2191
2215
return new Promise ( ( resolve ) => {
2192
2216
// This url is called multiple times during the secret storage bootstrap process
2193
2217
// When we received the newly generated key, we return it
2194
2218
fetchMock . put (
2195
- "express:/_matrix/client/r0/user/:userId/account_data/:type" ,
2219
+ "express:/_matrix/client/r0/user/:userId/account_data/:type(m.secret_storage.*) " ,
2196
2220
( url : string , options : RequestInit ) => {
2197
2221
const content = JSON . parse ( options . body as string ) ;
2198
2222
@@ -2202,7 +2226,25 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2202
2226
2203
2227
return { } ;
2204
2228
} ,
2205
- { overwriteRoutes : true } ,
2229
+ ) ;
2230
+ } ) ;
2231
+ }
2232
+
2233
+ /**
2234
+ * Create a mock to respond to the PUT request `/_matrix/client/r0/user/:userId/account_data/m.cross_signing.master`
2235
+ * Resolved when the cross signing master key is uploaded
2236
+ * https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3useruseridaccount_datatype
2237
+ */
2238
+ function awaitCrossSigningMasterKeyUpload ( ) : Promise < Record < string , { } > > {
2239
+ return new Promise ( ( resolve ) => {
2240
+ // Called when the cross signing key master key is uploaded
2241
+ fetchMock . put (
2242
+ "express:/_matrix/client/r0/user/:userId/account_data/m.cross_signing.master" ,
2243
+ ( url : string , options : RequestInit ) => {
2244
+ const content = JSON . parse ( options . body as string ) ;
2245
+ resolve ( content . encrypted ) ;
2246
+ return { } ;
2247
+ } ,
2206
2248
) ;
2207
2249
} ) ;
2208
2250
}
@@ -2258,7 +2300,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2258
2300
. bootstrapSecretStorage ( { setupNewSecretStorage : true , createSecretStorageKey } ) ;
2259
2301
2260
2302
// Wait for the key to be uploaded in the account data
2261
- const secretStorageKey = await awaitKeyStoredInAccountData ( ) ;
2303
+ const secretStorageKey = await awaitSecretStorageKeyStoredInAccountData ( ) ;
2262
2304
2263
2305
// Return the newly created key in the sync response
2264
2306
sendSyncResponse ( secretStorageKey ) ;
@@ -2279,7 +2321,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2279
2321
const bootstrapPromise = aliceClient . getCrypto ( ) ! . bootstrapSecretStorage ( { createSecretStorageKey } ) ;
2280
2322
2281
2323
// Wait for the key to be uploaded in the account data
2282
- const secretStorageKey = await awaitKeyStoredInAccountData ( ) ;
2324
+ const secretStorageKey = await awaitSecretStorageKeyStoredInAccountData ( ) ;
2283
2325
2284
2326
// Return the newly created key in the sync response
2285
2327
sendSyncResponse ( secretStorageKey ) ;
@@ -2303,7 +2345,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2303
2345
. bootstrapSecretStorage ( { setupNewSecretStorage : true , createSecretStorageKey } ) ;
2304
2346
2305
2347
// Wait for the key to be uploaded in the account data
2306
- let secretStorageKey = await awaitKeyStoredInAccountData ( ) ;
2348
+ let secretStorageKey = await awaitSecretStorageKeyStoredInAccountData ( ) ;
2307
2349
2308
2350
// Return the newly created key in the sync response
2309
2351
sendSyncResponse ( secretStorageKey ) ;
@@ -2317,7 +2359,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2317
2359
. bootstrapSecretStorage ( { setupNewSecretStorage : true , createSecretStorageKey } ) ;
2318
2360
2319
2361
// Wait for the key to be uploaded in the account data
2320
- secretStorageKey = await awaitKeyStoredInAccountData ( ) ;
2362
+ secretStorageKey = await awaitSecretStorageKeyStoredInAccountData ( ) ;
2321
2363
2322
2364
// Return the newly created key in the sync response
2323
2365
sendSyncResponse ( secretStorageKey ) ;
@@ -2329,5 +2371,30 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
2329
2371
expect ( createSecretStorageKey ) . toHaveBeenCalledTimes ( 2 ) ;
2330
2372
} ,
2331
2373
) ;
2374
+
2375
+ newBackendOnly ( "should upload cross signing master key" , async ( ) => {
2376
+ mockSetupCrossSigningRequests ( ) ;
2377
+
2378
+ await aliceClient . getCrypto ( ) ?. bootstrapCrossSigning ( { } ) ;
2379
+
2380
+ const bootstrapPromise = aliceClient
2381
+ . getCrypto ( ) !
2382
+ . bootstrapSecretStorage ( { setupNewSecretStorage : true , createSecretStorageKey } ) ;
2383
+
2384
+ // Wait for the key to be uploaded in the account data
2385
+ const secretStorageKey = await awaitSecretStorageKeyStoredInAccountData ( ) ;
2386
+
2387
+ // Return the newly created key in the sync response
2388
+ sendSyncResponse ( secretStorageKey ) ;
2389
+
2390
+ // Wait for the cross signing key to be uploaded
2391
+ const crossSigningKey = await awaitCrossSigningMasterKeyUpload ( ) ;
2392
+
2393
+ // Finally, wait for bootstrapSecretStorage to finished
2394
+ await bootstrapPromise ;
2395
+
2396
+ // Expect the cross signing master key to be uploaded and to be encrypted with `secretStorageKey`
2397
+ expect ( crossSigningKey [ secretStorageKey ] ) . toBeDefined ( ) ;
2398
+ } ) ;
2332
2399
} ) ;
2333
2400
} ) ;
0 commit comments