@react-vault/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +12 -0
- package/README.md +41 -0
- package/dist/audit/auditClient.d.ts +40 -0
- package/dist/audit/auditClient.d.ts.map +1 -0
- package/dist/audit/auditClient.js +180 -0
- package/dist/audit/auditClient.js.map +1 -0
- package/dist/audit/index.d.ts +9 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +9 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/scrubber.d.ts +27 -0
- package/dist/audit/scrubber.d.ts.map +1 -0
- package/dist/audit/scrubber.js +111 -0
- package/dist/audit/scrubber.js.map +1 -0
- package/dist/audit/types.d.ts +42 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +2 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/auth/crossTabSync.d.ts +15 -0
- package/dist/auth/crossTabSync.d.ts.map +1 -0
- package/dist/auth/crossTabSync.js +30 -0
- package/dist/auth/crossTabSync.js.map +1 -0
- package/dist/auth/idleTimer.d.ts +34 -0
- package/dist/auth/idleTimer.d.ts.map +1 -0
- package/dist/auth/idleTimer.js +54 -0
- package/dist/auth/idleTimer.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/tokenManager.d.ts +47 -0
- package/dist/auth/tokenManager.d.ts.map +1 -0
- package/dist/auth/tokenManager.js +75 -0
- package/dist/auth/tokenManager.js.map +1 -0
- package/dist/compliance/csp.d.ts +20 -0
- package/dist/compliance/csp.d.ts.map +1 -0
- package/dist/compliance/csp.js +34 -0
- package/dist/compliance/csp.js.map +1 -0
- package/dist/compliance/index.d.ts +8 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +8 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/compliance/safeError.d.ts +12 -0
- package/dist/compliance/safeError.d.ts.map +1 -0
- package/dist/compliance/safeError.js +39 -0
- package/dist/compliance/safeError.js.map +1 -0
- package/dist/encryption/aesgcm.d.ts +22 -0
- package/dist/encryption/aesgcm.d.ts.map +1 -0
- package/dist/encryption/aesgcm.js +67 -0
- package/dist/encryption/aesgcm.js.map +1 -0
- package/dist/encryption/envelope.d.ts +30 -0
- package/dist/encryption/envelope.d.ts.map +1 -0
- package/dist/encryption/envelope.js +46 -0
- package/dist/encryption/envelope.js.map +1 -0
- package/dist/encryption/index.d.ts +19 -0
- package/dist/encryption/index.d.ts.map +1 -0
- package/dist/encryption/index.js +19 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/encryption/pbkdf2.d.ts +21 -0
- package/dist/encryption/pbkdf2.d.ts.map +1 -0
- package/dist/encryption/pbkdf2.js +48 -0
- package/dist/encryption/pbkdf2.js.map +1 -0
- package/dist/encryption/rsaoaep.d.ts +21 -0
- package/dist/encryption/rsaoaep.d.ts.map +1 -0
- package/dist/encryption/rsaoaep.js +43 -0
- package/dist/encryption/rsaoaep.js.map +1 -0
- package/dist/encryption/util.d.ts +17 -0
- package/dist/encryption/util.d.ts.map +1 -0
- package/dist/encryption/util.js +47 -0
- package/dist/encryption/util.js.map +1 -0
- package/dist/http/createAxios.d.ts +39 -0
- package/dist/http/createAxios.d.ts.map +1 -0
- package/dist/http/createAxios.js +58 -0
- package/dist/http/createAxios.js.map +1 -0
- package/dist/http/errors.d.ts +28 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +57 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/index.d.ts +10 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +10 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/interceptors.d.ts +30 -0
- package/dist/http/interceptors.d.ts.map +1 -0
- package/dist/http/interceptors.js +112 -0
- package/dist/http/interceptors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/pii/index.d.ts +10 -0
- package/dist/pii/index.d.ts.map +1 -0
- package/dist/pii/index.js +10 -0
- package/dist/pii/index.js.map +1 -0
- package/dist/pii/maskers.d.ts +63 -0
- package/dist/pii/maskers.d.ts.map +1 -0
- package/dist/pii/maskers.js +186 -0
- package/dist/pii/maskers.js.map +1 -0
- package/dist/pii/patterns.d.ts +20 -0
- package/dist/pii/patterns.d.ts.map +1 -0
- package/dist/pii/patterns.js +19 -0
- package/dist/pii/patterns.js.map +1 -0
- package/dist/pii/validators.d.ts +10 -0
- package/dist/pii/validators.d.ts.map +1 -0
- package/dist/pii/validators.js +66 -0
- package/dist/pii/validators.js.map +1 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +14 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/secureStorage.d.ts +28 -0
- package/dist/storage/secureStorage.d.ts.map +1 -0
- package/dist/storage/secureStorage.js +140 -0
- package/dist/storage/secureStorage.js.map +1 -0
- package/dist/storage/types.d.ts +13 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/package.json +95 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Copyright (c) 2026 Rsense. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are the
|
|
4
|
+
proprietary property of Rsense and are licensed for internal use only by
|
|
5
|
+
employees, contractors, and authorised partners of Rsense.
|
|
6
|
+
|
|
7
|
+
No part of the Software may be redistributed, sublicensed, sold, or otherwise
|
|
8
|
+
made available to third parties without prior written consent from Rsense.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
11
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
12
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @react-vault/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic BFSI security primitives. The "core" package every BFSI React project depends on.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { aesgcm } from '@react-vault/core/encryption';
|
|
7
|
+
import { maskPan, isValidPan } from '@react-vault/core/pii';
|
|
8
|
+
import { AuditClient, generateEventId } from '@react-vault/core/audit';
|
|
9
|
+
import { createAxios, ApiError } from '@react-vault/core/http';
|
|
10
|
+
import { TokenManager, IdleTimer, CrossTabSync } from '@react-vault/core/auth';
|
|
11
|
+
import { put, get } from '@react-vault/core/storage';
|
|
12
|
+
import { generateCspNonce, buildCsp, toSafeView } from '@react-vault/core/compliance';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Modules
|
|
16
|
+
|
|
17
|
+
- **`encryption`** — Web Crypto wrappers: AES-GCM 256, RSA-OAEP, PBKDF2, envelope encryption
|
|
18
|
+
- **`pii`** — Maskers (PAN, Aadhaar, account#, mobile, email, name, address, DOB) + validators (Verhoeff for Aadhaar) + regex patterns
|
|
19
|
+
- **`audit`** — Batched audit log client with PII scrubber, page-unload beacon, sessionStorage retry
|
|
20
|
+
- **`http`** — Configurable axios factory with composable interceptors (auth header, snake↔camel, idempotency key, error mapping)
|
|
21
|
+
- **`auth`** — `TokenManager` with refresh race protection, `IdleTimer`, `CrossTabSync` (BroadcastChannel)
|
|
22
|
+
- **`storage`** — Tiered: transient (memory), session (sessionStorage), persistent (encrypted IndexedDB — v0.2)
|
|
23
|
+
- **`compliance`** — CSP nonce + builder, safe-error envelope mapping `ApiError` → user-facing view
|
|
24
|
+
|
|
25
|
+
## Conventions
|
|
26
|
+
|
|
27
|
+
- **No React dependency.** This is the core. UI lives in `@react-vault/ui`.
|
|
28
|
+
- **All public APIs are typed.** No `any`.
|
|
29
|
+
- **Errors are typed (`ApiError`).** App code matches on `kind`, not strings.
|
|
30
|
+
- **PII never logged.** All logging paths route through the scrubber.
|
|
31
|
+
- **Tokens never in localStorage.** `TokenManager` keeps them in memory.
|
|
32
|
+
|
|
33
|
+
## Run
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pnpm test # vitest run
|
|
37
|
+
pnpm test:watch # vitest watch
|
|
38
|
+
pnpm typecheck # tsc --noEmit
|
|
39
|
+
pnpm build # tsc → dist/
|
|
40
|
+
pnpm lint # eslint
|
|
41
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit client. Buffers events and POSTs them in batches.
|
|
3
|
+
*
|
|
4
|
+
* Survival rules:
|
|
5
|
+
* - On failure, retry once with exponential backoff
|
|
6
|
+
* - On second failure, store in sessionStorage and retry next flush
|
|
7
|
+
* - On page unload, flush via sendBeacon (best-effort)
|
|
8
|
+
*/
|
|
9
|
+
import type { AuditEvent, AuditClientConfig } from './types.js';
|
|
10
|
+
export declare class AuditClient {
|
|
11
|
+
private readonly config;
|
|
12
|
+
private queue;
|
|
13
|
+
private timer;
|
|
14
|
+
private inflight;
|
|
15
|
+
constructor(config: AuditClientConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Record an event. Scrubs metadata for PII before queueing.
|
|
18
|
+
*/
|
|
19
|
+
record(event: AuditEvent): void;
|
|
20
|
+
/**
|
|
21
|
+
* Force-flush the queue. Returns when done.
|
|
22
|
+
*/
|
|
23
|
+
flush(): Promise<void>;
|
|
24
|
+
private scheduleFlush;
|
|
25
|
+
private clearTimer;
|
|
26
|
+
private send;
|
|
27
|
+
private flushBeacon;
|
|
28
|
+
private persistToStorage;
|
|
29
|
+
private restoreFromStorage;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate a UUID v4. Used for event_id.
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateEventId(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Convenience: generate a short error reference code shown to users in toasts.
|
|
37
|
+
* E.g. `ERR-A7K2`. Use to correlate UI error to full log entry.
|
|
38
|
+
*/
|
|
39
|
+
export declare function generateErrorRef(): string;
|
|
40
|
+
//# sourceMappingURL=auditClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditClient.d.ts","sourceRoot":"","sources":["../../src/audit/auditClient.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAOhE,qBAAa,WAAW;IAKV,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,QAAQ,CAAS;gBAEI,MAAM,EAAE,iBAAiB;IAQtD;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAoB/B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB5B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,UAAU;YAOJ,IAAI;IAalB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,kBAAkB;CAe3B;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAexC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAWzC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { scrub } from './scrubber.js';
|
|
2
|
+
const DEFAULT_BATCH_SIZE = 20;
|
|
3
|
+
const DEFAULT_FLUSH_MS = 5_000;
|
|
4
|
+
const STORAGE_KEY = '__bfsi_audit_pending__';
|
|
5
|
+
export class AuditClient {
|
|
6
|
+
config;
|
|
7
|
+
queue = [];
|
|
8
|
+
timer = null;
|
|
9
|
+
inflight = false;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.restoreFromStorage();
|
|
13
|
+
if (typeof window !== 'undefined') {
|
|
14
|
+
window.addEventListener('pagehide', () => this.flushBeacon());
|
|
15
|
+
window.addEventListener('beforeunload', () => this.flushBeacon());
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Record an event. Scrubs metadata for PII before queueing.
|
|
20
|
+
*/
|
|
21
|
+
record(event) {
|
|
22
|
+
const scrubbed = {
|
|
23
|
+
...event,
|
|
24
|
+
metadata: event.metadata
|
|
25
|
+
? scrub(event.metadata, { additionalPatterns: this.config.additionalScrubPatterns })
|
|
26
|
+
: undefined,
|
|
27
|
+
};
|
|
28
|
+
this.queue.push(scrubbed);
|
|
29
|
+
const batchSize = this.config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
30
|
+
if (this.queue.length >= batchSize) {
|
|
31
|
+
void this.flush();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.scheduleFlush();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Force-flush the queue. Returns when done.
|
|
39
|
+
*/
|
|
40
|
+
async flush() {
|
|
41
|
+
if (this.inflight || this.queue.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
this.inflight = true;
|
|
44
|
+
this.clearTimer();
|
|
45
|
+
const batch = this.queue.splice(0);
|
|
46
|
+
try {
|
|
47
|
+
await this.send(batch);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// Re-queue on failure
|
|
51
|
+
this.queue.unshift(...batch);
|
|
52
|
+
this.persistToStorage();
|
|
53
|
+
try {
|
|
54
|
+
this.config.onError?.(err, batch);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// swallow — onError must not throw further
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
this.inflight = false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
scheduleFlush() {
|
|
65
|
+
if (this.timer)
|
|
66
|
+
return;
|
|
67
|
+
const intervalMs = this.config.flushIntervalMs ?? DEFAULT_FLUSH_MS;
|
|
68
|
+
this.timer = setTimeout(() => {
|
|
69
|
+
this.timer = null;
|
|
70
|
+
void this.flush();
|
|
71
|
+
}, intervalMs);
|
|
72
|
+
}
|
|
73
|
+
clearTimer() {
|
|
74
|
+
if (this.timer) {
|
|
75
|
+
clearTimeout(this.timer);
|
|
76
|
+
this.timer = null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async send(batch) {
|
|
80
|
+
const fetcher = this.config.fetchImpl ?? fetch;
|
|
81
|
+
const response = await fetcher(this.config.endpoint, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify({ events: batch }),
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new Error(`audit endpoint returned ${response.status}`);
|
|
88
|
+
}
|
|
89
|
+
this.persistToStorage();
|
|
90
|
+
}
|
|
91
|
+
flushBeacon() {
|
|
92
|
+
if (this.queue.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
if (typeof navigator === 'undefined' || typeof navigator.sendBeacon !== 'function') {
|
|
95
|
+
this.persistToStorage();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const blob = new Blob([JSON.stringify({ events: this.queue })], {
|
|
99
|
+
type: 'application/json',
|
|
100
|
+
});
|
|
101
|
+
const sent = navigator.sendBeacon(this.config.endpoint, blob);
|
|
102
|
+
if (sent) {
|
|
103
|
+
this.queue = [];
|
|
104
|
+
this.persistToStorage();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
persistToStorage() {
|
|
108
|
+
if (typeof sessionStorage === 'undefined')
|
|
109
|
+
return;
|
|
110
|
+
try {
|
|
111
|
+
if (this.queue.length === 0) {
|
|
112
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(this.queue));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// sessionStorage may be unavailable (privacy mode); fail silent
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
restoreFromStorage() {
|
|
123
|
+
if (typeof sessionStorage === 'undefined')
|
|
124
|
+
return;
|
|
125
|
+
try {
|
|
126
|
+
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
127
|
+
if (raw) {
|
|
128
|
+
const parsed = JSON.parse(raw);
|
|
129
|
+
if (Array.isArray(parsed)) {
|
|
130
|
+
this.queue.unshift(...parsed);
|
|
131
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// ignore corrupt state
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generate a UUID v4. Used for event_id.
|
|
142
|
+
*/
|
|
143
|
+
export function generateEventId() {
|
|
144
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
145
|
+
return crypto.randomUUID();
|
|
146
|
+
}
|
|
147
|
+
// Fallback: not as strong, but works in environments without randomUUID
|
|
148
|
+
const bytes = new Uint8Array(16);
|
|
149
|
+
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
|
150
|
+
crypto.getRandomValues(bytes);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
for (let i = 0; i < 16; i++)
|
|
154
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
155
|
+
}
|
|
156
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;
|
|
157
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
|
|
158
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
159
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Convenience: generate a short error reference code shown to users in toasts.
|
|
163
|
+
* E.g. `ERR-A7K2`. Use to correlate UI error to full log entry.
|
|
164
|
+
*/
|
|
165
|
+
export function generateErrorRef() {
|
|
166
|
+
const chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789'; // no 0/O confusion
|
|
167
|
+
let out = 'ERR-';
|
|
168
|
+
const bytes = new Uint8Array(4);
|
|
169
|
+
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
|
170
|
+
crypto.getRandomValues(bytes);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
for (let i = 0; i < 4; i++)
|
|
174
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
175
|
+
}
|
|
176
|
+
for (let i = 0; i < 4; i++)
|
|
177
|
+
out += chars[bytes[i] % chars.length];
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=auditClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditClient.js","sourceRoot":"","sources":["../../src/audit/auditClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit logging — batched, PII-scrubbed audit events for BFSI compliance.
|
|
3
|
+
*
|
|
4
|
+
* Required for RBI Annexure I §8, SOC2 CC7.3, PCI-DSS req 10.
|
|
5
|
+
*/
|
|
6
|
+
export * from './auditClient.js';
|
|
7
|
+
export * from './scrubber.js';
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit logging — batched, PII-scrubbed audit events for BFSI compliance.
|
|
3
|
+
*
|
|
4
|
+
* Required for RBI Annexure I §8, SOC2 CC7.3, PCI-DSS req 10.
|
|
5
|
+
*/
|
|
6
|
+
export * from './auditClient.js';
|
|
7
|
+
export * from './scrubber.js';
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII scrubber for audit log payloads.
|
|
3
|
+
*
|
|
4
|
+
* Walks an object recursively, replacing values that look like PII with
|
|
5
|
+
* sentinel tokens. Preserves shape so debugging is still possible.
|
|
6
|
+
*
|
|
7
|
+
* RULES OF SCRUBBING:
|
|
8
|
+
* - Default to over-redaction; humans can recover from "too little info"
|
|
9
|
+
* more cheaply than from "leaked PAN in audit log".
|
|
10
|
+
* - Key-name signal trumps value pattern. `pan: "FOO"` is scrubbed even if
|
|
11
|
+
* the value doesn't match PAN shape.
|
|
12
|
+
* - Values matching strong patterns (PAN, Aadhaar) are scrubbed regardless
|
|
13
|
+
* of key name.
|
|
14
|
+
*/
|
|
15
|
+
export interface ScrubOptions {
|
|
16
|
+
/** Extra patterns to scrub. */
|
|
17
|
+
additionalPatterns?: RegExp[];
|
|
18
|
+
/** Maximum depth to recurse. Prevents pathological inputs. Default 10. */
|
|
19
|
+
maxDepth?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function scrub(value: unknown, opts?: ScrubOptions): unknown;
|
|
22
|
+
/**
|
|
23
|
+
* Hash a value with SHA-256 for tamper-detection metadata.
|
|
24
|
+
* Returns hex. Use for `request_hash` — does NOT reverse the input.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hashRequest(input: unknown): Promise<string>;
|
|
27
|
+
//# sourceMappingURL=scrubber.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrubber.d.ts","sourceRoot":"","sources":["../../src/audit/scrubber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAsCH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAItE;AAwCD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAOjE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII scrubber for audit log payloads.
|
|
3
|
+
*
|
|
4
|
+
* Walks an object recursively, replacing values that look like PII with
|
|
5
|
+
* sentinel tokens. Preserves shape so debugging is still possible.
|
|
6
|
+
*
|
|
7
|
+
* RULES OF SCRUBBING:
|
|
8
|
+
* - Default to over-redaction; humans can recover from "too little info"
|
|
9
|
+
* more cheaply than from "leaked PAN in audit log".
|
|
10
|
+
* - Key-name signal trumps value pattern. `pan: "FOO"` is scrubbed even if
|
|
11
|
+
* the value doesn't match PAN shape.
|
|
12
|
+
* - Values matching strong patterns (PAN, Aadhaar) are scrubbed regardless
|
|
13
|
+
* of key name.
|
|
14
|
+
*/
|
|
15
|
+
const SENSITIVE_KEY_PATTERNS = [
|
|
16
|
+
/^pan$/i,
|
|
17
|
+
/^aadhaar$/i,
|
|
18
|
+
/^aadhar$/i,
|
|
19
|
+
/^account(_?number)?$/i,
|
|
20
|
+
/^card(_?number)?$/i,
|
|
21
|
+
/^(cvv|cvc)$/i,
|
|
22
|
+
/^otp$/i,
|
|
23
|
+
/^(password|passwd)$/i,
|
|
24
|
+
/^secret$/i,
|
|
25
|
+
/^token$/i,
|
|
26
|
+
/^api(_?key)?$/i,
|
|
27
|
+
/^(mobile|phone)$/i,
|
|
28
|
+
/^email$/i,
|
|
29
|
+
/^(dob|date_of_birth)$/i,
|
|
30
|
+
/^(first_?name|last_?name|full_?name|name)$/i,
|
|
31
|
+
/^address$/i,
|
|
32
|
+
/^ifsc$/i,
|
|
33
|
+
/^upi(_?(id|vpa))?$/i,
|
|
34
|
+
/^passport$/i,
|
|
35
|
+
/^auth/i,
|
|
36
|
+
];
|
|
37
|
+
const VALUE_PATTERNS = [
|
|
38
|
+
/[A-Z]{5}\d{4}[A-Z]/, // PAN
|
|
39
|
+
/\b\d{12}\b/, // Aadhaar
|
|
40
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
41
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key
|
|
42
|
+
/sk-(live|test)_[A-Za-z0-9]{20,}/, // Stripe
|
|
43
|
+
/sk-ant-[A-Za-z0-9_-]{32,}/, // Anthropic
|
|
44
|
+
/ghp_[A-Za-z0-9]{36}/, // GitHub
|
|
45
|
+
/AIza[0-9A-Za-z_-]{35}/, // Google
|
|
46
|
+
];
|
|
47
|
+
const REDACTED = '<scrubbed>';
|
|
48
|
+
export function scrub(value, opts = {}) {
|
|
49
|
+
const maxDepth = opts.maxDepth ?? 10;
|
|
50
|
+
const extraPatterns = opts.additionalPatterns ?? [];
|
|
51
|
+
return walk(value, 0, maxDepth, extraPatterns);
|
|
52
|
+
}
|
|
53
|
+
function walk(value, depth, maxDepth, extra) {
|
|
54
|
+
if (depth > maxDepth) {
|
|
55
|
+
return REDACTED;
|
|
56
|
+
}
|
|
57
|
+
if (value === null || value === undefined) {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
if (typeof value === 'string') {
|
|
61
|
+
return scrubString(value, extra);
|
|
62
|
+
}
|
|
63
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
return value.map((v) => walk(v, depth + 1, maxDepth, extra));
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === 'object') {
|
|
70
|
+
const out = {};
|
|
71
|
+
for (const [k, v] of Object.entries(value)) {
|
|
72
|
+
if (isSensitiveKey(k)) {
|
|
73
|
+
out[k] = v === null || v === undefined ? v : REDACTED;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
out[k] = walk(v, depth + 1, maxDepth, extra);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
return REDACTED;
|
|
82
|
+
}
|
|
83
|
+
function isSensitiveKey(key) {
|
|
84
|
+
return SENSITIVE_KEY_PATTERNS.some((p) => p.test(key));
|
|
85
|
+
}
|
|
86
|
+
function scrubString(value, extra) {
|
|
87
|
+
for (const p of VALUE_PATTERNS) {
|
|
88
|
+
if (p.test(value)) {
|
|
89
|
+
return REDACTED;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const p of extra) {
|
|
93
|
+
if (p.test(value)) {
|
|
94
|
+
return REDACTED;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Hash a value with SHA-256 for tamper-detection metadata.
|
|
101
|
+
* Returns hex. Use for `request_hash` — does NOT reverse the input.
|
|
102
|
+
*/
|
|
103
|
+
export async function hashRequest(input) {
|
|
104
|
+
const json = JSON.stringify(input);
|
|
105
|
+
const bytes = new TextEncoder().encode(json);
|
|
106
|
+
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));
|
|
107
|
+
return Array.from(digest)
|
|
108
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
109
|
+
.join('');
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=scrubber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrubber.js","sourceRoot":"","sources":["../../src/audit/scrubber.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit event shape. Matches the backend `POST /api/audit` contract.
|
|
3
|
+
*/
|
|
4
|
+
export interface AuditEvent {
|
|
5
|
+
/** Client-generated UUID v4. Backend re-stamps if needed for legal record. */
|
|
6
|
+
event_id: string;
|
|
7
|
+
/** Dot-separated convention: <feature>.<entity>.<action> */
|
|
8
|
+
event_name: string;
|
|
9
|
+
/** Who did it. From session. */
|
|
10
|
+
actor_id: string;
|
|
11
|
+
/** Session correlation. */
|
|
12
|
+
actor_session_id?: string;
|
|
13
|
+
/** Type of resource the action targets. */
|
|
14
|
+
target_type?: string;
|
|
15
|
+
/** Resource ID. */
|
|
16
|
+
target_id?: string;
|
|
17
|
+
/** ISO 8601. Client clock; backend re-stamps. */
|
|
18
|
+
timestamp: string;
|
|
19
|
+
/** Outcome of the action. */
|
|
20
|
+
outcome: 'success' | 'failure' | 'pending';
|
|
21
|
+
/** SHA-256 of the request body (for tamper detection). */
|
|
22
|
+
request_hash?: string;
|
|
23
|
+
/** Non-PII context. User agent, viewport, feature flag state, etc. */
|
|
24
|
+
client_metadata?: Record<string, unknown>;
|
|
25
|
+
/** Free-form metadata. Will be scrubbed for PII before send. */
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export interface AuditClientConfig {
|
|
29
|
+
/** Endpoint to POST events to. */
|
|
30
|
+
endpoint: string;
|
|
31
|
+
/** Max events to batch before sending. Default 20. */
|
|
32
|
+
batchSize?: number;
|
|
33
|
+
/** Max ms between flushes regardless of batch size. Default 5000. */
|
|
34
|
+
flushIntervalMs?: number;
|
|
35
|
+
/** Custom fetch (e.g. authenticated fetch). Default `fetch`. */
|
|
36
|
+
fetchImpl?: typeof fetch;
|
|
37
|
+
/** Called on send failure. Useful for surfacing to error monitoring. */
|
|
38
|
+
onError?: (err: unknown, batch: AuditEvent[]) => void;
|
|
39
|
+
/** Additional PII patterns to scrub (beyond defaults). */
|
|
40
|
+
additionalScrubPatterns?: RegExp[];
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3C,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,wEAAwE;IACxE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IACtD,0DAA0D;IAC1D,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;CACpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AuthBroadcast = {
|
|
2
|
+
type: 'logout';
|
|
3
|
+
reason: 'user' | 'idle' | 'expired' | 'forced';
|
|
4
|
+
} | {
|
|
5
|
+
type: 'login';
|
|
6
|
+
};
|
|
7
|
+
export declare class CrossTabSync {
|
|
8
|
+
private readonly onMessage;
|
|
9
|
+
private channel;
|
|
10
|
+
constructor(onMessage: (msg: AuthBroadcast) => void);
|
|
11
|
+
start(): void;
|
|
12
|
+
stop(): void;
|
|
13
|
+
broadcast(msg: AuthBroadcast): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=crossTabSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crossTabSync.d.ts","sourceRoot":"","sources":["../../src/auth/crossTabSync.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAH5B,OAAO,CAAC,OAAO,CAAiC;gBAG7B,SAAS,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI;IAG1D,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;IAKZ,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;CAGpC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-tab logout sync via BroadcastChannel.
|
|
3
|
+
*
|
|
4
|
+
* Use case: user logs out in one tab → all other tabs follow.
|
|
5
|
+
* Falls back gracefully when BroadcastChannel is unavailable.
|
|
6
|
+
*/
|
|
7
|
+
const CHANNEL_NAME = 'bfsi-auth';
|
|
8
|
+
export class CrossTabSync {
|
|
9
|
+
onMessage;
|
|
10
|
+
channel = null;
|
|
11
|
+
constructor(onMessage) {
|
|
12
|
+
this.onMessage = onMessage;
|
|
13
|
+
}
|
|
14
|
+
start() {
|
|
15
|
+
if (typeof BroadcastChannel === 'undefined')
|
|
16
|
+
return;
|
|
17
|
+
this.channel = new BroadcastChannel(CHANNEL_NAME);
|
|
18
|
+
this.channel.addEventListener('message', (ev) => {
|
|
19
|
+
this.onMessage(ev.data);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
stop() {
|
|
23
|
+
this.channel?.close();
|
|
24
|
+
this.channel = null;
|
|
25
|
+
}
|
|
26
|
+
broadcast(msg) {
|
|
27
|
+
this.channel?.postMessage(msg);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=crossTabSync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crossTabSync.js","sourceRoot":"","sources":["../../src/auth/crossTabSync.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,YAAY,GAAG,WAAW,CAAC;AAMjC,MAAM,OAAO,YAAY;IAIJ;IAHX,OAAO,GAA4B,IAAI,CAAC;IAEhD,YACmB,SAAuC;QAAvC,cAAS,GAAT,SAAS,CAA8B;IACvD,CAAC;IAEJ,KAAK;QACH,IAAI,OAAO,gBAAgB,KAAK,WAAW;YAAE,OAAO;QACpD,IAAI,CAAC,OAAO,GAAG,IAAI,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAA+B,EAAE,EAAE;YAC3E,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,SAAS,CAAC,GAAkB;QAC1B,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idle timer. Calls back when no user activity for `idleMs`.
|
|
3
|
+
*
|
|
4
|
+
* Listens to: mousemove, keydown, touchstart, scroll, focus.
|
|
5
|
+
* Use to auto-logout after inactivity (RBI Annexure I §6.2).
|
|
6
|
+
*/
|
|
7
|
+
export interface IdleTimerConfig {
|
|
8
|
+
/** Milliseconds of inactivity before onIdle fires. */
|
|
9
|
+
idleMs: number;
|
|
10
|
+
/** Called when idle threshold is crossed. */
|
|
11
|
+
onIdle: () => void;
|
|
12
|
+
/** Called on activity AFTER idle (resumed). Optional. */
|
|
13
|
+
onResume?: () => void;
|
|
14
|
+
/** Custom events to listen to. Default is the activity set above. */
|
|
15
|
+
events?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare class IdleTimer {
|
|
18
|
+
private readonly config;
|
|
19
|
+
private timer;
|
|
20
|
+
private isIdle;
|
|
21
|
+
private readonly handler;
|
|
22
|
+
private readonly events;
|
|
23
|
+
constructor(config: IdleTimerConfig);
|
|
24
|
+
start(): void;
|
|
25
|
+
stop(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Manually report activity. Useful for events outside the default set
|
|
28
|
+
* (e.g. API success indicating server-side activity).
|
|
29
|
+
*/
|
|
30
|
+
reportActivity(): void;
|
|
31
|
+
private onActivity;
|
|
32
|
+
private resetTimer;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=idleTimer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idleTimer.d.ts","sourceRoot":"","sources":["../../src/auth/idleTimer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,qEAAqE;IACrE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAID,qBAAa,SAAS;IAMR,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;gBAEd,MAAM,EAAE,eAAe;IAKpD,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;IASZ;;;OAGG;IACH,cAAc,IAAI,IAAI;IAItB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,UAAU;CAOnB"}
|