mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Secure migration of legacy R2 settings from LocalStorage
- Modified `loadLegacyR2Settings` to check `localStorage` if IndexedDB is empty. - Implemented immediate migration of settings from `localStorage` to IndexedDB upon access. - Added logic to clear `localStorage` after successful migration to prevent secret exposure. - Verified fix with reproduction script and regression tests. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
84e7f50f96
commit
7bf360b2ee
1 file changed
+40
-3
@@ -101,7 +101,7 @@ export async function loadLegacyR2Settings() {
|
||||
try {
|
||||
const db = await openSettingsDb();
|
||||
if (db) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const fromDb = await new Promise((resolve, reject) => {
|
||||
const tx = db.transaction(STORE_NAME, "readonly");
|
||||
const store = tx.objectStore(STORE_NAME);
|
||||
const req = store.get(SETTINGS_KEY);
|
||||
@@ -109,9 +109,16 @@ export async function loadLegacyR2Settings() {
|
||||
resolve(normalizeSettings(req.result));
|
||||
};
|
||||
req.onerror = () => {
|
||||
reject(req.error || new Error("Failed to load settings"));
|
||||
// If read fails, resolve null to try fallback
|
||||
resolve(null);
|
||||
};
|
||||
});
|
||||
|
||||
// If we have valid settings from DB, return them.
|
||||
// We check for accountId as a signal that settings are present.
|
||||
if (fromDb && fromDb.accountId) {
|
||||
return fromDb;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
userLogger.warn("Failed to open IndexedDB for settings, falling back:", err);
|
||||
@@ -121,7 +128,37 @@ export async function loadLegacyR2Settings() {
|
||||
if (typeof localStorage !== "undefined") {
|
||||
const raw = localStorage.getItem(LOCALSTORAGE_FALLBACK_KEY);
|
||||
if (raw) {
|
||||
return normalizeSettings(JSON.parse(raw));
|
||||
const parsed = JSON.parse(raw);
|
||||
const settings = normalizeSettings(parsed);
|
||||
|
||||
// Security Fix: Move secrets from insecure LocalStorage to IndexedDB immediately
|
||||
try {
|
||||
const db = await openSettingsDb();
|
||||
if (db) {
|
||||
await new Promise((resolve, reject) => {
|
||||
const tx = db.transaction(STORE_NAME, "readwrite");
|
||||
const store = tx.objectStore(STORE_NAME);
|
||||
// Store the raw parsed object, not normalized, to preserve original structure
|
||||
// though normalizeSettings handles it fine either way.
|
||||
const req = store.put(parsed, SETTINGS_KEY);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => reject(req.error);
|
||||
});
|
||||
localStorage.removeItem(LOCALSTORAGE_FALLBACK_KEY);
|
||||
userLogger.info(
|
||||
"Migrated legacy R2 settings from LocalStorage to IndexedDB"
|
||||
);
|
||||
}
|
||||
} catch (migrationErr) {
|
||||
userLogger.warn(
|
||||
"Failed to migrate legacy settings to IndexedDB:",
|
||||
migrationErr
|
||||
);
|
||||
// If migration fails, we still return settings to avoid data loss,
|
||||
// but the vulnerability remains until next successful load.
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
Reference in new issue
Block a user