forked from mystiq/hydrogen-web
cleanup code so far
This commit is contained in:
parent
5dc0c8c0b3
commit
cbf82fcd29
4 changed files with 167 additions and 135 deletions
111
src/matrix/e2ee/megolm/decryption/KeyLoader.ts
Normal file
111
src/matrix/e2ee/megolm/decryption/KeyLoader.ts
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
Copyright 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 {SessionCache} from "./SessionCache";
|
||||||
|
import {IRoomKey} from "./RoomKey";
|
||||||
|
|
||||||
|
export declare class OlmInboundGroupSession {
|
||||||
|
constructor();
|
||||||
|
free(): void;
|
||||||
|
pickle(key: string | Uint8Array): string;
|
||||||
|
unpickle(key: string | Uint8Array, pickle: string);
|
||||||
|
create(session_key: string): string;
|
||||||
|
import_session(session_key: string): string;
|
||||||
|
decrypt(message: string): object;
|
||||||
|
session_id(): string;
|
||||||
|
first_known_index(): number;
|
||||||
|
export_session(message_index: number): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Because Olm only has very limited memory available when compiled to wasm,
|
||||||
|
we limit the amount of sessions held in memory.
|
||||||
|
*/
|
||||||
|
export class KeyLoader {
|
||||||
|
|
||||||
|
public readonly cache: SessionCache;
|
||||||
|
private pickleKey: string;
|
||||||
|
private olm: any;
|
||||||
|
private resolveUnusedEntry?: () => void;
|
||||||
|
private entryBecomesUnusedPromise?: Promise<void>;
|
||||||
|
|
||||||
|
constructor(olm: any, pickleKey: string, limit: number) {
|
||||||
|
this.cache = new SessionCache(limit);
|
||||||
|
this.pickleKey = pickleKey;
|
||||||
|
this.olm = olm;
|
||||||
|
}
|
||||||
|
|
||||||
|
async useKey<T>(key: IRoomKey, callback: (session: OlmInboundGroupSession, pickleKey: string) => Promise<T> | T): Promise<T> {
|
||||||
|
const cacheEntry = await this.allocateEntry(key);
|
||||||
|
try {
|
||||||
|
const {session} = cacheEntry;
|
||||||
|
key.loadInto(session, this.pickleKey);
|
||||||
|
return await callback(session, this.pickleKey);
|
||||||
|
} finally {
|
||||||
|
this.freeEntry(cacheEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get running() {
|
||||||
|
return !!this.cache.find(entry => entry.inUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async allocateEntry(key: IRoomKey): Promise<CacheEntry> {
|
||||||
|
let entry;
|
||||||
|
if (this.cache.size >= this.cache.limit) {
|
||||||
|
while(!(entry = this.cache.find(entry => !entry.inUse))) {
|
||||||
|
await this.entryBecomesUnused();
|
||||||
|
}
|
||||||
|
entry.inUse = true;
|
||||||
|
entry.key = key;
|
||||||
|
} else {
|
||||||
|
const session: OlmInboundGroupSession = new this.olm.InboundGroupSession();
|
||||||
|
const entry = new CacheEntry(key, session);
|
||||||
|
this.cache.add(entry);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private freeEntry(entry: CacheEntry) {
|
||||||
|
entry.inUse = false;
|
||||||
|
if (this.resolveUnusedEntry) {
|
||||||
|
this.resolveUnusedEntry();
|
||||||
|
// promise is resolved now, we'll need a new one for next await so clear
|
||||||
|
this.entryBecomesUnusedPromise = this.resolveUnusedEntry = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private entryBecomesUnused(): Promise<void> {
|
||||||
|
if (!this.entryBecomesUnusedPromise) {
|
||||||
|
this.entryBecomesUnusedPromise = new Promise(resolve => {
|
||||||
|
this.resolveUnusedEntry = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.entryBecomesUnusedPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CacheEntry {
|
||||||
|
inUse: boolean;
|
||||||
|
session: OlmInboundGroupSession;
|
||||||
|
key: IRoomKey;
|
||||||
|
|
||||||
|
constructor(key, session) {
|
||||||
|
this.key = key;
|
||||||
|
this.session = session;
|
||||||
|
this.inUse = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,22 +14,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {InboundGroupSession} from "../../../storage/idb/stores/InboundGroupSessionStore";
|
import type {InboundGroupSessionEntry} from "../../../storage/idb/stores/InboundGroupSessionStore";
|
||||||
import type {Transaction} from "../../../storage/idb/Transaction";
|
import type {Transaction} from "../../../storage/idb/Transaction";
|
||||||
import type {DecryptionResult} from "../../DecryptionResult";
|
import type {DecryptionResult} from "../../DecryptionResult";
|
||||||
|
import type {KeyLoader, OlmInboundGroupSession} from "./KeyLoader";
|
||||||
declare class OlmInboundGroupSession {
|
import {SessionCache} from "./SessionCache";
|
||||||
constructor();
|
|
||||||
free(): void;
|
|
||||||
pickle(key: string | Uint8Array): string;
|
|
||||||
unpickle(key: string | Uint8Array, pickle: string);
|
|
||||||
create(session_key: string): string;
|
|
||||||
import_session(session_key: string): string;
|
|
||||||
decrypt(message: string): object;
|
|
||||||
session_id(): string;
|
|
||||||
first_known_index(): number;
|
|
||||||
export_session(message_index: number): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRoomKey {
|
export interface IRoomKey {
|
||||||
get roomId(): string;
|
get roomId(): string;
|
||||||
|
@ -37,24 +26,24 @@ export interface IRoomKey {
|
||||||
get sessionId(): string;
|
get sessionId(): string;
|
||||||
get claimedEd25519Key(): string;
|
get claimedEd25519Key(): string;
|
||||||
get eventIds(): string[] | undefined;
|
get eventIds(): string[] | undefined;
|
||||||
deserializeInto(session: OlmInboundGroupSession, pickleKey: string): void;
|
loadInto(session: OlmInboundGroupSession, pickleKey: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IIncomingRoomKey extends IRoomKey {
|
export interface IIncomingRoomKey extends IRoomKey {
|
||||||
get isBetter(): boolean | undefined;
|
get isBetter(): boolean | undefined;
|
||||||
checkIsBetterThanStorage(keyDeserialization: KeyDeserialization, txn: Transaction): Promise<boolean>;
|
checkBetterKeyInStorage(loader: KeyLoader, txn: Transaction): Promise<boolean>;
|
||||||
write(keyDeserialization: KeyDeserialization, txn: Transaction): Promise<boolean>;
|
write(loader: KeyLoader, txn: Transaction): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
private _eventIds?: string[];
|
private _eventIds?: string[];
|
||||||
private _isBetter?: boolean;
|
private _isBetter?: boolean;
|
||||||
|
|
||||||
checkBetterKeyInStorage(keyDeserialization: KeyDeserialization, txn: Transaction): Promise<boolean> {
|
checkBetterKeyInStorage(loader: KeyLoader, txn: Transaction): Promise<boolean> {
|
||||||
return this._checkBetterKeyInStorage(keyDeserialization, undefined, txn);
|
return this._checkBetterKeyInStorage(loader, undefined, txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
async write(keyDeserialization: KeyDeserialization, pickleKey: string, txn: Transaction): Promise<boolean> {
|
async write(loader: KeyLoader, txn: Transaction): Promise<boolean> {
|
||||||
// we checked already and we had a better session in storage, so don't write
|
// we checked already and we had a better session in storage, so don't write
|
||||||
let pickledSession;
|
let pickledSession;
|
||||||
if (this._isBetter === undefined) {
|
if (this._isBetter === undefined) {
|
||||||
|
@ -62,23 +51,23 @@ abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
// we haven't checked if this is the best key yet,
|
// we haven't checked if this is the best key yet,
|
||||||
// so do that now to not overwrite a better key.
|
// so do that now to not overwrite a better key.
|
||||||
// while we have the key deserialized, also pickle it to store it later on here.
|
// while we have the key deserialized, also pickle it to store it later on here.
|
||||||
await this._checkBetterKeyInStorage(keyDeserialization, session => {
|
await this._checkBetterKeyInStorage(loader, (session, pickleKey) => {
|
||||||
pickledSession = session.pickle(pickleKey);
|
pickledSession = session.pickle(pickleKey);
|
||||||
}, txn);
|
}, txn);
|
||||||
}
|
}
|
||||||
if (this._isBetter === false) {
|
if (this._isBetter === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// before calling write in parallel, we need to check keyDeserialization.running is false so we are sure our transaction will not be closed
|
// before calling write in parallel, we need to check loader.running is false so we are sure our transaction will not be closed
|
||||||
if (!pickledSession) {
|
if (!pickledSession) {
|
||||||
pickledSession = await keyDeserialization.useKey(this, session => session.pickle(pickleKey));
|
pickledSession = await loader.useKey(this, (session, pickleKey) => session.pickle(pickleKey));
|
||||||
}
|
}
|
||||||
const sessionEntry = {
|
const sessionEntry = {
|
||||||
roomId: this.roomId,
|
roomId: this.roomId,
|
||||||
senderKey: this.senderKey,
|
senderKey: this.senderKey,
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
session: pickledSession,
|
session: pickledSession,
|
||||||
claimedKeys: this._sessionInfo.claimedKeys,
|
claimedKeys: {"ed25519": this.claimedEd25519Key},
|
||||||
};
|
};
|
||||||
txn.inboundGroupSessions.set(sessionEntry);
|
txn.inboundGroupSessions.set(sessionEntry);
|
||||||
return true;
|
return true;
|
||||||
|
@ -87,11 +76,11 @@ abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
get eventIds() { return this._eventIds; }
|
get eventIds() { return this._eventIds; }
|
||||||
get isBetter() { return this._isBetter; }
|
get isBetter() { return this._isBetter; }
|
||||||
|
|
||||||
private async _checkBetterKeyInStorage(keyDeserialization: KeyDeserialization, callback?: (session: OlmInboundGroupSession) => void, txn: Transaction): Promise<boolean> {
|
private async _checkBetterKeyInStorage(loader: KeyLoader, callback: (((session: OlmInboundGroupSession, pickleKey: string) => void) | undefined), txn: Transaction): Promise<boolean> {
|
||||||
if (this._isBetter !== undefined) {
|
if (this._isBetter !== undefined) {
|
||||||
return this._isBetter;
|
return this._isBetter;
|
||||||
}
|
}
|
||||||
let existingKey = keyDeserialization.cache.get(this.roomId, this.senderKey, this.sessionId);
|
let existingKey = loader.cache.get(this.roomId, this.senderKey, this.sessionId);
|
||||||
if (!existingKey) {
|
if (!existingKey) {
|
||||||
const storageKey = await fromStorage(this.roomId, this.senderKey, this.sessionId, txn);
|
const storageKey = await fromStorage(this.roomId, this.senderKey, this.sessionId, txn);
|
||||||
// store the event ids that can be decrypted with this key
|
// store the event ids that can be decrypted with this key
|
||||||
|
@ -105,11 +94,11 @@ abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (existingKey) {
|
if (existingKey) {
|
||||||
this._isBetter = await keyDeserialization.useKey(key, newSession => {
|
this._isBetter = await loader.useKey(this, newSession => {
|
||||||
return keyDeserialization.useKey(existingKey, existingSession => {
|
return loader.useKey(existingKey, (existingSession, pickleKey) => {
|
||||||
const isBetter = newSession.first_known_index() < existingSession.first_known_index();
|
const isBetter = newSession.first_known_index() < existingSession.first_known_index();
|
||||||
if (isBetter && callback) {
|
if (isBetter && callback) {
|
||||||
callback(newSession);
|
callback(newSession, pickleKey);
|
||||||
}
|
}
|
||||||
return isBetter;
|
return isBetter;
|
||||||
});
|
});
|
||||||
|
@ -120,9 +109,15 @@ abstract class BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
}
|
}
|
||||||
return this._isBetter;
|
return this._isBetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract get roomId(): string;
|
||||||
|
abstract get senderKey(): string;
|
||||||
|
abstract get sessionId(): string;
|
||||||
|
abstract get claimedEd25519Key(): string;
|
||||||
|
abstract loadInto(session: OlmInboundGroupSession, pickleKey: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeviceMessageRoomKey extends BaseIncomingRoomKey implements IIncomingRoomKey {
|
class DeviceMessageRoomKey extends BaseIncomingRoomKey {
|
||||||
private _decryptionResult: DecryptionResult;
|
private _decryptionResult: DecryptionResult;
|
||||||
|
|
||||||
constructor(decryptionResult: DecryptionResult) {
|
constructor(decryptionResult: DecryptionResult) {
|
||||||
|
@ -135,13 +130,13 @@ class DeviceMessageRoomKey extends BaseIncomingRoomKey implements IIncomingRoomK
|
||||||
get sessionId() { return this._decryptionResult.event.content?.["session_id"]; }
|
get sessionId() { return this._decryptionResult.event.content?.["session_id"]; }
|
||||||
get claimedEd25519Key() { return this._decryptionResult.claimedEd25519Key; }
|
get claimedEd25519Key() { return this._decryptionResult.claimedEd25519Key; }
|
||||||
|
|
||||||
deserializeInto(session) {
|
loadInto(session) {
|
||||||
const sessionKey = this._decryptionResult.event.content?.["session_key"];
|
const sessionKey = this._decryptionResult.event.content?.["session_key"];
|
||||||
session.create(sessionKey);
|
session.create(sessionKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BackupRoomKey extends BaseIncomingRoomKey implements IIncomingRoomKey {
|
class BackupRoomKey extends BaseIncomingRoomKey {
|
||||||
private _roomId: string;
|
private _roomId: string;
|
||||||
private _sessionId: string;
|
private _sessionId: string;
|
||||||
private _backupInfo: string;
|
private _backupInfo: string;
|
||||||
|
@ -158,16 +153,16 @@ class BackupRoomKey extends BaseIncomingRoomKey implements IIncomingRoomKey {
|
||||||
get sessionId() { return this._sessionId; }
|
get sessionId() { return this._sessionId; }
|
||||||
get claimedEd25519Key() { return this._backupInfo["sender_claimed_keys"]?.["ed25519"]; }
|
get claimedEd25519Key() { return this._backupInfo["sender_claimed_keys"]?.["ed25519"]; }
|
||||||
|
|
||||||
deserializeInto(session) {
|
loadInto(session) {
|
||||||
const sessionKey = this._backupInfo["session_key"];
|
const sessionKey = this._backupInfo["session_key"];
|
||||||
session.import_session(sessionKey);
|
session.import_session(sessionKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StoredRoomKey implements IRoomKey {
|
class StoredRoomKey implements IRoomKey {
|
||||||
private storageEntry: InboundGroupSession;
|
private storageEntry: InboundGroupSessionEntry;
|
||||||
|
|
||||||
constructor(storageEntry: InboundGroupSession) {
|
constructor(storageEntry: InboundGroupSessionEntry) {
|
||||||
this.storageEntry = storageEntry;
|
this.storageEntry = storageEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +172,7 @@ class StoredRoomKey implements IRoomKey {
|
||||||
get claimedEd25519Key() { return this.storageEntry.claimedKeys!["ed25519"]; }
|
get claimedEd25519Key() { return this.storageEntry.claimedKeys!["ed25519"]; }
|
||||||
get eventIds() { return this.storageEntry.eventIds; }
|
get eventIds() { return this.storageEntry.eventIds; }
|
||||||
|
|
||||||
deserializeInto(session, pickleKey) {
|
loadInto(session, pickleKey) {
|
||||||
session.unpickle(pickleKey, this.storageEntry.session);
|
session.unpickle(pickleKey, this.storageEntry.session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,17 +184,16 @@ class StoredRoomKey implements IRoomKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fromDeviceMessage(dr) {
|
export function fromDeviceMessage(dr: DecryptionResult): DeviceMessageRoomKey | undefined {
|
||||||
const roomId = dr.event.content?.["room_id"];
|
|
||||||
const sessionId = dr.event.content?.["session_id"];
|
|
||||||
const sessionKey = dr.event.content?.["session_key"];
|
const sessionKey = dr.event.content?.["session_key"];
|
||||||
|
const key = new DeviceMessageRoomKey(dr);
|
||||||
if (
|
if (
|
||||||
typeof roomId === "string" ||
|
typeof key.roomId === "string" &&
|
||||||
typeof sessionId === "string" ||
|
typeof key.sessionId === "string" &&
|
||||||
typeof senderKey === "string" ||
|
typeof key.senderKey === "string" &&
|
||||||
typeof sessionKey === "string"
|
typeof sessionKey === "string"
|
||||||
) {
|
) {
|
||||||
return new DeviceMessageRoomKey(dr);
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,11 +205,11 @@ sessionInfo is a response from key backup and has the following keys:
|
||||||
sender_key
|
sender_key
|
||||||
session_key
|
session_key
|
||||||
*/
|
*/
|
||||||
export function fromBackup(roomId, sessionId, sessionInfo) {
|
export function fromBackup(roomId, sessionId, backupInfo): BackupRoomKey | undefined {
|
||||||
const sessionKey = sessionInfo["session_key"];
|
const sessionKey = backupInfo["session_key"];
|
||||||
const senderKey = sessionInfo["sender_key"];
|
const senderKey = backupInfo["sender_key"];
|
||||||
// TODO: can we just trust this?
|
// TODO: can we just trust this?
|
||||||
const claimedEd25519Key = sessionInfo["sender_claimed_keys"]?.["ed25519"];
|
const claimedEd25519Key = backupInfo["sender_claimed_keys"]?.["ed25519"];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof roomId === "string" &&
|
typeof roomId === "string" &&
|
||||||
|
@ -224,7 +218,7 @@ export function fromBackup(roomId, sessionId, sessionInfo) {
|
||||||
typeof sessionKey === "string" &&
|
typeof sessionKey === "string" &&
|
||||||
typeof claimedEd25519Key === "string"
|
typeof claimedEd25519Key === "string"
|
||||||
) {
|
) {
|
||||||
return new BackupRoomKey(roomId, sessionId, sessionInfo);
|
return new BackupRoomKey(roomId, sessionId, backupInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,82 +229,3 @@ export async function fromStorage(roomId: string, senderKey: string, sessionId:
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
Because Olm only has very limited memory available when compiled to wasm,
|
|
||||||
we limit the amount of sessions held in memory.
|
|
||||||
*/
|
|
||||||
class KeyDeserialization {
|
|
||||||
|
|
||||||
public readonly cache: SessionCache;
|
|
||||||
private pickleKey: string;
|
|
||||||
private olm: any;
|
|
||||||
private resolveUnusedEntry?: () => void;
|
|
||||||
private entryBecomesUnusedPromise?: Promise<void>;
|
|
||||||
|
|
||||||
constructor({olm, pickleKey, limit}) {
|
|
||||||
this.cache = new SessionCache(limit);
|
|
||||||
this.pickleKey = pickleKey;
|
|
||||||
this.olm = olm;
|
|
||||||
}
|
|
||||||
|
|
||||||
async useKey<T>(key: IRoomKey, callback: (session: OlmInboundGroupSession) => Promise<T> | T): Promise<T> {
|
|
||||||
const cacheEntry = await this.allocateEntry(key);
|
|
||||||
try {
|
|
||||||
const {session} = cacheEntry;
|
|
||||||
key.deserializeInto(session, this.pickleKey);
|
|
||||||
return await callback(session);
|
|
||||||
} finally {
|
|
||||||
this.freeEntry(cacheEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get running() {
|
|
||||||
return !!this.cache.find(entry => entry.inUse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async allocateEntry(key): CacheEntry {
|
|
||||||
let entry;
|
|
||||||
if (this.cache.size >= MAX) {
|
|
||||||
while(!(entry = this.cache.find(entry => !entry.inUse))) {
|
|
||||||
await this.entryBecomesUnused();
|
|
||||||
}
|
|
||||||
entry.inUse = true;
|
|
||||||
entry.key = key;
|
|
||||||
} else {
|
|
||||||
const session: OlmInboundGroupSession = new this.olm.InboundGroupSession();
|
|
||||||
const entry = new CacheEntry(key, session);
|
|
||||||
this.cache.add(entry);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
private freeEntry(entry) {
|
|
||||||
entry.inUse = false;
|
|
||||||
if (this.resolveUnusedEntry) {
|
|
||||||
this.resolveUnusedEntry();
|
|
||||||
// promise is resolved now, we'll need a new one for next await so clear
|
|
||||||
this.entryBecomesUnusedPromise = this.resolveUnusedEntry = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private entryBecomesUnused(): Promise<void> {
|
|
||||||
if (!this.entryBecomesUnusedPromise) {
|
|
||||||
this.entryBecomesUnusedPromise = new Promise(resolve => {
|
|
||||||
this.resolveUnusedEntry = resolve;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this.entryBecomesUnusedPromise;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CacheEntry {
|
|
||||||
inUse: boolean;
|
|
||||||
session: OlmInboundGroupSession;
|
|
||||||
key: IRoomKey;
|
|
||||||
|
|
||||||
constructor(key, session) {
|
|
||||||
this.key = key;
|
|
||||||
this.session = session;
|
|
||||||
this.inUse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,24 +17,26 @@ limitations under the License.
|
||||||
import {MIN_UNICODE, MAX_UNICODE} from "./common";
|
import {MIN_UNICODE, MAX_UNICODE} from "./common";
|
||||||
import {Store} from "../Store";
|
import {Store} from "../Store";
|
||||||
|
|
||||||
export interface InboundGroupSession {
|
export interface InboundGroupSessionEntry {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
senderKey: string;
|
senderKey: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
session?: string;
|
session?: string;
|
||||||
claimedKeys?: { [algorithm : string] : string };
|
claimedKeys?: { [algorithm : string] : string };
|
||||||
eventIds?: string[];
|
eventIds?: string[];
|
||||||
key: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InboundGroupSessionStorageEntry = InboundGroupSessionEntry & { key: string };
|
||||||
|
|
||||||
|
|
||||||
function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
|
function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
|
||||||
return `${roomId}|${senderKey}|${sessionId}`;
|
return `${roomId}|${senderKey}|${sessionId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InboundGroupSessionStore {
|
export class InboundGroupSessionStore {
|
||||||
private _store: Store<InboundGroupSession>;
|
private _store: Store<InboundGroupSessionStorageEntry>;
|
||||||
|
|
||||||
constructor(store: Store<InboundGroupSession>) {
|
constructor(store: Store<InboundGroupSessionStorageEntry>) {
|
||||||
this._store = store;
|
this._store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,13 +46,14 @@ export class InboundGroupSessionStore {
|
||||||
return key === fetchedKey;
|
return key === fetchedKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(roomId: string, senderKey: string, sessionId: string): Promise<InboundGroupSession | null> {
|
get(roomId: string, senderKey: string, sessionId: string): Promise<InboundGroupSessionEntry | null> {
|
||||||
return this._store.get(encodeKey(roomId, senderKey, sessionId));
|
return this._store.get(encodeKey(roomId, senderKey, sessionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
set(session: InboundGroupSession): void {
|
set(session: InboundGroupSessionEntry): void {
|
||||||
session.key = encodeKey(session.roomId, session.senderKey, session.sessionId);
|
const storageEntry = session as InboundGroupSessionStorageEntry;
|
||||||
this._store.put(session);
|
storageEntry.key = encodeKey(session.roomId, session.senderKey, session.sessionId);
|
||||||
|
this._store.put(storageEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllForRoom(roomId: string) {
|
removeAllForRoom(roomId: string) {
|
||||||
|
|
|
@ -24,6 +24,9 @@ export class BaseLRUCache {
|
||||||
this._entries = [];
|
this._entries = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get size() { return this._entries.length; }
|
||||||
|
get limit() { return this._limit; }
|
||||||
|
|
||||||
_get(findEntryFn) {
|
_get(findEntryFn) {
|
||||||
const idx = this._entries.findIndex(findEntryFn);
|
const idx = this._entries.findIndex(findEntryFn);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
|
|
Loading…
Reference in a new issue