import type { StorageProvider, IdentityKeyPair, SignedPreKey, OneTimePreKey, SessionState, RetiredIdentity } from '@shade/core'; import { constantTimeEqual } from '@shade/core'; /** * In-memory StorageProvider for testing and embedded use. * All data is lost when the instance is garbage collected. */ export class MemoryStorage implements StorageProvider { private identityKeyPair: IdentityKeyPair | null = null; private registrationId: number = 0; private signedPreKeys = new Map(); private oneTimePreKeys = new Map(); private sessions = new Map(); private trustedIdentities = new Map(); private retiredIdentities: RetiredIdentity[] = []; // ─── Identity ────────────────────────────────────────────── async getIdentityKeyPair(): Promise { return this.identityKeyPair; } async saveIdentityKeyPair(keyPair: IdentityKeyPair): Promise { this.identityKeyPair = keyPair; } async getLocalRegistrationId(): Promise { return this.registrationId; } async saveLocalRegistrationId(id: number): Promise { this.registrationId = id; } // ─── Signed Pre-Keys ────────────────────────────────────── async getSignedPreKey(keyId: number): Promise { return this.signedPreKeys.get(keyId) ?? null; } async saveSignedPreKey(key: SignedPreKey): Promise { this.signedPreKeys.set(key.keyId, key); } async removeSignedPreKey(keyId: number): Promise { this.signedPreKeys.delete(keyId); } // ─── One-Time Pre-Keys ──────────────────────────────────── async getOneTimePreKey(keyId: number): Promise { return this.oneTimePreKeys.get(keyId) ?? null; } async saveOneTimePreKey(key: OneTimePreKey): Promise { this.oneTimePreKeys.set(key.keyId, key); } async removeOneTimePreKey(keyId: number): Promise { this.oneTimePreKeys.delete(keyId); } async getOneTimePreKeyCount(): Promise { return this.oneTimePreKeys.size; } // ─── Sessions ───────────────────────────────────────────── async getSession(address: string): Promise { return this.sessions.get(address) ?? null; } async saveSession(address: string, state: SessionState): Promise { this.sessions.set(address, state); } async removeSession(address: string): Promise { this.sessions.delete(address); } // ─── Trust ──────────────────────────────────────────────── async isTrustedIdentity(address: string, identityKey: Uint8Array): Promise { const stored = this.trustedIdentities.get(address); if (!stored) return true; // TOFU: trust on first use return constantTimeEqual(stored, identityKey); } async saveTrustedIdentity(address: string, identityKey: Uint8Array): Promise { this.trustedIdentities.set(address, identityKey); } // ─── Identity History ───────────────────────────────────── async addRetiredIdentity(identity: RetiredIdentity): Promise { this.retiredIdentities.push(identity); } async getRetiredIdentities(): Promise { return [...this.retiredIdentities]; } async pruneRetiredIdentities(olderThan: number): Promise { this.retiredIdentities = this.retiredIdentities.filter((r) => r.retiredAt >= olderThan); } }