Update CBS Mobile App codebase
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import 'react-native-get-random-values';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import * as Keychain from 'react-native-keychain';
|
||||
|
||||
const DEVICE_SERVICE = 'com.bankcbs.mobile.deviceId';
|
||||
|
||||
/**
|
||||
* Kept in memory as well so the many calls that need it during one flow do not
|
||||
* each hit the Keystore.
|
||||
*/
|
||||
let cachedDeviceId: string | null = null;
|
||||
let inflight: Promise<string> | null = null;
|
||||
|
||||
const persist = async (deviceId: string) => {
|
||||
await Keychain.setGenericPassword('deviceId', deviceId, {
|
||||
service: DEVICE_SERVICE,
|
||||
accessible: Keychain.ACCESSIBLE.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
|
||||
securityLevel: Keychain.SECURITY_LEVEL.SECURE_SOFTWARE,
|
||||
});
|
||||
};
|
||||
|
||||
const load = async (): Promise<string> => {
|
||||
const stored = await Keychain.getGenericPassword({ service: DEVICE_SERVICE });
|
||||
|
||||
if (stored && stored.password) {
|
||||
return stored.password;
|
||||
}
|
||||
|
||||
const created = uuidv4();
|
||||
await persist(created);
|
||||
|
||||
return created;
|
||||
};
|
||||
|
||||
/**
|
||||
* The profile the customer registers is bound to this value. Registration and
|
||||
* every later sign-in must send the *same* one — a different value comes back
|
||||
* as `DEVICE_NOT_BOUND`, which reads like a server fault but is a client bug.
|
||||
* So it is generated exactly once, on first launch, and never regenerated
|
||||
* except by an explicit `reset()`.
|
||||
*
|
||||
* `AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY` rather than `WHEN_UNLOCKED_*`: the id
|
||||
* is not a secret, and sign-in must read it before the user has authenticated.
|
||||
*/
|
||||
export const deviceIdentity = {
|
||||
async get(): Promise<string> {
|
||||
if (cachedDeviceId) {
|
||||
return cachedDeviceId;
|
||||
}
|
||||
|
||||
// Concurrent callers on a cold start would otherwise each mint a UUID and
|
||||
// the last write would win, silently unbinding the device.
|
||||
inflight = inflight ?? load();
|
||||
|
||||
try {
|
||||
cachedDeviceId = await inflight;
|
||||
return cachedDeviceId;
|
||||
} finally {
|
||||
inflight = null;
|
||||
}
|
||||
},
|
||||
|
||||
/** In-memory peek for code that cannot await. Null before the first `get()`. */
|
||||
peek() {
|
||||
return cachedDeviceId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Mints a fresh id, unbinding this install from its registered profile. Only
|
||||
* for a deliberate "Register again" action — the customer will
|
||||
* have to go through registration once more.
|
||||
*/
|
||||
async reset(): Promise<string> {
|
||||
const next = uuidv4();
|
||||
await persist(next);
|
||||
cachedDeviceId = next;
|
||||
|
||||
return next;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user