teamdigitale/italia-app

View on GitHub
ts/utils/keychain.ts

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * Helpers for setting a getting the PIN code.
 *
 * Note: setGenerigPassword and getGenericPassword will use the App bundle ID
 * as the service ID by default.
 * @see https://github.com/oblador/react-native-keychain#options
 */

import * as O from "fp-ts/lib/Option";
import * as Keychain from "react-native-keychain";

import { PinString } from "../types/PinString";

const PIN_KEY = "PIN";

/**
 * Wrapper that sets default accessible option.
 *
 * More about accessibility options:
 * https://developer.apple.com/documentation/security/ksecattraccessibleafterfirstunlock
 */
export async function setGenericPasswordWithDefaultAccessibleOption(
  username: string,
  password: string,
  options?: Keychain.Options
) {
  return Keychain.setGenericPassword(username, password, {
    ...options,
    // The data in the keychain item can be accessed only while the device is unlocked by the user.
    // This is recommended for items that need to be accessible only while the application is in the foreground. Items
    // with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device,
    // these items will not be present.
    accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY
  });
}

/**
 * Saves the provided unlock code in the Keychain
 */
export async function setPin(pin: PinString): Promise<boolean> {
  return await setGenericPasswordWithDefaultAccessibleOption(PIN_KEY, pin);
}

/**
 * Removes the unlock code from the Keychain
 */
export async function deletePin(): Promise<boolean> {
  return await Keychain.resetGenericPassword();
}

/**
 * Returns the unlock code from the Keychain.
 *
 * The promise fails when there is no valid unlock code stored.
 */
export async function getPin(): Promise<O.Option<PinString>> {
  const credentials = await Keychain.getGenericPassword();
  if (typeof credentials !== "boolean" && credentials.password.length > 0) {
    return O.fromEither(PinString.decode(credentials.password));
  } else {
    return O.none;
  }
}