import { NativeModules, Platform } from "react-native"; const { RNSecureStorage } = NativeModules; export enum Accessible { /** * The data in the keychain item can be accessed only while the device is unlocked by the user. */ WHEN_UNLOCKED = "AccessibleWhenUnlocked", /** * The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. */ AFTER_FIRST_UNLOCK = "AccessibleAfterFirstUnlock", /** * The data in the keychain item can always be accessed regardless of whether the device is locked. */ ALWAYS = "AccessibleAlways", /** * The data in the keychain can only be accessed when the device is unlocked. Only available if a passcode is set on the device. Items with this attribute never migrate to a new device. */ WHEN_PASSCODE_SET_THIS_DEVICE_ONLY = "AccessibleWhenPasscodeSetThisDeviceOnly", /** * The data in the keychain item can be accessed only while the device is unlocked by the user. Items with this attribute do not migrate to a new device. */ WHEN_UNLOCKED_THIS_DEVICE_ONLY = "AccessibleWhenUnlockedThisDeviceOnly", /** * The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. Items with this attribute never migrate to a new device. */ AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY = "AccessibleAfterFirstUnlockThisDeviceOnly", /** * The data in the keychain item can always be accessed regardless of whether the device is locked. Items with this attribute never migrate to a new device. */ ALWAYS_THIS_DEVICE_ONLY = "AccessibleAlwaysThisDeviceOnly", } export const ACCESS_CONTROL = { /** * Constraint to access an item with either Touch ID or passcode. */ USER_PRESENCE: "UserPresence", /** * Constraint to access an item with Touch ID for any enrolled fingers. */ BIOMETRY_ANY: "BiometryAny", /** * Constraint to access an item with Touch ID for currently enrolled fingers. */ BIOMETRY_CURRENT_SET: "BiometryCurrentSet", /** * Constraint to access an item with a passcode. */ DEVICE_PASSCODE: "DevicePasscode", /** * Constraint to use an application-provided password for data encryption key generation. */ APPLICATION_PASSWORD: "ApplicationPassword", /** * Constraint to access an item with Touch ID for any enrolled fingers or passcode. */ BIOMETRY_ANY_OR_DEVICE_PASSCODE: "BiometryAnyOrDevicePasscode", /** * Constraint to access an item with Touch ID for currently enrolled fingers or passcode. */ BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE: "BiometryCurrentSetOrDevicePasscode", }; export enum AuthenticationType { /** * Device owner is going to be authenticated by biometry or device passcode. */ DEVICE_PASSCODE_OR_BIOMETRICS = "AuthenticationWithBiometricsDevicePasscode", /** * Device owner is going to be authenticated using a biometric method (Touch ID or Face ID). */ BIOMETRIC = "AuthenticationWithBiometrics", } export const BIOMETRY_TYPE = { /** * Device supports authentication with Touch ID. */ TOUCH_ID: "TouchID", /** * Device supports authentication with Face ID. */ FACE_ID: "FaceID", /** * Device supports authentication with Android Fingerprint. */ FINGERPRINT: "Fingerprint", }; const isAndroid = Platform.OS === "android"; export interface Options { /** * iOS only | This dictates how a keychain item may be used, see possible values in `SecureStorage.ACCESS_CONTROL`. * @default null */ accessControl: keyof typeof ACCESS_CONTROL | null; /** * iOS only | This dictates when a keychain item is accessible, see possible values in `SecureStorage.ACCESSIBLE`. * @default Accessible.WHEN_UNLOCKED */ accessible: Accessible; /** * iOS only | In which App Group to share the keychain. Requires additional setup with entitlements. * @default null */ accessGroup: string | null; /** * iOS only | What to prompt the user when unlocking the keychain with biometry or device password. * @default "Authenticate to retrieve secret data" */ authenticationPrompt: string; /** * iOS only | Policies specifying which forms of authentication are acceptable. * @default AuthenticationType.DEVICE_PASSCODE_OR_BIOMETRICS */ authenticationType: AuthenticationType; /** * All | Qualifier for the service. * @default null */ service: string | null; } const defaultOptions: Options = { accessControl: null, accessible: Accessible.WHEN_UNLOCKED, accessGroup: null, authenticationPrompt: "Authenticate to retrieve secret data", service: null, authenticationType: AuthenticationType.DEVICE_PASSCODE_OR_BIOMETRICS, }; const getItem = (key: string, options: Options) => { const finalOptions = { ...defaultOptions, ...options, }; if (isAndroid) { return RNSecureStorage.getItem(key, finalOptions.service); } return RNSecureStorage.getItem(key, finalOptions); }; const setItem = (key: string, value: any, options: Options) => { const finalOptions = { ...defaultOptions, ...options, }; if (isAndroid) { return RNSecureStorage.setItem(key, value, finalOptions.service); } return RNSecureStorage.setItem(key, value, finalOptions); }; const removeItem = (key: string, options: Options) => { const finalOptions = { ...defaultOptions, ...options, }; if (isAndroid) { return RNSecureStorage.removeItem(key, finalOptions.service); } return RNSecureStorage.removeItem(key, finalOptions); }; const getAllKeys = (options: Options) => { const finalOptions = { ...defaultOptions, ...options, }; if (isAndroid) { return RNSecureStorage.getAllKeys(finalOptions.service); } return RNSecureStorage.getAllKeys(finalOptions); }; const getSupportedBiometryType = () => RNSecureStorage.getSupportedBiometryType(); const canCheckAuthentication = (options: Options) => { const finalOptions = { ...defaultOptions, ...options, }; if (isAndroid) { return RNSecureStorage.getSupportedBiometryType() !== null; } return RNSecureStorage.canCheckAuthentication(finalOptions); }; export default { getItem, setItem, removeItem, getAllKeys, getSupportedBiometryType, canCheckAuthentication, };