diff --git a/src/crypto/store/memory-crypto-store.ts b/src/crypto/store/memory-crypto-store.ts index de3dc3ada..32d83f24d 100644 --- a/src/crypto/store/memory-crypto-store.ts +++ b/src/crypto/store/memory-crypto-store.ts @@ -37,6 +37,17 @@ import { IOlmDevice } from "../algorithms/megolm"; import { IRoomEncryption } from "../RoomList"; import { InboundGroupSessionData } from "../OlmDevice"; +function encodeSessionKey(senderCurve25519Key: string, sessionId: string): string { + return encodeURIComponent(senderCurve25519Key) + "/" + encodeURIComponent(sessionId); +} + +function decodeSessionKey(key: string): { senderKey: string; sessionId: string } { + const keyParts = key.split("/"); + const senderKey = decodeURIComponent(keyParts[0]); + const sessionId = decodeURIComponent(keyParts[1]); + return { senderKey, sessionId }; +} + /** * Internal module. in-memory storage for e2e. */ @@ -481,20 +492,14 @@ export class MemoryCryptoStore implements CryptoStore { txn: unknown, func: (groupSession: InboundGroupSessionData | null, groupSessionWithheld: IWithheld | null) => void, ): void { - const k = senderCurve25519Key + "/" + sessionId; + const k = encodeSessionKey(senderCurve25519Key, sessionId); func(this.inboundGroupSessions[k] || null, this.inboundGroupSessionsWithheld[k] || null); } public getAllEndToEndInboundGroupSessions(txn: unknown, func: (session: ISession | null) => void): void { for (const key of Object.keys(this.inboundGroupSessions)) { - // we can't use split, as the components we are trying to split out - // might themselves contain '/' characters. We rely on the - // senderKey being a (32-byte) curve25519 key, base64-encoded - // (hence 43 characters long). - func({ - senderKey: key.slice(0, 43), - sessionId: key.slice(44), + ...decodeSessionKey(key), sessionData: this.inboundGroupSessions[key], }); } @@ -507,7 +512,7 @@ export class MemoryCryptoStore implements CryptoStore { sessionData: InboundGroupSessionData, txn: unknown, ): void { - const k = senderCurve25519Key + "/" + sessionId; + const k = encodeSessionKey(senderCurve25519Key, sessionId); if (this.inboundGroupSessions[k] === undefined) { this.inboundGroupSessions[k] = sessionData; } @@ -519,7 +524,8 @@ export class MemoryCryptoStore implements CryptoStore { sessionData: InboundGroupSessionData, txn: unknown, ): void { - this.inboundGroupSessions[senderCurve25519Key + "/" + sessionId] = sessionData; + const k = encodeSessionKey(senderCurve25519Key, sessionId); + this.inboundGroupSessions[k] = sessionData; } public storeEndToEndInboundGroupSessionWithheld( @@ -528,7 +534,7 @@ export class MemoryCryptoStore implements CryptoStore { sessionData: IWithheld, txn: unknown, ): void { - const k = senderCurve25519Key + "/" + sessionId; + const k = encodeSessionKey(senderCurve25519Key, sessionId); this.inboundGroupSessionsWithheld[k] = sessionData; } @@ -554,8 +560,7 @@ export class MemoryCryptoStore implements CryptoStore { const result: SessionExtended[] = []; for (const [key, session] of Object.entries(this.inboundGroupSessions)) { result.push({ - senderKey: key.slice(0, 43), - sessionId: key.slice(44), + ...decodeSessionKey(key), sessionData: session, needsBackup: key in this.sessionsNeedingBackup, }); @@ -584,7 +589,7 @@ export class MemoryCryptoStore implements CryptoStore { sessions: { senderKey: string; sessionId: string }[], ): Promise { for (const { senderKey, sessionId } of sessions) { - const k = senderKey + "/" + sessionId; + const k = encodeSessionKey(senderKey, sessionId); delete this.inboundGroupSessions[k]; } } @@ -614,8 +619,7 @@ export class MemoryCryptoStore implements CryptoStore { for (const session in this.sessionsNeedingBackup) { if (this.inboundGroupSessions[session]) { sessions.push({ - senderKey: session.slice(0, 43), - sessionId: session.slice(44), + ...decodeSessionKey(session), sessionData: this.inboundGroupSessions[session], }); if (limit && session.length >= limit) { @@ -632,7 +636,7 @@ export class MemoryCryptoStore implements CryptoStore { public unmarkSessionsNeedingBackup(sessions: ISession[]): Promise { for (const session of sessions) { - const sessionKey = session.senderKey + "/" + session.sessionId; + const sessionKey = encodeSessionKey(session.senderKey, session.sessionId); delete this.sessionsNeedingBackup[sessionKey]; } return Promise.resolve(); @@ -640,7 +644,7 @@ export class MemoryCryptoStore implements CryptoStore { public markSessionsNeedingBackup(sessions: ISession[]): Promise { for (const session of sessions) { - const sessionKey = session.senderKey + "/" + session.sessionId; + const sessionKey = encodeSessionKey(session.senderKey, session.sessionId); this.sessionsNeedingBackup[sessionKey] = true; } return Promise.resolve();