diff --git a/src/crypto-api/index.ts b/src/crypto-api/index.ts index 94c4ac5a5c2..4a780696770 100644 --- a/src/crypto-api/index.ts +++ b/src/crypto-api/index.ts @@ -20,7 +20,7 @@ import type { ToDeviceBatch, ToDevicePayload } from "../models/ToDeviceMessage.t import { Room } from "../models/room.ts"; import { DeviceMap } from "../models/device.ts"; import { UIAuthCallback } from "../interactive-auth.ts"; -import { PassphraseInfo, SecretStorageCallbacks, SecretStorageKeyDescription } from "../secret-storage.ts"; +import { PassphraseInfo, SecretStorageKeyDescription } from "../secret-storage.ts"; import { VerificationRequest } from "./verification.ts"; import { BackupTrustInfo, @@ -268,9 +268,9 @@ export interface CryptoApi { * - is enabled on this account and trusted by this device * - has private keys either cached locally or stored in secret storage * - * If this function returns false, bootstrapCrossSigning() can be used + * If this function returns false, {@link bootstrapCrossSigning()} can be used * to fix things such that it returns true. That is to say, after - * bootstrapCrossSigning() completes successfully, this function should + * `bootstrapCrossSigning()` completes successfully, this function should * return true. * * @returns True if cross-signing is ready to be used on this device @@ -317,9 +317,9 @@ export interface CryptoApi { * - is storing cross-signing private keys * - is storing session backup key (if enabled) * - * If this function returns false, bootstrapSecretStorage() can be used + * If this function returns false, {@link bootstrapSecretStorage()} can be used * to fix things such that it returns true. That is to say, after - * bootstrapSecretStorage() completes successfully, this function should + * `bootstrapSecretStorage()` completes successfully, this function should * return true. * * @returns True if secret storage is ready to be used on this device @@ -327,17 +327,20 @@ export interface CryptoApi { isSecretStorageReady(): Promise; /** - * Bootstrap the secret storage by creating a new secret storage key, add it in the secret storage and - * store the cross signing keys in the secret storage. + * Bootstrap [secret storage](https://spec.matrix.org/v1.12/client-server-api/#storage). * - * - Generate a new key {@link GeneratedSecretStorageKey} with `createSecretStorageKey`. - * Only if `setupNewSecretStorage` is set or if there is no AES key in the secret storage - * - Store this key in the secret storage and set it as the default key. - * - Call `cryptoCallbacks.cacheSecretStorageKey` if provided. - * - Store the cross signing keys in the secret storage if - * - the cross signing is ready - * - a new key was created during the previous step - * - or the secret storage already contains the cross signing keys + * - If secret storage is not already set up, or {@link CreateSecretStorageOpts.setupNewSecretStorage} is set: + * * Calls {@link CreateSecretStorageOpts.createSecretStorageKey} to generate a new key. + * * Stores the metadata of the new key in account data and sets it as the default secret storage key. + * * Calls {@link CryptoCallbacks.cacheSecretStorageKey} if provided. + * - Stores the private cross signing keys in the secret storage if they are known, and they are not + * already stored in secret storage. + * - If {@link CreateSecretStorageOpts.setupNewKeyBackup} is set, calls {@link CryptoApi.resetKeyBackup}; otherwise, + * stores the key backup decryption key in secret storage if it is known, and it is not + * already stored in secret storage. + * + * Note that there may be multiple accesses to secret storage during the course of this call, each of which will + * result in a call to {@link CryptoCallbacks.getSecretStorageKey}. * * @param opts - Options object. */ @@ -562,9 +565,10 @@ export interface CryptoApi { * * If there are existing backups they will be replaced. * - * The decryption key will be saved in Secret Storage (the {@link matrix.SecretStorage.SecretStorageCallbacks.getSecretStorageKey} Crypto - * callback will be called) - * and the backup engine will be started. + * If secret storage is set up, the new decryption key will be saved (the {@link CryptoCallbacks.getSecretStorageKey} + * callback will be called to obtain the secret storage key). + * + * The backup engine will be started using the new backup version (i.e., {@link checkKeyBackupAndEnable} is called). */ resetKeyBackup(): Promise; @@ -995,15 +999,77 @@ export interface CrossSigningStatus { /** * Crypto callbacks provided by the application */ -export interface CryptoCallbacks extends SecretStorageCallbacks { +export interface CryptoCallbacks { + /** + * Called to retrieve a secret storage encryption key. + * + * [Server-side secret storage](https://spec.matrix.org/v1.12/client-server-api/#key-storage) + * is, as the name implies, a mechanism for storing secrets which should be shared between + * clients on the server. For example, it is typically used for storing the + * [key backup decryption key](https://spec.matrix.org/v1.12/client-server-api/#decryption-key) + * and the private [cross-signing keys](https://spec.matrix.org/v1.12/client-server-api/#cross-signing). + * + * The secret storage mechanism encrypts the secrets before uploading them to the server using a + * secret storage key. The schema supports multiple keys, but in practice only one tends to be used + * at once; this is the "default secret storage key" and may be known as the "recovery key" (or, sometimes, + * the "security key"). + * + * Secret storage can be set up by calling {@link CryptoApi.bootstrapSecretStorage}. Having done so, when + * the crypto stack needs to access secret storage (for example, when setting up a new device, or to + * store newly-generated secrets), it will use this callback (`getSecretStorageKey`). + * + * Note that the secret storage key may be needed several times in quick succession: it is recommended + * that applications use a temporary cache to avoid prompting the user multiple times for the key. See + * also {@link cacheSecretStorageKey} which is called when a new key is created. + * + * The helper method {@link deriveRecoveryKeyFromPassphrase} may be useful if the secret storage key + * was derived from a passphrase. + * + * @param opts - An options object. + * + * @param name - the name of the *secret* (NB: not the encryption key) being stored or retrieved. + * When the item is stored in account data, it will have this `type`. + * + * @returns a pair [`keyId`, `privateKey`], where `keyId` is one of the keys from the `keys` parameter, + * and `privateKey` is the raw private encryption key, as appropriate for the encryption algorithm. + * (For `m.secret_storage.v1.aes-hmac-sha2`, it is the input to an HKDF as defined in the + * [specification](https://spec.matrix.org/v1.6/client-server-api/#msecret_storagev1aes-hmac-sha2).) + * + * Alternatively, if none of the keys are known, may return `null` — in which case the original + * operation that requires access to a secret in secret storage may fail with an exception. + */ + getSecretStorageKey?: ( + opts: { + /** + * Details of the secret storage keys required: a map from the key ID + * (excluding the `m.secret_storage.key.` prefix) to details of the key. + * + * When storing a secret, `keys` will contain exactly one entry. + * + * For secret retrieval, `keys` may contain several entries, and the application can return + * any one of the requested keys. Unless your application specifically wants to offer the + * user the ability to have more than one secret storage key active at a time, it is recommended + * to call {@link matrix.SecretStorage.ServerSideSecretStorage.getDefaultKeyId | ServerSideSecretStorage.getDefaultKeyId} + * to figure out which is the current default key, and to return `null` if the default key is not listed in `keys`. + */ + keys: Record; + }, + name: string, + ) => Promise<[string, Uint8Array] | null>; + /** @deprecated: unused with the Rust crypto stack. */ getCrossSigningKey?: (keyType: string, pubKey: string) => Promise; /** @deprecated: unused with the Rust crypto stack. */ saveCrossSigningKeys?: (keys: Record) => void; /** @deprecated: unused with the Rust crypto stack. */ shouldUpgradeDeviceVerifications?: (users: Record) => Promise; + /** - * Called by {@link CryptoApi#bootstrapSecretStorage} + * Called by {@link CryptoApi.bootstrapSecretStorage} when a new default secret storage key is created. + * + * Applications can use this to (temporarily) cache the secret storage key, for later return by + * {@link getSecretStorageKey}. + * * @param keyId - secret storage key id * @param keyInfo - secret storage key info * @param key - private key to store