-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Encryption tab: hide
Advanced
section when the key storage is out o…
…f sync (#29129) * fix(encryption tab): hide the advanced section when the secrets are not cached locally The secret verification is now made at the level of `EncryptionUserSettingsTab` instead at the `RecoveryPanel` level. In the `EncryptionUserSettingsTab`, we decide to only display `RecoveryPanelOutOfSync` in case of uncached secrets. `RecoveryPanelOutOfSync` is simplified version of `RecoveryPanel` handling only the `secrets_not_cached` case. * refactor(encryption tab): simplify the `RecoveryPanel` without having to handle the missing secrets * test(encryption tab): move test about cached secrets in `EncryptionUserSettingsTab-test.tsx` * test(encryption tab): move e2e test which are testing all the encryption tab in `encryption-tab.spec.ts * refactor(encryption tab): move `RecoveryPanelOutOfSync` in its own file - fix typos - call onFinish after accessSecretStorage - onFinish doesn't need to be asynchronous * doc(encryption tab): improve documentation when the secrets are not cached locally * test(encryption tab): improve test documentation and naming * doc(encryption tab): improve `RecoveryPanelOutOfSync` documentation
- Loading branch information
1 parent
e75ba35
commit b7f8623
Showing
13 changed files
with
307 additions
and
227 deletions.
There are no files selected for viewing
96 changes: 96 additions & 0 deletions
96
playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* Copyright 2025 New Vector Ltd. | ||
* | ||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial | ||
* Please see LICENSE files in the repository root for full details. | ||
*/ | ||
|
||
import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api"; | ||
|
||
import { test, expect } from "."; | ||
import { | ||
checkDeviceIsConnectedKeyBackup, | ||
checkDeviceIsCrossSigned, | ||
createBot, | ||
deleteCachedSecrets, | ||
verifySession, | ||
} from "../../crypto/utils"; | ||
|
||
test.describe("Encryption tab", () => { | ||
test.use({ | ||
displayName: "Alice", | ||
}); | ||
|
||
let recoveryKey: GeneratedSecretStorageKey; | ||
let expectedBackupVersion: string; | ||
|
||
test.beforeEach(async ({ page, homeserver, credentials }) => { | ||
// The bot bootstraps cross-signing, creates a key backup and sets up a recovery key | ||
const res = await createBot(page, homeserver, credentials); | ||
recoveryKey = res.recoveryKey; | ||
expectedBackupVersion = res.expectedBackupVersion; | ||
}); | ||
|
||
test( | ||
"should show a 'Verify this device' button if the device is unverified", | ||
{ tag: "@screenshot" }, | ||
async ({ page, app, util }) => { | ||
const dialog = await util.openEncryptionTab(); | ||
const content = util.getEncryptionTabContent(); | ||
|
||
// The user's device is in an unverified state, therefore the only option available to them here is to verify it | ||
const verifyButton = dialog.getByRole("button", { name: "Verify this device" }); | ||
await expect(verifyButton).toBeVisible(); | ||
await expect(content).toMatchScreenshot("verify-device-encryption-tab.png"); | ||
await verifyButton.click(); | ||
|
||
await util.verifyDevice(recoveryKey); | ||
|
||
await expect(content).toMatchScreenshot("default-tab.png", { | ||
mask: [content.getByTestId("deviceId"), content.getByTestId("sessionKey")], | ||
}); | ||
|
||
// Check that our device is now cross-signed | ||
await checkDeviceIsCrossSigned(app); | ||
|
||
// Check that the current device is connected to key backup | ||
// The backup decryption key should be in cache also, as we got it directly from the 4S | ||
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true); | ||
}, | ||
); | ||
|
||
// Test what happens if the cross-signing secrets are in secret storage but are not cached in the local DB. | ||
// | ||
// This can happen if we verified another device and secret-gossiping failed, or the other device itself lacked the secrets. | ||
// We simulate this case by deleting the cached secrets in the indexedDB. | ||
test( | ||
"should prompt to enter the recovery key when the secrets are not cached locally", | ||
{ tag: "@screenshot" }, | ||
async ({ page, app, util }) => { | ||
await verifySession(app, "new passphrase"); | ||
// We need to delete the cached secrets | ||
await deleteCachedSecrets(page); | ||
|
||
await util.openEncryptionTab(); | ||
// We ask the user to enter the recovery key | ||
const dialog = util.getEncryptionTabContent(); | ||
const enterKeyButton = dialog.getByRole("button", { name: "Enter recovery key" }); | ||
await expect(enterKeyButton).toBeVisible(); | ||
await expect(dialog).toMatchScreenshot("out-of-sync-recovery.png"); | ||
await enterKeyButton.click(); | ||
|
||
// Fill the recovery key | ||
await util.enterRecoveryKey(recoveryKey); | ||
await expect(dialog).toMatchScreenshot("default-tab.png", { | ||
mask: [dialog.getByTestId("deviceId"), dialog.getByTestId("sessionKey")], | ||
}); | ||
|
||
// Check that our device is now cross-signed | ||
await checkDeviceIsCrossSigned(app); | ||
|
||
// Check that the current device is connected to key backup | ||
// The backup decryption key should be in cache also, as we got it directly from the 4S | ||
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true); | ||
}, | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
Binary file added
BIN
+21.8 KB
...tings/encryption-user-tab/encryption-tab.spec.ts/out-of-sync-recovery-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file removed
BIN
-20.9 KB
...ts/settings/encryption-user-tab/recovery.spec.ts/out-of-sync-recovery-linux.png
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
src/components/views/settings/encryption/RecoveryPanelOutOfSync.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright 2025 New Vector Ltd. | ||
* | ||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial | ||
* Please see LICENSE files in the repository root for full details. | ||
*/ | ||
|
||
import React, { JSX } from "react"; | ||
import { Button } from "@vector-im/compound-web"; | ||
import KeyIcon from "@vector-im/compound-design-tokens/assets/web/icons/key"; | ||
|
||
import { SettingsSection } from "../shared/SettingsSection"; | ||
import { _t } from "../../../../languageHandler"; | ||
import { SettingsSubheader } from "../SettingsSubheader"; | ||
import { accessSecretStorage } from "../../../../SecurityManager"; | ||
|
||
interface RecoveryPanelOutOfSyncProps { | ||
/** | ||
* Callback for when the user has finished entering their recovery key. | ||
*/ | ||
onFinish: () => void; | ||
} | ||
|
||
/** | ||
* This component is shown as part of the {@link EncryptionUserSettingsTab}, instead of the | ||
* {@link RecoveryPanel}, when some of the user secrets are not cached in the local client. | ||
* | ||
* It prompts the user to enter their recovery key so that the secrets can be loaded from 4S into | ||
* the client. | ||
*/ | ||
export function RecoveryPanelOutOfSync({ onFinish }: RecoveryPanelOutOfSyncProps): JSX.Element { | ||
return ( | ||
<SettingsSection | ||
legacy={false} | ||
heading={_t("settings|encryption|recovery|title")} | ||
subHeading={ | ||
<SettingsSubheader | ||
label={_t("settings|encryption|recovery|description")} | ||
state="error" | ||
stateMessage={_t("settings|encryption|recovery|key_storage_warning")} | ||
/> | ||
} | ||
data-testid="recoveryPanel" | ||
> | ||
<Button | ||
size="sm" | ||
kind="primary" | ||
Icon={KeyIcon} | ||
onClick={async () => { | ||
await accessSecretStorage(); | ||
onFinish(); | ||
}} | ||
> | ||
{_t("settings|encryption|recovery|enter_recovery_key")} | ||
</Button> | ||
</SettingsSection> | ||
); | ||
} |
Oops, something went wrong.