Skip to content

Commit

Permalink
fix vault key changes not seen by all instances of useVault
Browse files Browse the repository at this point in the history
  • Loading branch information
huumn committed Nov 5, 2024
1 parent 7efd089 commit f0a5bc4
Showing 1 changed file with 31 additions and 27 deletions.
58 changes: 31 additions & 27 deletions components/vault/use-vault-configurator.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useMutation, useQuery } from '@apollo/client'
import { useMutation, useQuery, makeVar, useReactiveVar } from '@apollo/client'
import { useMe } from '../me'
import { useToast } from '../toast'
import useIndexedDB, { getDbName } from '../use-indexeddb'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo } from 'react'
import { E_VAULT_KEY_EXISTS } from '@/lib/error'
import { CLEAR_VAULT, GET_VAULT_ENTRIES, UPDATE_VAULT_KEY } from '@/fragments/vault'
import { toHex } from '@/lib/hex'
Expand All @@ -18,57 +18,61 @@ const useImperativeQuery = (query) => {
return imperativelyCallQuery
}

// reactive variable to store the vault key shared by all vaults
// so all vaults can react to changes in the vault key
// an alternative is to create a vault context which may be more idiomatic(?)
const keyReactiveVar = makeVar(null)

export function useVaultConfigurator ({ onVaultKeySet, beforeDisconnectVault } = {}) {
const { me } = useMe()
const toaster = useToast()
const idbConfig = useMemo(() => ({ dbName: getDbName(me?.id, 'vault'), storeName: 'vault', options: {} }), [me?.id])
const { set, get, remove } = useIndexedDB(idbConfig)
const [updateVaultKey] = useMutation(UPDATE_VAULT_KEY)
const getVaultEntries = useImperativeQuery(GET_VAULT_ENTRIES)
const [key, setKey] = useState(null)
const [keyHash, setKeyHash] = useState(null)
const key = useReactiveVar(keyReactiveVar)

const disconnectVault = useCallback(async () => {
console.log('disconnecting vault')
beforeDisconnectVault?.()
await remove('key')
keyReactiveVar(null)
}, [remove, keyReactiveVar])

useEffect(() => {
if (!me) return

(async () => {
try {
let localVaultKey = await get('key')
const localKeyHash = me?.privates?.vaultKeyHash || keyHash
if (localVaultKey?.hash && localVaultKey?.hash !== localKeyHash) {
// If the hash stored in the server does not match the hash of the local key,
// we can tell that the key is outdated (reset by another device or other reasons)
// in this case we clear the local key and let the user re-enter the passphrase
console.log('vault key hash mismatch, clearing local key', localVaultKey?.hash, '!=', localKeyHash)
localVaultKey = null
await remove('key')
const localVaultKey = await get('key')
if (localVaultKey?.hash && localVaultKey?.hash !== me?.privates?.vaultKeyHash) {
// If the hash stored in the server does not match the hash of the local key,
// we can tell that the key is outdated (reset by another device or other reasons)
// in this case we clear the local key and let the user re-enter the passphrase
console.log('vault key hash mismatch, clearing local key', localVaultKey?.hash, '!=', me?.privates?.vaultKeyHash)
await disconnectVault()
return
}
setKey(localVaultKey)
keyReactiveVar(localVaultKey)
} catch (e) {
console.error('error loading vault configuration', e)
// toaster?.danger('error loading vault configuration ' + e.message)
}
})()
}, [me?.privates?.vaultKeyHash, keyHash, get, remove, setKey])
}, [me?.privates?.vaultKeyHash, get, remove, keyReactiveVar, disconnectVault])

// clear vault: remove everything and reset the key
const [clearVault] = useMutation(CLEAR_VAULT, {
onCompleted: async () => {
try {
await remove('key')
setKey(null)
setKeyHash(null)
keyReactiveVar(null)
} catch (e) {
toaster.danger('error clearing vault ' + e.message)
}
}
})

const disconnectVault = useCallback(async () => {
beforeDisconnectVault?.()
await remove('key')
setKey(null)
setKeyHash(null)
}, [remove, setKey, setKeyHash])

// initialize the vault and set a vault key
const setVaultKey = useCallback(async (passphrase) => {
try {
Expand Down Expand Up @@ -99,14 +103,14 @@ export function useVaultConfigurator ({ onVaultKeySet, beforeDisconnectVault } =
}
})

setKey(vaultKey)
setKeyHash(vaultKey.hash)
await set('key', vaultKey)
onVaultKeySet?.(encrypt).catch(console.error)
keyReactiveVar(vaultKey)
} catch (e) {
console.error('error setting vault key', e)
toaster.danger(e.message)
}
}, [getVaultEntries, updateVaultKey, set, get, remove, onVaultKeySet])
}, [getVaultEntries, updateVaultKey, set, get, remove, onVaultKeySet, keyReactiveVar])

return { key, setVaultKey, clearVault, disconnectVault }
}
Expand Down

0 comments on commit f0a5bc4

Please sign in to comment.