diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 6d3d55bc..30335d23 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -777,13 +777,15 @@ export class Session { txn.accountData.set(event); } } - changes.accountData = accountData.events; + if (this._secretStorage) { + changes.secretStorageChanges = await this._secretStorage.writeSync(accountData.events, txn, log); + } } return changes; } /** @internal */ - afterSync({syncInfo, e2eeAccountChanges, accountData}) { + afterSync({syncInfo, e2eeAccountChanges, secretStorageChanges}) { if (syncInfo) { // sync transaction succeeded, modify object state now this._syncInfo = syncInfo; @@ -791,8 +793,8 @@ export class Session { if (this._e2eeAccount) { this._e2eeAccount.afterSync(e2eeAccountChanges); } - if (accountData && this._secretStorage) { - this._secretStorage.afterSync(accountData); + if (secretStorageChanges && this._secretStorage) { + this._secretStorage.afterSync(secretStorageChanges); } } diff --git a/src/matrix/ssss/SecretStorage.ts b/src/matrix/ssss/SecretStorage.ts index a5e15768..e8e13080 100644 --- a/src/matrix/ssss/SecretStorage.ts +++ b/src/matrix/ssss/SecretStorage.ts @@ -13,7 +13,11 @@ 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 type {Key} from "./common"; +import {BaseObservableValue, RetainedObservableValue} from "../../observable/value"; +import {KeyType} from "./index"; +import {keyFromPassphrase} from "./passphrase"; +import {keyFromRecoveryKey} from "./recoveryKey"; +import type {Key, KeyDescription} from "./common"; import type {Platform} from "../../platform/web/Platform.js"; import type {Transaction} from "../storage/idb/Transaction"; import type {Storage} from "../storage/idb/Storage"; @@ -37,11 +41,25 @@ class DecryptionError extends Error { } } +type AccountData = {type: string, content: Record}; + +type KeyCredentials = { + type: KeyType, + credential: string +} + export class SecretStorage { - private readonly _key: Key; + // we know the id but don't have the description yet + private _keyId?: string; + // we have the description but not the credentials yet + private _keyDescription?: KeyDescription; + // we have the credentials but not the id or description yet + private _keyCredentials?: KeyCredentials; + // we have everything to compose a valid key + private _key?: Key; private readonly _platform: Platform; private readonly _storage: Storage; - private observedSecrets + private observedSecrets: Map>; constructor({key, platform, storage}: {key: Key, platform: Platform, storage: Storage}) { this._key = key; @@ -49,12 +67,60 @@ export class SecretStorage { this._storage = storage; } - afterSync(accountData: ReadonlyArray<{type: string, content: Record}>): void { - for(const event of accountData) { - if (type === ) + load() { + // read key + } + + async setKey(type: KeyType, credential: string) { + const credentials: KeyCredentials = {type, credential}; + this._keyCredentials = credentials; + this.updateKey(this._keyDescription, this._keyCredentials); + } + + async setKeyWithDehydratedDeviceKey() { + + } + + private async updateKey(keyDescription: KeyDescription | undefined, credentials: KeyCredentials | undefined, txn: Transaction) { + if (keyDescription && credentials) { + if (credentials.type === KeyType.Passphrase) { + this._key = await keyFromPassphrase(keyDescription, credentials.credential, this._platform); + } else if (credentials.type === KeyType.RecoveryKey) { + this._key = await keyFromRecoveryKey(keyDescription, credentials.credential, this._olm, this._platform); + } + // } } + private update(keyDescription: KeyDescription, credentials: KeyCredentials) { + + } + + writeSync(accountData: ReadonlyArray, txn: Transaction, log: ILogItem): Promise { + + const newDefaultKey = accountData.find(e => e.type === "m.secret_storage.default_key"); + const keyId: string | undefined = newDefaultKey ? newDefaultKey.content?.key : this._keyId; + const keyEventType = keyId ? `m.secret_storage.key.${keyId}` : undefined; + let newKey = keyEventType ? accountData.find(e => e.type === keyEventType) : undefined; + if (newDefaultKey && keyEventType && !newKey) { + newKey = await txn.accountData.get(keyEventType); + } + if (newKey) { + this.setKeyDescription() + } + const keyChanged = !!newDefaultKey || !!newKey; + if (keyChanged) { + // update all values + } else { + for(const event of accountData) { + + } + } + } + + afterSync(): void { + } + /** this method will auto-commit any indexeddb transaction because of its use of the webcrypto api */ async hasValidKeyForAnyAccountData() { const txn = await this._storage.readTxn([ diff --git a/src/matrix/ssss/index.ts b/src/matrix/ssss/index.ts index 02f3290e..3b939a92 100644 --- a/src/matrix/ssss/index.ts +++ b/src/matrix/ssss/index.ts @@ -30,8 +30,8 @@ const SSSS_KEY = `${SESSION_E2EE_KEY_PREFIX}ssssKey`; const BACKUPVERSION_KEY = `${SESSION_E2EE_KEY_PREFIX}keyBackupVersion`; export enum KeyType { - "RecoveryKey", - "Passphrase" + RecoveryKey, + Passphrase } async function readDefaultKeyDescription(storage: Storage): Promise { diff --git a/src/matrix/ssss/passphrase.ts b/src/matrix/ssss/passphrase.ts index 00e4801e..32d2cb0c 100644 --- a/src/matrix/ssss/passphrase.ts +++ b/src/matrix/ssss/passphrase.ts @@ -27,7 +27,7 @@ const DEFAULT_BITSIZE = 256; * @param {Platform} platform * @return {Key} */ -export async function keyFromPassphrase(keyDescription: KeyDescription, passphrase: string, platform: Platform): Promise { +export async function keyFromPassphrase(passphrase: string, platform: Platform): Promise { const {passphraseParams} = keyDescription; if (!passphraseParams) { throw new Error("not a passphrase key");