fix: account isolation, auto-import signer certs, and no-key error handling #35

This commit is contained in:
Linus Rath
2026-03-28 17:32:06 +01:00
parent 6e0c79ca2c
commit c7c22bd210
18 changed files with 240 additions and 45 deletions
+26 -9
View File
@@ -1,22 +1,35 @@
import type { SmimeKeyRecord, SmimePublicCert } from './types';
const DB_NAME = 'smime-store';
const DB_VERSION = 1;
const DB_VERSION = 2;
const KEY_RECORDS_STORE = 'key-records';
const PUBLIC_CERTS_STORE = 'public-certs';
function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = () => {
request.onupgradeneeded = (event) => {
const db = request.result;
if (!db.objectStoreNames.contains(KEY_RECORDS_STORE)) {
const oldVersion = event.oldVersion;
if (oldVersion < 1) {
const keyStore = db.createObjectStore(KEY_RECORDS_STORE, { keyPath: 'id' });
keyStore.createIndex('email', 'email', { unique: false });
}
if (!db.objectStoreNames.contains(PUBLIC_CERTS_STORE)) {
keyStore.createIndex('accountId', 'accountId', { unique: false });
const certStore = db.createObjectStore(PUBLIC_CERTS_STORE, { keyPath: 'id' });
certStore.createIndex('email', 'email', { unique: false });
certStore.createIndex('accountId', 'accountId', { unique: false });
}
if (oldVersion >= 1 && oldVersion < 2) {
// Add accountId index to existing stores
const tx = request.transaction!;
const keyStore = tx.objectStore(KEY_RECORDS_STORE);
if (!keyStore.indexNames.contains('accountId')) {
keyStore.createIndex('accountId', 'accountId', { unique: false });
}
const certStore = tx.objectStore(PUBLIC_CERTS_STORE);
if (!certStore.indexNames.contains('accountId')) {
certStore.createIndex('accountId', 'accountId', { unique: false });
}
}
};
request.onsuccess = () => resolve(request.result);
@@ -62,9 +75,11 @@ export async function getKeyRecordForEmail(email: string): Promise<SmimeKeyRecor
});
}
export async function listKeyRecords(): Promise<SmimeKeyRecord[]> {
export async function listKeyRecords(accountId?: string): Promise<SmimeKeyRecord[]> {
const db = await openDB();
return txPromise(db, KEY_RECORDS_STORE, 'readonly', (s) => s.getAll());
const all = await txPromise<SmimeKeyRecord[]>(db, KEY_RECORDS_STORE, 'readonly', (s) => s.getAll());
if (!accountId) return all;
return all.filter((r) => r.accountId === accountId || !r.accountId);
}
export async function deleteKeyRecord(id: string): Promise<void> {
@@ -90,9 +105,11 @@ export async function getPublicCertForEmail(email: string): Promise<SmimePublicC
});
}
export async function listPublicCerts(): Promise<SmimePublicCert[]> {
export async function listPublicCerts(accountId?: string): Promise<SmimePublicCert[]> {
const db = await openDB();
return txPromise(db, PUBLIC_CERTS_STORE, 'readonly', (s) => s.getAll());
const all = await txPromise<SmimePublicCert[]>(db, PUBLIC_CERTS_STORE, 'readonly', (s) => s.getAll());
if (!accountId) return all;
return all.filter((c) => c.accountId === accountId || !c.accountId);
}
export async function deletePublicCert(id: string): Promise<void> {