mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-02 00:03:27 +00:00
The verify step now returns an encrypted verificationToken alongside the readable identity. After the existing signup succeeds, the page posts it to POST /profiles/me/fayda, which marks the phone verified when it is the one Fayda vouched for and fills the still-empty profile fields. Best-effort: the account already works if the call fails, and the token can be presented again. When the server confirms the phone, the page goes straight to the portal instead of /otp-verify — Fayda already verified that exact number with its own OTP, and asking for a second one on the same number is theatre. An applicant who edited the prefilled number still gets the normal OTP step.
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
/**
|
|
* The Fayda round trip leaves the app entirely, so the little state that has to
|
|
* survive it lives in sessionStorage: same tab, same origin, gone when the tab
|
|
* closes.
|
|
*
|
|
* Nothing secret is kept here. The `transactionToken` is signed by the API and
|
|
* useless without it — the PKCE verifier, the nonce and the client key never
|
|
* leave the backend.
|
|
*/
|
|
|
|
const REQUEST_KEY = 'fayda:request';
|
|
const RESULT_KEY = 'fayda:result';
|
|
|
|
export interface FaydaRequest {
|
|
transactionToken: string;
|
|
state: string;
|
|
}
|
|
|
|
export interface FaydaPrefill {
|
|
email?: string;
|
|
phoneNumber?: string;
|
|
nameEn?: string;
|
|
nameAm?: string;
|
|
/** Shown for context only — the signup form has no field for these. */
|
|
gender?: string;
|
|
address?: string;
|
|
birthdate?: string;
|
|
nationality?: string;
|
|
faydaNumber?: string;
|
|
}
|
|
|
|
/** Shape of `POST /auth/register-with-fayda` with `action: "verify"`. */
|
|
export interface FaydaResult {
|
|
identity: FaydaPrefill;
|
|
faydaVerified: boolean;
|
|
/** Signup fields Fayda vouched for. */
|
|
verifiedFields: string[];
|
|
/** Prefilled fields already taken by another account. */
|
|
conflicts: string[];
|
|
/**
|
|
* Encrypted proof of the verification, presented to POST /profiles/me/fayda
|
|
* after signup so the account and profile record what Fayda vouched for.
|
|
*/
|
|
verificationToken: string;
|
|
}
|
|
|
|
// Private browsing and locked-down browsers can throw on access, and a failure
|
|
// here should degrade to "no Fayda prefill", never break the signup page.
|
|
function read<T>(key: string): T | null {
|
|
try {
|
|
const raw = sessionStorage.getItem(key);
|
|
return raw ? (JSON.parse(raw) as T) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function write(key: string, value: unknown): void {
|
|
try {
|
|
sessionStorage.setItem(key, JSON.stringify(value));
|
|
} catch {
|
|
/* nothing to do — the flow reports a generic failure instead */
|
|
}
|
|
}
|
|
|
|
function clear(key: string): void {
|
|
try {
|
|
sessionStorage.removeItem(key);
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
export const faydaSession = {
|
|
saveRequest: (request: FaydaRequest) => write(REQUEST_KEY, request),
|
|
takeRequest: (): FaydaRequest | null => {
|
|
const request = read<FaydaRequest>(REQUEST_KEY);
|
|
// Single use: a stale token would otherwise be replayed against a fresh
|
|
// callback and fail with a confusing "session expired".
|
|
clear(REQUEST_KEY);
|
|
return request;
|
|
},
|
|
|
|
saveResult: (result: FaydaResult) => write(RESULT_KEY, result),
|
|
peekResult: (): FaydaResult | null => read<FaydaResult>(RESULT_KEY),
|
|
clearResult: () => clear(RESULT_KEY),
|
|
};
|