Skip to content

Commit

Permalink
Add CryptoApi#resetEncryption
Browse files Browse the repository at this point in the history
  • Loading branch information
florianduros committed Jan 14, 2025
1 parent f22d5e9 commit f99e069
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/@types/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ export interface AccountDataEvents extends SecretStorageAccountDataEvents {
[EventType.PushRules]: IPushRules;
[EventType.Direct]: { [userId: string]: string[] };
[EventType.IgnoredUserList]: { [userId: string]: {} };
"m.secret_storage.default_key": { key: string };
"m.secret_storage.default_key": { key: string } | {};
"m.identity_server": { base_url: string | null };
[key: `${typeof LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${string}`]: LocalNotificationSettings;
[key: `m.secret_storage.key.${string}`]: SecretStorageKeyDescription;
Expand Down
13 changes: 13 additions & 0 deletions src/crypto-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,19 @@ export interface CryptoApi {
payload: ToDevicePayload,
): Promise<ToDeviceBatch>;

/**
*
* - Disable backing up room keys and delete any existing backup.
* - Remove the default secret storage key from the account data (ie: the recovery key).
* - Reset the cross-signing keys.
* - Re-enable backing up room keys if enabled before.
*
* @param authUploadDeviceSigningKeys - Callback to authenticate the upload of device signing keys.
* Used when resetting the cross signing keys.
* See {@link BootstrapCrossSigningOpts#authUploadDeviceSigningKeys}.
*/
resetEncryption(authUploadDeviceSigningKeys: UIAuthCallback<void>): Promise<void>;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Device/User verification
Expand Down
7 changes: 7 additions & 0 deletions src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4340,6 +4340,13 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
): Promise<KeyBackupRestoreResult> {
throw new Error("Not implemented");
}

/**
* Stub function -- resetEncryption is not implemented here, so throw error
*/
public resetEncryption(): Promise<void> {
throw new Error("Not implemented");
}
}

/**
Expand Down
23 changes: 23 additions & 0 deletions src/rust-crypto/rust-crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import { PerSessionKeyBackupDownloader } from "./PerSessionKeyBackupDownloader.t
import { DehydratedDeviceManager } from "./DehydratedDeviceManager.ts";
import { VerificationMethod } from "../types.ts";
import { keyFromAuthData } from "../common-crypto/key-passphrase.ts";
import { UIAuthCallback } from "../interactive-auth.ts";

const ALL_VERIFICATION_METHODS = [
VerificationMethod.Sas,
Expand Down Expand Up @@ -1472,6 +1473,28 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
return batch;
}

/**
* Implementation of {@link CryptoApi#resetEncryption}.
*/
public async resetEncryption(authUploadDeviceSigningKeys: UIAuthCallback<void>): Promise<void> {
const backupEnabled = (await this.backupManager.getActiveBackupVersion()) !== null;

// Delete all the backup
await this.backupManager.deleteAllKeyBackupVersions();

// Disable the recovery key and the secret storage
await this.secretStorage.setDefaultKeyId(null);

// Reset the cross-signing keys
await this.crossSigningIdentity.bootstrapCrossSigning({
setupNewCrossSigning: true,
authUploadDeviceSigningKeys,
});

// Enable the key backup if it was enabled before
if (backupEnabled) await this.backupManager.checkKeyBackupAndEnable(true);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SyncCryptoCallbacks implementation
Expand Down
21 changes: 15 additions & 6 deletions src/secret-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,12 @@ export interface ServerSideSecretStorage {

/**
* Set the default key ID for encrypting secrets.
* If keyId is `null`, the default key id value in the account data will be set to an empty object.
* This is considered as "disabling" the default key.
*
* @param keyId - The new default key ID
*/
setDefaultKeyId(keyId: string): Promise<void>;
setDefaultKeyId(keyId: string | null): Promise<void>;
}

/**
Expand Down Expand Up @@ -352,26 +354,33 @@ export class ServerSideSecretStorageImpl implements ServerSideSecretStorage {
*/
public async getDefaultKeyId(): Promise<string | null> {
const defaultKey = await this.accountDataAdapter.getAccountDataFromServer("m.secret_storage.default_key");
if (!defaultKey) return null;
return defaultKey.key ?? null;
if (!defaultKey || !Object.keys(defaultKey).length) return null;
return (defaultKey as { key: string }).key ?? null;
}

/**
* Set the default key ID for encrypting secrets.
*
* @param keyId - The new default key ID
*/
public setDefaultKeyId(keyId: string): Promise<void> {
public setDefaultKeyId(keyId: string | null): Promise<void> {
return new Promise<void>((resolve, reject) => {
const listener = (ev: MatrixEvent): void => {
if (ev.getType() === "m.secret_storage.default_key" && ev.getContent().key === keyId) {
const content = ev.getContent();
const isSameKey = keyId === null ? !Object.keys(content).length : content.key === keyId;
if (ev.getType() === "m.secret_storage.default_key" && isSameKey) {
this.accountDataAdapter.removeListener(ClientEvent.AccountData, listener);
resolve();
}
};
this.accountDataAdapter.on(ClientEvent.AccountData, listener);

this.accountDataAdapter.setAccountData("m.secret_storage.default_key", { key: keyId }).catch((e) => {
// The spec says that the key should be an object with a `key` property
// https://spec.matrix.org/v1.13/client-server-api/#key-storage
// To delete the default key, we send an empty object like the rust sdk does
// (see https://docs.rs/matrix-sdk/latest/matrix_sdk/encryption/recovery/struct.Recovery.html#method.reset_identity)
const newValue = keyId === null ? {} : { key: keyId };
this.accountDataAdapter.setAccountData("m.secret_storage.default_key", newValue).catch((e) => {
this.accountDataAdapter.removeListener(ClientEvent.AccountData, listener);
reject(e);
});
Expand Down

0 comments on commit f99e069

Please sign in to comment.