mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 03:25:12 +01:00
Persist request-id in storage
This commit is contained in:
parent
af2dde7a1f
commit
f8bfc384d3
@ -25,6 +25,7 @@ import type {Encoding} from "../../platform/web/utils/Encoding.js";
|
|||||||
import type {CrossSigning} from "../verification/CrossSigning";
|
import type {CrossSigning} from "../verification/CrossSigning";
|
||||||
import type {SecretFetcher} from "./SecretFetcher";
|
import type {SecretFetcher} from "./SecretFetcher";
|
||||||
import type {ObservableValue} from "../../observable/value";
|
import type {ObservableValue} from "../../observable/value";
|
||||||
|
import type {DecryptionResult} from "../e2ee/DecryptionResult";
|
||||||
import {makeTxnId, formatToDeviceMessagesPayload} from "../common.js";
|
import {makeTxnId, formatToDeviceMessagesPayload} from "../common.js";
|
||||||
import {Deferred} from "../../utils/Deferred";
|
import {Deferred} from "../../utils/Deferred";
|
||||||
import {StoreNames} from "../storage/common";
|
import {StoreNames} from "../storage/common";
|
||||||
@ -48,6 +49,9 @@ const enum EVENT_TYPE {
|
|||||||
SEND = "m.secret.send",
|
SEND = "m.secret.send",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const STORAGE_KEY = "secretRequestIds";
|
||||||
|
|
||||||
export class SecretSharing {
|
export class SecretSharing {
|
||||||
private readonly hsApi: HomeServerApi;
|
private readonly hsApi: HomeServerApi;
|
||||||
private readonly storage: Storage;
|
private readonly storage: Storage;
|
||||||
@ -80,20 +84,18 @@ export class SecretSharing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async init() {
|
private async init() {
|
||||||
this.deviceMessageHandler.on("message", ({ encrypted }) => {
|
this.deviceMessageHandler.on("message", async ({ encrypted }) => {
|
||||||
const type: EVENT_TYPE = encrypted?.event.type;
|
const type: EVENT_TYPE = encrypted?.event.type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EVENT_TYPE.REQUEST: {
|
case EVENT_TYPE.REQUEST: {
|
||||||
this._respondToRequest(encrypted);
|
this._respondToRequest(encrypted);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_TYPE.SEND: {
|
case EVENT_TYPE.SEND: {
|
||||||
const { request_id, secret } = encrypted.event.content;
|
const {secret} = encrypted.event.content;
|
||||||
const obj = this.waitMap.get(request_id);
|
const name = await this.shouldAcceptSecret(encrypted);
|
||||||
if (obj) {
|
if (name) {
|
||||||
const { deferred, name } = obj;
|
this.writeSecretToStorage(name, secret);
|
||||||
deferred.resolve(encrypted);
|
|
||||||
this.waitMap.delete(request_id);
|
|
||||||
this.writeToStorage(name, secret);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -180,6 +182,40 @@ export class SecretSharing {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns name of the secret if we can accept the response.
|
||||||
|
* Returns undefined otherwise.
|
||||||
|
* @param decryptionResult Encrypted to-device event that contains the secret
|
||||||
|
*/
|
||||||
|
async shouldAcceptSecret(decryptionResult: DecryptionResult): Promise<string | undefined> {
|
||||||
|
const content = decryptionResult.event.content!;
|
||||||
|
const requestId = content.request_id;
|
||||||
|
const obj = this.waitMap.get(requestId);
|
||||||
|
if (obj) {
|
||||||
|
const { name, deferred } = obj;
|
||||||
|
deferred.resolve(decryptionResult);
|
||||||
|
this.waitMap.delete(requestId);
|
||||||
|
await this.removeStoredRequestId(requestId);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
const txn = await this.storage.readTxn([this.storage.storeNames.session]);
|
||||||
|
const storedIds = await txn.session.get(STORAGE_KEY);
|
||||||
|
const name = storedIds?.[requestId];
|
||||||
|
if (name) {
|
||||||
|
await this.removeStoredRequestId(requestId);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeStoredRequestId(requestId: string): Promise<void> {
|
||||||
|
const txn = await this.storage.readWriteTxn([this.storage.storeNames.session]);
|
||||||
|
const storedIds = await txn.session.get(STORAGE_KEY);
|
||||||
|
if (storedIds) {
|
||||||
|
delete storedIds[requestId];
|
||||||
|
txn.session.set(STORAGE_KEY, storedIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getLocallyStoredSecret(name: string): Promise<any> {
|
async getLocallyStoredSecret(name: string): Promise<any> {
|
||||||
const txn = await this.storage.readTxn([
|
const txn = await this.storage.readTxn([
|
||||||
this.storage.storeNames.sharedSecrets,
|
this.storage.storeNames.sharedSecrets,
|
||||||
@ -197,12 +233,28 @@ export class SecretSharing {
|
|||||||
const request_id = makeTxnId();
|
const request_id = makeTxnId();
|
||||||
const promise = this.trackSecretRequest(request_id, name);
|
const promise = this.trackSecretRequest(request_id, name);
|
||||||
await this.sendRequestForSecret(name, request_id, _log);
|
await this.sendRequestForSecret(name, request_id, _log);
|
||||||
|
await this.writeRequestIdToStorage(request_id, name);
|
||||||
const request = new SecretRequest(promise);
|
const request = new SecretRequest(promise);
|
||||||
return request;
|
return request;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async writeToStorage(name:string, secret: any) {
|
/**
|
||||||
|
* We will store the request-id of every secret request that we send.
|
||||||
|
* If a device responds to our secret request when we're offline and we receive
|
||||||
|
* it via sync when we come online at some later time, we can use this persisted
|
||||||
|
* request-id to determine if we should accept the secret.
|
||||||
|
*/
|
||||||
|
private async writeRequestIdToStorage(requestId: string, name: string): Promise<void> {
|
||||||
|
const txn = await this.storage.readWriteTxn([
|
||||||
|
this.storage.storeNames.session,
|
||||||
|
]);
|
||||||
|
const txnIds = await txn.session.get(STORAGE_KEY) ?? {};
|
||||||
|
txnIds[requestId] = name;
|
||||||
|
txn.session.set(STORAGE_KEY, txnIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async writeSecretToStorage(name:string, secret: any): Promise<void> {
|
||||||
const encrypted = await this.aesEncryption.encrypt(secret);
|
const encrypted = await this.aesEncryption.encrypt(secret);
|
||||||
const txn = await this.storage.readWriteTxn([StoreNames.sharedSecrets]);
|
const txn = await this.storage.readWriteTxn([StoreNames.sharedSecrets]);
|
||||||
txn.sharedSecrets.set(name, { encrypted });
|
txn.sharedSecrets.set(name, { encrypted });
|
||||||
|
Loading…
Reference in New Issue
Block a user