fix(security): harden auth and request limits

This commit is contained in:
shuaiplus
2026-07-05 23:43:49 +08:00
parent 12af18e3a3
commit d9a36fefe6
12 changed files with 315 additions and 30 deletions
+9 -7
View File
@@ -94,6 +94,14 @@ export function loadSession(): SessionState | null {
const raw = localStorage.getItem(SESSION_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw) as Partial<SessionState> & Partial<PersistedSessionState>;
if (parsed.email && (parsed.accessToken || parsed.refreshToken)) {
const authMode = parsed.authMode === 'web-cookie' ? 'web-cookie' : 'token';
saveSession({ email: parsed.email, authMode });
return {
email: parsed.email,
authMode,
};
}
if (parsed.authMode === 'web-cookie' && parsed.email) {
return {
email: parsed.email,
@@ -106,13 +114,7 @@ export function loadSession(): SessionState | null {
authMode: 'token',
};
}
if (!parsed.accessToken || !parsed.refreshToken || !parsed.email) return null;
return {
accessToken: parsed.accessToken,
refreshToken: parsed.refreshToken,
email: parsed.email,
authMode: 'token',
};
return null;
} catch {
return null;
}
+24 -2
View File
@@ -19,6 +19,28 @@ const VAULT_CORE_STORE = 'vault-core';
let dbPromise: Promise<IDBDatabase | null> | null = null;
function stripDecryptedCacheFields<T>(value: T): T {
if (Array.isArray(value)) {
return value.map((item) => stripDecryptedCacheFields(item)) as T;
}
if (!value || typeof value !== 'object') return value;
const source = value as Record<string, unknown>;
const out: Record<string, unknown> = {};
for (const [key, item] of Object.entries(source)) {
if (/^dec[A-Z]/.test(key) || key === 'shareUrl') continue;
out[key] = stripDecryptedCacheFields(item);
}
return out as T;
}
function sanitizeSnapshotForCache(snapshot: VaultCoreSnapshot): VaultCoreSnapshot {
return {
ciphers: stripDecryptedCacheFields(Array.isArray(snapshot.ciphers) ? snapshot.ciphers : []),
folders: stripDecryptedCacheFields(Array.isArray(snapshot.folders) ? snapshot.folders : []),
sends: stripDecryptedCacheFields(Array.isArray(snapshot.sends) ? snapshot.sends : []),
};
}
function supportsIndexedDb(): boolean {
return typeof indexedDB !== 'undefined';
}
@@ -72,7 +94,7 @@ export async function loadCachedVaultCoreSnapshot(cacheKey: string): Promise<Vau
const request = store.get(normalized);
request.onsuccess = () => {
const record = request.result as VaultCoreCacheRecord | undefined;
resolve(record || null);
resolve(record ? { ...record, snapshot: sanitizeSnapshotForCache(record.snapshot) } : null);
};
request.onerror = () => resolve(null);
}));
@@ -90,7 +112,7 @@ export async function saveCachedVaultCoreSnapshot(
cacheKey: normalized,
revisionStamp,
savedAt: Date.now(),
snapshot,
snapshot: sanitizeSnapshotForCache(snapshot),
};
const request = store.put(record);
request.onsuccess = () => resolve();