diff options
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-js-sdk/src/crypto/dehydration.ts')
-rw-r--r-- | includes/external/matrix/node_modules/matrix-js-sdk/src/crypto/dehydration.ts | 271 |
1 files changed, 0 insertions, 271 deletions
diff --git a/includes/external/matrix/node_modules/matrix-js-sdk/src/crypto/dehydration.ts b/includes/external/matrix/node_modules/matrix-js-sdk/src/crypto/dehydration.ts deleted file mode 100644 index 373b236..0000000 --- a/includes/external/matrix/node_modules/matrix-js-sdk/src/crypto/dehydration.ts +++ /dev/null @@ -1,271 +0,0 @@ -/* -Copyright 2020-2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import anotherjson from "another-json"; - -import type { IDeviceKeys, IOneTimeKey } from "../@types/crypto"; -import { decodeBase64, encodeBase64 } from "./olmlib"; -import { IndexedDBCryptoStore } from "../crypto/store/indexeddb-crypto-store"; -import { decryptAES, encryptAES } from "./aes"; -import { logger } from "../logger"; -import { Crypto } from "./index"; -import { Method } from "../http-api"; -import { SecretStorageKeyDescription } from "../secret-storage"; - -export interface IDehydratedDevice { - device_id: string; // eslint-disable-line camelcase - device_data: SecretStorageKeyDescription & { - // eslint-disable-line camelcase - algorithm: string; - account: string; // pickle - }; -} - -export interface IDehydratedDeviceKeyInfo { - passphrase?: string; -} - -export const DEHYDRATION_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle"; - -const oneweek = 7 * 24 * 60 * 60 * 1000; - -export class DehydrationManager { - private inProgress = false; - private timeoutId: any; - private key?: Uint8Array; - private keyInfo?: { [props: string]: any }; - private deviceDisplayName?: string; - - public constructor(private readonly crypto: Crypto) { - this.getDehydrationKeyFromCache(); - } - - public getDehydrationKeyFromCache(): Promise<void> { - return this.crypto.cryptoStore.doTxn("readonly", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => { - this.crypto.cryptoStore.getSecretStorePrivateKey( - txn, - async (result) => { - if (result) { - const { key, keyInfo, deviceDisplayName, time } = result; - const pickleKey = Buffer.from(this.crypto.olmDevice.pickleKey); - const decrypted = await decryptAES(key, pickleKey, DEHYDRATION_ALGORITHM); - this.key = decodeBase64(decrypted); - this.keyInfo = keyInfo; - this.deviceDisplayName = deviceDisplayName; - const now = Date.now(); - const delay = Math.max(1, time + oneweek - now); - this.timeoutId = global.setTimeout(this.dehydrateDevice.bind(this), delay); - } - }, - "dehydration", - ); - }); - } - - /** set the key, and queue periodic dehydration to the server in the background */ - public async setKeyAndQueueDehydration( - key: Uint8Array, - keyInfo: { [props: string]: any } = {}, - deviceDisplayName?: string, - ): Promise<void> { - const matches = await this.setKey(key, keyInfo, deviceDisplayName); - if (!matches) { - // start dehydration in the background - this.dehydrateDevice(); - } - } - - public async setKey( - key: Uint8Array, - keyInfo: { [props: string]: any } = {}, - deviceDisplayName?: string, - ): Promise<boolean | undefined> { - if (!key) { - // unsetting the key -- cancel any pending dehydration task - if (this.timeoutId) { - global.clearTimeout(this.timeoutId); - this.timeoutId = undefined; - } - // clear storage - await this.crypto.cryptoStore.doTxn("readwrite", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => { - this.crypto.cryptoStore.storeSecretStorePrivateKey(txn, "dehydration", null); - }); - this.key = undefined; - this.keyInfo = undefined; - return; - } - - // Check to see if it's the same key as before. If it's different, - // dehydrate a new device. If it's the same, we can keep the same - // device. (Assume that keyInfo and deviceDisplayName will be the - // same if the key is the same.) - let matches: boolean = !!this.key && key.length == this.key.length; - for (let i = 0; matches && i < key.length; i++) { - if (key[i] != this.key![i]) { - matches = false; - } - } - if (!matches) { - this.key = key; - this.keyInfo = keyInfo; - this.deviceDisplayName = deviceDisplayName; - } - return matches; - } - - /** returns the device id of the newly created dehydrated device */ - public async dehydrateDevice(): Promise<string | undefined> { - if (this.inProgress) { - logger.log("Dehydration already in progress -- not starting new dehydration"); - return; - } - this.inProgress = true; - if (this.timeoutId) { - global.clearTimeout(this.timeoutId); - this.timeoutId = undefined; - } - try { - const pickleKey = Buffer.from(this.crypto.olmDevice.pickleKey); - - // update the crypto store with the timestamp - const key = await encryptAES(encodeBase64(this.key!), pickleKey, DEHYDRATION_ALGORITHM); - await this.crypto.cryptoStore.doTxn("readwrite", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => { - this.crypto.cryptoStore.storeSecretStorePrivateKey(txn, "dehydration", { - keyInfo: this.keyInfo, - key, - deviceDisplayName: this.deviceDisplayName!, - time: Date.now(), - }); - }); - logger.log("Attempting to dehydrate device"); - - logger.log("Creating account"); - // create the account and all the necessary keys - const account = new global.Olm.Account(); - account.create(); - const e2eKeys = JSON.parse(account.identity_keys()); - - const maxKeys = account.max_number_of_one_time_keys(); - // FIXME: generate in small batches? - account.generate_one_time_keys(maxKeys / 2); - account.generate_fallback_key(); - const otks: Record<string, string> = JSON.parse(account.one_time_keys()); - const fallbacks: Record<string, string> = JSON.parse(account.fallback_key()); - account.mark_keys_as_published(); - - // dehydrate the account and store it on the server - const pickledAccount = account.pickle(new Uint8Array(this.key!)); - - const deviceData: { [props: string]: any } = { - algorithm: DEHYDRATION_ALGORITHM, - account: pickledAccount, - }; - if (this.keyInfo!.passphrase) { - deviceData.passphrase = this.keyInfo!.passphrase; - } - - logger.log("Uploading account to server"); - // eslint-disable-next-line camelcase - const dehydrateResult = await this.crypto.baseApis.http.authedRequest<{ device_id: string }>( - Method.Put, - "/dehydrated_device", - undefined, - { - device_data: deviceData, - initial_device_display_name: this.deviceDisplayName, - }, - { - prefix: "/_matrix/client/unstable/org.matrix.msc2697.v2", - }, - ); - - // send the keys to the server - const deviceId = dehydrateResult.device_id; - logger.log("Preparing device keys", deviceId); - const deviceKeys: IDeviceKeys = { - algorithms: this.crypto.supportedAlgorithms, - device_id: deviceId, - user_id: this.crypto.userId, - keys: { - [`ed25519:${deviceId}`]: e2eKeys.ed25519, - [`curve25519:${deviceId}`]: e2eKeys.curve25519, - }, - }; - const deviceSignature = account.sign(anotherjson.stringify(deviceKeys)); - deviceKeys.signatures = { - [this.crypto.userId]: { - [`ed25519:${deviceId}`]: deviceSignature, - }, - }; - if (this.crypto.crossSigningInfo.getId("self_signing")) { - await this.crypto.crossSigningInfo.signObject(deviceKeys, "self_signing"); - } - - logger.log("Preparing one-time keys"); - const oneTimeKeys: Record<string, IOneTimeKey> = {}; - for (const [keyId, key] of Object.entries(otks.curve25519)) { - const k: IOneTimeKey = { key }; - const signature = account.sign(anotherjson.stringify(k)); - k.signatures = { - [this.crypto.userId]: { - [`ed25519:${deviceId}`]: signature, - }, - }; - oneTimeKeys[`signed_curve25519:${keyId}`] = k; - } - - logger.log("Preparing fallback keys"); - const fallbackKeys: Record<string, IOneTimeKey> = {}; - for (const [keyId, key] of Object.entries(fallbacks.curve25519)) { - const k: IOneTimeKey = { key, fallback: true }; - const signature = account.sign(anotherjson.stringify(k)); - k.signatures = { - [this.crypto.userId]: { - [`ed25519:${deviceId}`]: signature, - }, - }; - fallbackKeys[`signed_curve25519:${keyId}`] = k; - } - - logger.log("Uploading keys to server"); - await this.crypto.baseApis.http.authedRequest( - Method.Post, - "/keys/upload/" + encodeURI(deviceId), - undefined, - { - "device_keys": deviceKeys, - "one_time_keys": oneTimeKeys, - "org.matrix.msc2732.fallback_keys": fallbackKeys, - }, - ); - logger.log("Done dehydrating"); - - // dehydrate again in a week - this.timeoutId = global.setTimeout(this.dehydrateDevice.bind(this), oneweek); - - return deviceId; - } finally { - this.inProgress = false; - } - } - - public stop(): void { - if (this.timeoutId) { - global.clearTimeout(this.timeoutId); - this.timeoutId = undefined; - } - } -} |