This commit is contained in:
Bruno Windels 2023-03-31 17:42:38 +02:00
parent 25aac4b7c0
commit 8cf7a1b161
4 changed files with 81 additions and 13 deletions

View File

@ -777,13 +777,15 @@ export class Session {
txn.accountData.set(event); txn.accountData.set(event);
} }
} }
changes.accountData = accountData.events; if (this._secretStorage) {
changes.secretStorageChanges = await this._secretStorage.writeSync(accountData.events, txn, log);
}
} }
return changes; return changes;
} }
/** @internal */ /** @internal */
afterSync({syncInfo, e2eeAccountChanges, accountData}) { afterSync({syncInfo, e2eeAccountChanges, secretStorageChanges}) {
if (syncInfo) { if (syncInfo) {
// sync transaction succeeded, modify object state now // sync transaction succeeded, modify object state now
this._syncInfo = syncInfo; this._syncInfo = syncInfo;
@ -791,8 +793,8 @@ export class Session {
if (this._e2eeAccount) { if (this._e2eeAccount) {
this._e2eeAccount.afterSync(e2eeAccountChanges); this._e2eeAccount.afterSync(e2eeAccountChanges);
} }
if (accountData && this._secretStorage) { if (secretStorageChanges && this._secretStorage) {
this._secretStorage.afterSync(accountData); this._secretStorage.afterSync(secretStorageChanges);
} }
} }

View File

@ -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 See the License for the specific language governing permissions and
limitations under the License. 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 {Platform} from "../../platform/web/Platform.js";
import type {Transaction} from "../storage/idb/Transaction"; import type {Transaction} from "../storage/idb/Transaction";
import type {Storage} from "../storage/idb/Storage"; import type {Storage} from "../storage/idb/Storage";
@ -37,11 +41,25 @@ class DecryptionError extends Error {
} }
} }
type AccountData = {type: string, content: Record<string, any>};
type KeyCredentials = {
type: KeyType,
credential: string
}
export class SecretStorage { 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 _platform: Platform;
private readonly _storage: Storage; private readonly _storage: Storage;
private observedSecrets private observedSecrets: Map<string, RetainedObservableValue<string | undefined>>;
constructor({key, platform, storage}: {key: Key, platform: Platform, storage: Storage}) { constructor({key, platform, storage}: {key: Key, platform: Platform, storage: Storage}) {
this._key = key; this._key = key;
@ -49,12 +67,60 @@ export class SecretStorage {
this._storage = storage; this._storage = storage;
} }
afterSync(accountData: ReadonlyArray<{type: string, content: Record<string, any>}>): void { load() {
for(const event of accountData) { // read key
if (type === ) }
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<AccountData>, txn: Transaction, log: ILogItem): Promise<void> {
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 */ /** this method will auto-commit any indexeddb transaction because of its use of the webcrypto api */
async hasValidKeyForAnyAccountData() { async hasValidKeyForAnyAccountData() {
const txn = await this._storage.readTxn([ const txn = await this._storage.readTxn([

View File

@ -30,8 +30,8 @@ const SSSS_KEY = `${SESSION_E2EE_KEY_PREFIX}ssssKey`;
const BACKUPVERSION_KEY = `${SESSION_E2EE_KEY_PREFIX}keyBackupVersion`; const BACKUPVERSION_KEY = `${SESSION_E2EE_KEY_PREFIX}keyBackupVersion`;
export enum KeyType { export enum KeyType {
"RecoveryKey", RecoveryKey,
"Passphrase" Passphrase
} }
async function readDefaultKeyDescription(storage: Storage): Promise<KeyDescription | undefined> { async function readDefaultKeyDescription(storage: Storage): Promise<KeyDescription | undefined> {

View File

@ -27,7 +27,7 @@ const DEFAULT_BITSIZE = 256;
* @param {Platform} platform * @param {Platform} platform
* @return {Key} * @return {Key}
*/ */
export async function keyFromPassphrase(keyDescription: KeyDescription, passphrase: string, platform: Platform): Promise<Key> { export async function keyFromPassphrase(passphrase: string, platform: Platform): Promise<Key> {
const {passphraseParams} = keyDescription; const {passphraseParams} = keyDescription;
if (!passphraseParams) { if (!passphraseParams) {
throw new Error("not a passphrase key"); throw new Error("not a passphrase key");