Skip to content

Commit

Permalink
Fix possible race condition in read/write of retained encryption key
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaw3d committed Feb 1, 2025
1 parent 65616b7 commit 330eb29
Showing 1 changed file with 23 additions and 18 deletions.
41 changes: 23 additions & 18 deletions src/app/state/persist/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,30 @@ function* encryptAndPersistState(action: AnyAction) {
}

function* retainEncryptionKeyBetweenPopupReopenings() {
if (runtimeIs !== 'extension') return
yield* fork(function* () {
if (runtimeIs !== 'extension') return

// Read before rewriting.
const encryptedState = window.localStorage.getItem(
STORAGE_FIELD,
) as EncryptedString<PersistedRootState> | null
if (encryptedState) {
try {
const stringifiedEncryptionKey = yield* call(readSharedExtMemory)
if (!stringifiedEncryptionKey) throw new Error('skip')
if (stringifiedEncryptionKey === 'skipped') throw new Error('skip')
const keyWithSalt: KeyWithSalt = fromBase64andParse(stringifiedEncryptionKey)
const persistedRootState = yield* call(
decryptWithKey<PersistedRootState>,
keyWithSalt,
encryptedState,
)
yield* put(persistActions.setUnlockedRootState({ persistedRootState, stringifiedEncryptionKey }))
} catch (error) {
// Ignore
}
}

const channelQueue = yield* actionChannel<AnyAction>('*')
let previousStringifiedEncryptionKey: PersistState['stringifiedEncryptionKey'] = undefined
while (true) {
Expand All @@ -233,23 +255,6 @@ function* retainEncryptionKeyBetweenPopupReopenings() {
}
}
})

yield* fork(function* () {
const encryptedState = window.localStorage.getItem(
STORAGE_FIELD,
) as EncryptedString<PersistedRootState> | null
if (!encryptedState) return // Ignore
try {
const stringifiedEncryptionKey = yield* call(readSharedExtMemory)
if (!stringifiedEncryptionKey) return // Ignore
if (stringifiedEncryptionKey === 'skipped') return // Ignore
const keyWithSalt: KeyWithSalt = fromBase64andParse(stringifiedEncryptionKey)
const persistedRootState = yield* call(decryptWithKey<PersistedRootState>, keyWithSalt, encryptedState)
yield* put(persistActions.setUnlockedRootState({ persistedRootState, stringifiedEncryptionKey }))
} catch (error) {
// Ignore
}
})
}

async function writeSharedExtMemory(stringifiedEncryptionKey: PersistState['stringifiedEncryptionKey']) {
Expand Down

0 comments on commit 330eb29

Please sign in to comment.