as-app/src/lib/secureStore.js

77 lines
2.5 KiB
JavaScript

import * as SecureStore from "expo-secure-store";
import { createLogger } from "~/lib/logger";
import { SYSTEM_SCOPES } from "~/lib/logger/scopes";
const storageLogger = createLogger({
module: SYSTEM_SCOPES.STORAGE,
feature: "secure-store",
});
const secureStoreOptions = {
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
};
/**
* Wrapper for SecureStore that uses AFTER_FIRST_UNLOCK accessibility
* to prevent "User interaction is not allowed" errors on iOS
* see also https://github.com/expo/expo/issues/23924
*/
export const secureStore = {
getItemAsync: async (key) => {
storageLogger.debug("Retrieving secure item", { key });
const value = await SecureStore.getItemAsync(key, secureStoreOptions);
storageLogger.debug("Secure item retrieval result", {
key,
hasValue: !!value,
});
return value;
},
setItemAsync: async (key, value) => {
storageLogger.debug("Setting secure item", { key });
await SecureStore.setItemAsync(key, value, secureStoreOptions);
storageLogger.debug("Secure item set successfully", { key });
},
deleteItemAsync: async (key) => {
storageLogger.debug("Deleting secure item", { key });
await SecureStore.deleteItemAsync(key, secureStoreOptions);
storageLogger.debug("Secure item deleted successfully", { key });
},
};
/**
* Migrates a key from the old accessibility setting to the new one
*/
export const migrateKey = async (oldKey, newKey = oldKey) => {
storageLogger.info("Starting secure store key migration", { oldKey, newKey });
try {
// Try to get value with old accessibility setting
const value = await SecureStore.getItemAsync(oldKey);
if (value) {
storageLogger.debug("Found value with old accessibility setting", {
oldKey,
});
// Store with new accessibility setting
await secureStore.setItemAsync(newKey, value);
storageLogger.debug("Stored value with new accessibility setting", {
newKey,
});
// Clean up old key if the new key is different
if (oldKey !== newKey) {
await SecureStore.deleteItemAsync(oldKey);
storageLogger.debug("Cleaned up old key", { oldKey });
}
storageLogger.info("Key migration completed successfully", {
oldKey,
newKey,
});
return value;
}
} catch (error) {
storageLogger.error("Failed to migrate secure store key", {
oldKey,
error: error.message,
stack: error.stack,
});
}
return null;
};