@@ -8,14 +8,7 @@ Please see LICENSE files in the repository root for full details.
8
8
9
9
import type { Page } from "@playwright/test" ;
10
10
import { expect , test } from "../../element-web-test" ;
11
- import {
12
- autoJoin ,
13
- completeCreateSecretStorageDialog ,
14
- copyAndContinue ,
15
- createSharedRoomWithUser ,
16
- enableKeyBackup ,
17
- verify ,
18
- } from "./utils" ;
11
+ import { autoJoin , createSharedRoomWithUser , enableKeyBackup , verify } from "./utils" ;
19
12
import { type Bot } from "../../pages/bot" ;
20
13
import { type ElementAppPage } from "../../pages/ElementAppPage" ;
21
14
import { isDendrite } from "../../plugins/homeserver/dendrite" ;
@@ -84,123 +77,73 @@ test.describe("Cryptography", function () {
84
77
} ,
85
78
} ) ;
86
79
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
- } ) ;
80
+ /**
81
+ * Verify that the `m.cross_signing.${keyType}` key is available on the account data on the server
82
+ * @param keyType
83
+ */
84
+ async function verifyKey ( app : ElementAppPage , keyType : "master" | "self_signing" | "user_signing" ) {
85
+ const accountData : { encrypted : Record < string , Record < string , string > > } = await app . client . evaluate (
86
+ ( cli , keyType ) => cli . getAccountDataFromServer ( `m.cross_signing.${ keyType } ` ) ,
87
+ keyType ,
88
+ ) ;
89
+
90
+ expect ( accountData . encrypted ) . toBeDefined ( ) ;
91
+ const keys = Object . keys ( accountData . encrypted ) ;
92
+ const key = accountData . encrypted [ keys [ 0 ] ] ;
93
+ expect ( key . ciphertext ) . toBeDefined ( ) ;
94
+ expect ( key . iv ) . toBeDefined ( ) ;
95
+ expect ( key . mac ) . toBeDefined ( ) ;
162
96
}
163
97
98
+ test ( "Setting up key backup by recovery key" , async ( { page, app, user : aliceCredentials } ) => {
99
+ // Verified the device
100
+ await app . client . bootstrapCrossSigning ( aliceCredentials ) ;
101
+
102
+ await enableKeyBackup ( app ) ;
103
+
104
+ // Wait for the cross signing keys to be uploaded
105
+ // Waiting for "Change the recovery key" button ensure that all the secrets are uploaded and cached locally
106
+ const encryptionTab = await app . settings . openUserSettings ( "Encryption" ) ;
107
+ await expect ( encryptionTab . getByRole ( "button" , { name : "Change recovery key" } ) ) . toBeVisible ( ) ;
108
+
109
+ // Verify that the SSSS keys are in the account data stored in the server
110
+ await verifyKey ( app , "master" ) ;
111
+ await verifyKey ( app , "self_signing" ) ;
112
+ await verifyKey ( app , "user_signing" ) ;
113
+ } ) ;
114
+
164
115
test ( "Can reset cross-signing keys" , async ( { page, app, user : aliceCredentials } ) => {
165
116
await app . client . bootstrapCrossSigning ( aliceCredentials ) ;
166
117
const secretStorageKey = await enableKeyBackup ( app ) ;
167
118
168
119
// Fetch the current cross-signing keys
169
120
async function fetchMasterKey ( ) {
170
121
return await test . step ( "Fetch master key from server" , async ( ) => {
171
- const k = await app . client . evaluate ( async ( cli ) => {
172
- const userId = cli . getUserId ( ) ;
173
- const keys = await cli . downloadKeysForUsers ( [ userId ] ) ;
174
- return Object . values ( keys . master_keys [ userId ] . keys ) [ 0 ] ;
175
- } ) ;
176
- console . log ( `fetchMasterKey: ${ k } ` ) ;
122
+ const k = await app . client . evaluate (
123
+ // @ts -ignore we can't use the CrossSigning enum here
124
+ async ( cli ) => await cli . getCrypto ( ) . getCrossSigningKeyId ( "master" ) ,
125
+ ) ;
177
126
return k ;
178
127
} ) ;
179
128
}
129
+
180
130
const masterKey1 = await fetchMasterKey ( ) ;
181
131
182
- // Find the "reset cross signing" button, and click it
183
- await app . settings . openUserSettings ( "Security & Privacy " ) ;
184
- await page . locator ( "div.mx_CrossSigningPanel_buttonRow" ) . getByRole ( "button" , { name : "Reset" } ) . click ( ) ;
132
+ // Find the Reset cryptographic identity button
133
+ const encryptionTab = await app . settings . openUserSettings ( "Encryption " ) ;
134
+ await encryptionTab . getByRole ( "button" , { name : "Reset cryptographic identity " } ) . click ( ) ;
185
135
186
136
// Confirm
187
- await page . getByRole ( "button" , { name : "Clear cross-signing keys " } ) . click ( ) ;
137
+ await encryptionTab . getByRole ( "button" , { name : "Continue " } ) . click ( ) ;
188
138
189
139
// Enter the 4S key
190
140
await page . getByPlaceholder ( "Recovery Key" ) . fill ( secretStorageKey ) ;
191
141
await page . getByRole ( "button" , { name : "Continue" } ) . click ( ) ;
192
142
193
- // Enter the password
194
- await page . getByPlaceholder ( "Password" ) . fill ( aliceCredentials . password ) ;
195
- await page . getByRole ( "button" , { name : "Continue" } ) . click ( ) ;
196
-
197
143
await expect ( async ( ) => {
198
144
const masterKey2 = await fetchMasterKey ( ) ;
199
145
expect ( masterKey1 ) . not . toEqual ( masterKey2 ) ;
200
146
} ) . toPass ( ) ;
201
-
202
- // The dialog should have gone away
203
- await expect ( page . locator ( ".mx_Dialog" ) ) . toHaveCount ( 1 ) ;
204
147
} ) ;
205
148
206
149
test (
0 commit comments