Add TPIN reset via OTP, with server-clock countdowns and redacted API logs
- Reset TPIN: empty-body initiate -> OTP -> encrypted new TPIN via /tpin/reset/*, from a Services tile, search, and "Forgot your TPIN?" on the transfer's TPIN sheet (returns to the same transfer review) - Handle every documented code: SESSION_INVALID signs out, TPIN_NOT_SET offers Create TPIN, CBS customer/account/org refusals stop the flow, outages retry from the start, expired or spent OTP/token restarts, policy VALIDATION_ERROR stays on the new-TPIN step - Secrets live in screen state only and are dropped as each step ends - Countdowns use the envelope timestamp, kept aside by the interceptor, so a wrong device clock cannot skew OTP or token expiry - New TPINs refuse any three-digit run (1235, 5987), for create too - Dev API logger redacts the session token, OTPs, PINs, encrypted payloads and one-time tokens - Tests: request bodies, RSA-OAEP SHA-256 payload decrypted with Node, fresh nonce on key retry, server-clock deadlines, log redaction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f1def81eb7
commit
5fbd13ba12
@@ -5,6 +5,7 @@ import { sessionManager } from '../security/sessionManager';
|
||||
import { secureStorage } from '../storage/secureStorage';
|
||||
import { apiLogger } from './apiLogger';
|
||||
import { CbsApiError, isCbsErrorCode, type FieldErrors } from './cbsErrors';
|
||||
import { rememberServerTime } from './serverClock';
|
||||
|
||||
const unauthorizedHandlers = new Set<() => void>();
|
||||
|
||||
@@ -83,8 +84,9 @@ export const attachInterceptors = (client: AxiosInstance) => {
|
||||
config.headers = nextHeaders as never;
|
||||
}
|
||||
|
||||
// Logged here, at the end of the interceptor, so the curl carries the
|
||||
// Authorization header the request will actually be sent with.
|
||||
// Logged here, at the end of the interceptor, so the curl shows the
|
||||
// headers the request will actually be sent with — the token itself as a
|
||||
// placeholder.
|
||||
apiLogger.request(config);
|
||||
|
||||
return config;
|
||||
@@ -117,7 +119,12 @@ export const attachInterceptors = (client: AxiosInstance) => {
|
||||
}
|
||||
|
||||
// Unwrap so callers read the payload directly rather than the envelope.
|
||||
return { ...response, data: envelope.data };
|
||||
// The server's `timestamp` is kept aside for anything counting down to
|
||||
// a server expiry — see `serverClock`.
|
||||
const unwrapped = { ...response, data: envelope.data };
|
||||
rememberServerTime(unwrapped, envelope.timestamp);
|
||||
|
||||
return unwrapped;
|
||||
},
|
||||
async (error: AxiosError) => {
|
||||
if (error instanceof CbsApiError) {
|
||||
|
||||
Reference in New Issue
Block a user