fix: cross-browser sync import corrupting local encryption + v2.0.9
Root cause: when importing an encrypted sync code from another device, _decryptFromSync was replacing the local encryption config (salt) with the source device's salt. This caused: 1. Local key cache derived from wrong salt 2. Local data (encrypted with local salt) became unreadable 3. _applyData tried to write with the wrong key Fixed with a complete refactor of cross-device decryption: - authenticateForSync() derives a TEMPORARY key using the source salt - Temporary key stored separately as 'tempSyncKey' in IndexedDB - Local encryption config and cached key are NEVER modified - After decryption, _applyData writes via _writeSecure using the LOCAL key (which uses the local salt) - _handleDecryptedMeta extracted for code reuse Also: - Options.js auth handler detects pending sync import and routes to authenticateForSync instead of regular authenticate - After auth success, automatically retries the import - README updated: imported passwords are protected (dots in UI, vault password to reveal, AES-256 encrypted at rest) - Bumped to v2.0.9 https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
This commit is contained in:
+14
-9
@@ -1016,24 +1016,29 @@ async function initSyncEncryptionUI() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is re-verification (key exists) or first-device (needs full auth)
|
||||
const cached = await SilentSendCrypto.getCachedKey();
|
||||
let result;
|
||||
if (cached) {
|
||||
// Re-verification — password alone is enough
|
||||
result = await SilentSendSync.reverifyWithPassword(password);
|
||||
|
||||
// If there's a pending sync import, use authenticateForSync
|
||||
// (derives a temporary key with the source salt, doesn't touch local config)
|
||||
if (window.__ssPendingSyncImport) {
|
||||
result = await SilentSendSync.authenticateForSync(password);
|
||||
} else {
|
||||
// First device — full auth with password + TOTP if configured
|
||||
result = await SilentSendSync.authenticate(password, totpCode || undefined);
|
||||
// Normal auth: check if re-verification or first-device
|
||||
const cached = await SilentSendCrypto.getCachedKey();
|
||||
if (cached) {
|
||||
result = await SilentSendSync.reverifyWithPassword(password);
|
||||
} else {
|
||||
result = await SilentSendSync.authenticate(password, totpCode || undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
$('#syncAuthPrompt').style.display = 'none';
|
||||
$('#syncAuthPassword').value = '';
|
||||
$('#syncAuthTOTPForPassword').value = '';
|
||||
setSyncEncStatus(cached ? 'Re-verified with password.' : 'Authenticated. Sync data unlocked.', 'ok');
|
||||
setSyncEncStatus('Authenticated.', 'ok');
|
||||
|
||||
// If there's a pending sync import, retry it now that auth succeeded
|
||||
// If there's a pending sync import, retry it now
|
||||
if (window.__ssPendingSyncImport) {
|
||||
const retry = window.__ssPendingSyncImport;
|
||||
window.__ssPendingSyncImport = null;
|
||||
|
||||
Reference in New Issue
Block a user