1import { UnavailabilityError } from 'expo-errors';
2import ExpoSecureStore from './ExpoSecureStore';
3
4export type KeychainAccessibilityConstant = number;
5
6export const AFTER_FIRST_UNLOCK: KeychainAccessibilityConstant = ExpoSecureStore.AFTER_FIRST_UNLOCK;
7export const AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY: KeychainAccessibilityConstant =
8  ExpoSecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY;
9export const ALWAYS: KeychainAccessibilityConstant = ExpoSecureStore.ALWAYS;
10export const WHEN_PASSCODE_SET_THIS_DEVICE_ONLY: KeychainAccessibilityConstant =
11  ExpoSecureStore.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY;
12export const ALWAYS_THIS_DEVICE_ONLY: KeychainAccessibilityConstant =
13  ExpoSecureStore.ALWAYS_THIS_DEVICE_ONLY;
14export const WHEN_UNLOCKED: KeychainAccessibilityConstant = ExpoSecureStore.WHEN_UNLOCKED;
15export const WHEN_UNLOCKED_THIS_DEVICE_ONLY: KeychainAccessibilityConstant =
16  ExpoSecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY;
17
18export type SecureStoreOptions = {
19  keychainService?: string;
20  keychainAccessible?: KeychainAccessibilityConstant;
21};
22
23export async function deleteItemAsync(
24  key: string,
25  options: SecureStoreOptions = {}
26): Promise<void> {
27  _ensureValidKey(key);
28
29  if (!ExpoSecureStore.deleteValueWithKeyAsync) {
30    throw new UnavailabilityError('SecureStore', 'deleteItemAsync');
31  }
32  await ExpoSecureStore.deleteValueWithKeyAsync(key, options);
33}
34
35export async function getItemAsync(
36  key: string,
37  options: SecureStoreOptions = {}
38): Promise<string | null> {
39  _ensureValidKey(key);
40  return await ExpoSecureStore.getValueWithKeyAsync(key, options);
41}
42
43export async function setItemAsync(
44  key: string,
45  value: string,
46  options: SecureStoreOptions = {}
47): Promise<void> {
48  _ensureValidKey(key);
49  if (!_isValidValue(value)) {
50    throw new Error(
51      `Invalid value provided to SecureStore. Values must be strings; consider JSON-encoding your values if they are serializable.`
52    );
53  }
54  if (!ExpoSecureStore.setValueWithKeyAsync) {
55    throw new UnavailabilityError('SecureStore', 'setItemAsync');
56  }
57  await ExpoSecureStore.setValueWithKeyAsync(value, key, options);
58}
59
60function _ensureValidKey(key: string) {
61  if (!_isValidKey(key)) {
62    throw new Error(
63      `Invalid key provided to SecureStore. Keys must not be empty and contain only alphanumeric characters, ".", "-", and "_".`
64    );
65  }
66}
67
68function _isValidKey(key: string) {
69  return typeof key === 'string' && /^[\w.-]+$/.test(key);
70}
71
72function _isValidValue(value: string) {
73  return typeof value === 'string';
74}
75