@@ -6,16 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
6
6
Please see LICENSE files in the repository root for full details.
7
7
*/
8
8
9
+ import { CrossSigningKey } from "matrix-js-sdk/src/crypto-api" ;
10
+
9
11
import type { Page } from "@playwright/test" ;
10
12
import { expect , test } from "../../element-web-test" ;
11
- import {
12
- autoJoin ,
13
- completeCreateSecretStorageDialog ,
14
- copyAndContinue ,
15
- createSharedRoomWithUser ,
16
- enableKeyBackup ,
17
- verify ,
18
- } from "./utils" ;
13
+ import { autoJoin , createSharedRoomWithUser , enableKeyBackup , verify } from "./utils" ;
19
14
import { type Bot } from "../../pages/bot" ;
20
15
import { type ElementAppPage } from "../../pages/ElementAppPage" ;
21
16
import { isDendrite } from "../../plugins/homeserver/dendrite" ;
@@ -84,122 +79,72 @@ test.describe("Cryptography", function () {
84
79
} ,
85
80
} ) ;
86
81
87
- for ( const isDeviceVerified of [ true , false ] ) {
88
- test . describe ( `setting up secure key backup should work isDeviceVerified=${ isDeviceVerified } ` , ( ) => {
89
- /**
90
- * Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
91
- * @param keyType
92
- */
93
- async function verifyKey ( app : ElementAppPage , keyType : "master" | "self_signing" | "user_signing" ) {
94
- const accountData : { encrypted : Record < string , Record < string , string > > } = await app . client . evaluate (
95
- ( cli , keyType ) => cli . getAccountDataFromServer ( `m.cross_signing.${ keyType } ` ) ,
96
- keyType ,
97
- ) ;
98
- expect ( accountData . encrypted ) . toBeDefined ( ) ;
99
- const keys = Object . keys ( accountData . encrypted ) ;
100
- const key = accountData . encrypted [ keys [ 0 ] ] ;
101
- expect ( key . ciphertext ) . toBeDefined ( ) ;
102
- expect ( key . iv ) . toBeDefined ( ) ;
103
- expect ( key . mac ) . toBeDefined ( ) ;
104
- }
105
-
106
- test ( "by recovery code" , async ( { page, app, user : aliceCredentials } ) => {
107
- // Verified the device
108
- if ( isDeviceVerified ) {
109
- await app . client . bootstrapCrossSigning ( aliceCredentials ) ;
110
- }
111
-
112
- await page . route ( "**/_matrix/client/v3/keys/signatures/upload" , async ( route ) => {
113
- // We delay this API otherwise the `Setting up keys` may happen too quickly and cause flakiness
114
- await new Promise ( ( resolve ) => setTimeout ( resolve , 500 ) ) ;
115
- await route . continue ( ) ;
116
- } ) ;
117
-
118
- await app . settings . openUserSettings ( "Security & Privacy" ) ;
119
- await page . getByRole ( "button" , { name : "Set up Secure Backup" } ) . click ( ) ;
120
-
121
- await completeCreateSecretStorageDialog ( page ) ;
122
-
123
- // Verify that the SSSS keys are in the account data stored in the server
124
- await verifyKey ( app , "master" ) ;
125
- await verifyKey ( app , "self_signing" ) ;
126
- await verifyKey ( app , "user_signing" ) ;
127
- } ) ;
128
-
129
- test ( "by passphrase" , async ( { page, app, user : aliceCredentials } ) => {
130
- // Verified the device
131
- if ( isDeviceVerified ) {
132
- await app . client . bootstrapCrossSigning ( aliceCredentials ) ;
133
- }
134
-
135
- await app . settings . openUserSettings ( "Security & Privacy" ) ;
136
- await page . getByRole ( "button" , { name : "Set up Secure Backup" } ) . click ( ) ;
137
-
138
- const dialog = page . locator ( ".mx_Dialog" ) ;
139
- // Select passphrase option
140
- await dialog . getByText ( "Enter a Security Phrase" ) . click ( ) ;
141
- await dialog . getByRole ( "button" , { name : "Continue" } ) . click ( ) ;
142
-
143
- // Fill passphrase input
144
- await dialog . locator ( "input" ) . fill ( "new passphrase for setting up a secure key backup" ) ;
145
- await dialog . locator ( ".mx_Dialog_primary:not([disabled])" , { hasText : "Continue" } ) . click ( ) ;
146
- // Confirm passphrase
147
- await dialog . locator ( "input" ) . fill ( "new passphrase for setting up a secure key backup" ) ;
148
- await dialog . locator ( ".mx_Dialog_primary:not([disabled])" , { hasText : "Continue" } ) . click ( ) ;
149
-
150
- await copyAndContinue ( page ) ;
151
-
152
- await expect ( dialog . getByText ( "Secure Backup successful" ) ) . toBeVisible ( ) ;
153
- await dialog . getByRole ( "button" , { name : "Done" } ) . click ( ) ;
154
- await expect ( dialog . getByText ( "Secure Backup successful" ) ) . not . toBeVisible ( ) ;
155
-
156
- // Verify that the SSSS keys are in the account data stored in the server
157
- await verifyKey ( app , "master" ) ;
158
- await verifyKey ( app , "self_signing" ) ;
159
- await verifyKey ( app , "user_signing" ) ;
160
- } ) ;
161
- } ) ;
82
+ /**
83
+ * Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
84
+ * @param keyType
85
+ */
86
+ async function verifyKey ( app : ElementAppPage , keyType : "master" | "self_signing" | "user_signing" ) {
87
+ const accountData : { encrypted : Record < string , Record < string , string > > } = await app . client . evaluate (
88
+ ( cli , keyType ) => cli . getAccountDataFromServer ( `m.cross_signing.${ keyType } ` ) ,
89
+ keyType ,
90
+ ) ;
91
+
92
+ expect ( accountData . encrypted ) . toBeDefined ( ) ;
93
+ const keys = Object . keys ( accountData . encrypted ) ;
94
+ const key = accountData . encrypted [ keys [ 0 ] ] ;
95
+ expect ( key . ciphertext ) . toBeDefined ( ) ;
96
+ expect ( key . iv ) . toBeDefined ( ) ;
97
+ expect ( key . mac ) . toBeDefined ( ) ;
162
98
}
163
99
100
+ test ( "Setting up key backup by recovery key" , async ( { page, app, user : aliceCredentials } ) => {
101
+ // Verified the device
102
+ await app . client . bootstrapCrossSigning ( aliceCredentials ) ;
103
+
104
+ await enableKeyBackup ( app ) ;
105
+
106
+ // Wait for the cross signing keys to be uploaded
107
+ // Waiting for "Change the recovery key" button ensure that all the secrets are uploaded and cached locally
108
+ const encryptionTab = await app . settings . openUserSettings ( "Encryption" ) ;
109
+ await expect ( encryptionTab . getByRole ( "button" , { name : "Change recovery key" } ) ) . toBeVisible ( ) ;
110
+
111
+ // Verify that the SSSS keys are in the account data stored in the server
112
+ await verifyKey ( app , "master" ) ;
113
+ await verifyKey ( app , "self_signing" ) ;
114
+ await verifyKey ( app , "user_signing" ) ;
115
+ } ) ;
116
+
164
117
test ( "Can reset cross-signing keys" , async ( { page, app, user : aliceCredentials } ) => {
165
118
const secretStorageKey = await enableKeyBackup ( app ) ;
166
119
167
120
// Fetch the current cross-signing keys
168
121
async function fetchMasterKey ( ) {
169
122
return await test . step ( "Fetch master key from server" , async ( ) => {
170
- const k = await app . client . evaluate ( async ( cli ) => {
171
- const userId = cli . getUserId ( ) ;
172
- const keys = await cli . downloadKeysForUsers ( [ userId ] ) ;
173
- return Object . values ( keys . master_keys [ userId ] . keys ) [ 0 ] ;
174
- } ) ;
175
- console . log ( `fetchMasterKey: ${ k } ` ) ;
123
+ const k = await app . client . evaluate (
124
+ async ( cli , keyType ) => await cli . getCrypto ( ) . getCrossSigningKeyId ( keyType ) ,
125
+ CrossSigningKey . Master ,
126
+ ) ;
176
127
return k ;
177
128
} ) ;
178
129
}
130
+
179
131
const masterKey1 = await fetchMasterKey ( ) ;
180
132
181
- // Find the "reset cross signing" button, and click it
182
- await app . settings . openUserSettings ( "Security & Privacy " ) ;
183
- await page . locator ( "div.mx_CrossSigningPanel_buttonRow" ) . getByRole ( "button" , { name : "Reset" } ) . click ( ) ;
133
+ // Find the Reset cryptographic identity button
134
+ const encryptionTab = await app . settings . openUserSettings ( "Encryption " ) ;
135
+ await encryptionTab . getByRole ( "button" , { name : "Reset cryptographic identity " } ) . click ( ) ;
184
136
185
137
// Confirm
186
- await page . getByRole ( "button" , { name : "Clear cross-signing keys " } ) . click ( ) ;
138
+ await encryptionTab . getByRole ( "button" , { name : "Continue " } ) . click ( ) ;
187
139
188
140
// Enter the 4S key
189
141
await page . getByPlaceholder ( "Recovery Key" ) . fill ( secretStorageKey ) ;
190
142
await page . getByRole ( "button" , { name : "Continue" } ) . click ( ) ;
191
143
192
- // Enter the password
193
- await page . getByPlaceholder ( "Password" ) . fill ( aliceCredentials . password ) ;
194
- await page . getByRole ( "button" , { name : "Continue" } ) . click ( ) ;
195
-
196
144
await expect ( async ( ) => {
197
145
const masterKey2 = await fetchMasterKey ( ) ;
198
146
expect ( masterKey1 ) . not . toEqual ( masterKey2 ) ;
199
147
} ) . toPass ( ) ;
200
-
201
- // The dialog should have gone away
202
- await expect ( page . locator ( ".mx_Dialog" ) ) . toHaveCount ( 1 ) ;
203
148
} ) ;
204
149
205
150
test (
0 commit comments