@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.
Files changed (119) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +41 -0
  3. package/dist/audit/auditClient.d.ts +40 -0
  4. package/dist/audit/auditClient.d.ts.map +1 -0
  5. package/dist/audit/auditClient.js +180 -0
  6. package/dist/audit/auditClient.js.map +1 -0
  7. package/dist/audit/index.d.ts +9 -0
  8. package/dist/audit/index.d.ts.map +1 -0
  9. package/dist/audit/index.js +9 -0
  10. package/dist/audit/index.js.map +1 -0
  11. package/dist/audit/scrubber.d.ts +27 -0
  12. package/dist/audit/scrubber.d.ts.map +1 -0
  13. package/dist/audit/scrubber.js +111 -0
  14. package/dist/audit/scrubber.js.map +1 -0
  15. package/dist/audit/types.d.ts +42 -0
  16. package/dist/audit/types.d.ts.map +1 -0
  17. package/dist/audit/types.js +2 -0
  18. package/dist/audit/types.js.map +1 -0
  19. package/dist/auth/crossTabSync.d.ts +15 -0
  20. package/dist/auth/crossTabSync.d.ts.map +1 -0
  21. package/dist/auth/crossTabSync.js +30 -0
  22. package/dist/auth/crossTabSync.js.map +1 -0
  23. package/dist/auth/idleTimer.d.ts +34 -0
  24. package/dist/auth/idleTimer.d.ts.map +1 -0
  25. package/dist/auth/idleTimer.js +54 -0
  26. package/dist/auth/idleTimer.js.map +1 -0
  27. package/dist/auth/index.d.ts +8 -0
  28. package/dist/auth/index.d.ts.map +1 -0
  29. package/dist/auth/index.js +8 -0
  30. package/dist/auth/index.js.map +1 -0
  31. package/dist/auth/tokenManager.d.ts +47 -0
  32. package/dist/auth/tokenManager.d.ts.map +1 -0
  33. package/dist/auth/tokenManager.js +75 -0
  34. package/dist/auth/tokenManager.js.map +1 -0
  35. package/dist/compliance/csp.d.ts +20 -0
  36. package/dist/compliance/csp.d.ts.map +1 -0
  37. package/dist/compliance/csp.js +34 -0
  38. package/dist/compliance/csp.js.map +1 -0
  39. package/dist/compliance/index.d.ts +8 -0
  40. package/dist/compliance/index.d.ts.map +1 -0
  41. package/dist/compliance/index.js +8 -0
  42. package/dist/compliance/index.js.map +1 -0
  43. package/dist/compliance/safeError.d.ts +12 -0
  44. package/dist/compliance/safeError.d.ts.map +1 -0
  45. package/dist/compliance/safeError.js +39 -0
  46. package/dist/compliance/safeError.js.map +1 -0
  47. package/dist/encryption/aesgcm.d.ts +22 -0
  48. package/dist/encryption/aesgcm.d.ts.map +1 -0
  49. package/dist/encryption/aesgcm.js +67 -0
  50. package/dist/encryption/aesgcm.js.map +1 -0
  51. package/dist/encryption/envelope.d.ts +30 -0
  52. package/dist/encryption/envelope.d.ts.map +1 -0
  53. package/dist/encryption/envelope.js +46 -0
  54. package/dist/encryption/envelope.js.map +1 -0
  55. package/dist/encryption/index.d.ts +19 -0
  56. package/dist/encryption/index.d.ts.map +1 -0
  57. package/dist/encryption/index.js +19 -0
  58. package/dist/encryption/index.js.map +1 -0
  59. package/dist/encryption/pbkdf2.d.ts +21 -0
  60. package/dist/encryption/pbkdf2.d.ts.map +1 -0
  61. package/dist/encryption/pbkdf2.js +48 -0
  62. package/dist/encryption/pbkdf2.js.map +1 -0
  63. package/dist/encryption/rsaoaep.d.ts +21 -0
  64. package/dist/encryption/rsaoaep.d.ts.map +1 -0
  65. package/dist/encryption/rsaoaep.js +43 -0
  66. package/dist/encryption/rsaoaep.js.map +1 -0
  67. package/dist/encryption/util.d.ts +17 -0
  68. package/dist/encryption/util.d.ts.map +1 -0
  69. package/dist/encryption/util.js +47 -0
  70. package/dist/encryption/util.js.map +1 -0
  71. package/dist/http/createAxios.d.ts +39 -0
  72. package/dist/http/createAxios.d.ts.map +1 -0
  73. package/dist/http/createAxios.js +58 -0
  74. package/dist/http/createAxios.js.map +1 -0
  75. package/dist/http/errors.d.ts +28 -0
  76. package/dist/http/errors.d.ts.map +1 -0
  77. package/dist/http/errors.js +57 -0
  78. package/dist/http/errors.js.map +1 -0
  79. package/dist/http/index.d.ts +10 -0
  80. package/dist/http/index.d.ts.map +1 -0
  81. package/dist/http/index.js +10 -0
  82. package/dist/http/index.js.map +1 -0
  83. package/dist/http/interceptors.d.ts +30 -0
  84. package/dist/http/interceptors.d.ts.map +1 -0
  85. package/dist/http/interceptors.js +112 -0
  86. package/dist/http/interceptors.js.map +1 -0
  87. package/dist/index.d.ts +17 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +17 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/pii/index.d.ts +10 -0
  92. package/dist/pii/index.d.ts.map +1 -0
  93. package/dist/pii/index.js +10 -0
  94. package/dist/pii/index.js.map +1 -0
  95. package/dist/pii/maskers.d.ts +63 -0
  96. package/dist/pii/maskers.d.ts.map +1 -0
  97. package/dist/pii/maskers.js +186 -0
  98. package/dist/pii/maskers.js.map +1 -0
  99. package/dist/pii/patterns.d.ts +20 -0
  100. package/dist/pii/patterns.d.ts.map +1 -0
  101. package/dist/pii/patterns.js +19 -0
  102. package/dist/pii/patterns.js.map +1 -0
  103. package/dist/pii/validators.d.ts +10 -0
  104. package/dist/pii/validators.d.ts.map +1 -0
  105. package/dist/pii/validators.js +66 -0
  106. package/dist/pii/validators.js.map +1 -0
  107. package/dist/storage/index.d.ts +14 -0
  108. package/dist/storage/index.d.ts.map +1 -0
  109. package/dist/storage/index.js +14 -0
  110. package/dist/storage/index.js.map +1 -0
  111. package/dist/storage/secureStorage.d.ts +28 -0
  112. package/dist/storage/secureStorage.d.ts.map +1 -0
  113. package/dist/storage/secureStorage.js +140 -0
  114. package/dist/storage/secureStorage.js.map +1 -0
  115. package/dist/storage/types.d.ts +13 -0
  116. package/dist/storage/types.d.ts.map +1 -0
  117. package/dist/storage/types.js +2 -0
  118. package/dist/storage/types.js.map +1 -0
  119. package/package.json +95 -0
@@ -0,0 +1,54 @@
1
+ const DEFAULT_EVENTS = ['mousemove', 'keydown', 'touchstart', 'scroll', 'focus'];
2
+ export class IdleTimer {
3
+ config;
4
+ timer = null;
5
+ isIdle = false;
6
+ handler;
7
+ events;
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.events = config.events ?? DEFAULT_EVENTS;
11
+ this.handler = () => this.onActivity();
12
+ }
13
+ start() {
14
+ if (typeof window === 'undefined')
15
+ return;
16
+ for (const ev of this.events) {
17
+ window.addEventListener(ev, this.handler, { passive: true });
18
+ }
19
+ this.resetTimer();
20
+ }
21
+ stop() {
22
+ if (typeof window === 'undefined')
23
+ return;
24
+ for (const ev of this.events) {
25
+ window.removeEventListener(ev, this.handler);
26
+ }
27
+ if (this.timer)
28
+ clearTimeout(this.timer);
29
+ this.timer = null;
30
+ }
31
+ /**
32
+ * Manually report activity. Useful for events outside the default set
33
+ * (e.g. API success indicating server-side activity).
34
+ */
35
+ reportActivity() {
36
+ this.onActivity();
37
+ }
38
+ onActivity() {
39
+ if (this.isIdle) {
40
+ this.isIdle = false;
41
+ this.config.onResume?.();
42
+ }
43
+ this.resetTimer();
44
+ }
45
+ resetTimer() {
46
+ if (this.timer)
47
+ clearTimeout(this.timer);
48
+ this.timer = setTimeout(() => {
49
+ this.isIdle = true;
50
+ this.config.onIdle();
51
+ }, this.config.idleMs);
52
+ }
53
+ }
54
+ //# sourceMappingURL=idleTimer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idleTimer.js","sourceRoot":"","sources":["../../src/auth/idleTimer.ts"],"names":[],"mappings":"AAiBA,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAC;AAE1F,MAAM,OAAO,SAAS;IAMS;IALrB,KAAK,GAAyC,IAAI,CAAC;IACnD,MAAM,GAAG,KAAK,CAAC;IACN,OAAO,CAAa;IACpB,MAAM,CAAoB;IAE3C,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;IACzC,CAAC;IAED,KAAK;QACH,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,IAAI;QACF,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,CAAC,mBAAmB,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,IAAI,CAAC,KAAK;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,cAAc;QACZ,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,KAAK;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Auth — JWT token management with refresh race protection,
3
+ * idle timeout, and cross-tab logout sync.
4
+ */
5
+ export * from './tokenManager.js';
6
+ export * from './idleTimer.js';
7
+ export * from './crossTabSync.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Auth — JWT token management with refresh race protection,
3
+ * idle timeout, and cross-tab logout sync.
4
+ */
5
+ export * from './tokenManager.js';
6
+ export * from './idleTimer.js';
7
+ export * from './crossTabSync.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Token manager with refresh race protection.
3
+ *
4
+ * Key invariants:
5
+ * - Tokens live in MEMORY, not localStorage (which is XSS-readable)
6
+ * - One refresh in-flight at a time, others await it
7
+ * - Refresh failure clears tokens and fires `onLoggedOut`
8
+ */
9
+ export interface TokenPair {
10
+ accessToken: string;
11
+ refreshToken: string;
12
+ /** Unix ms when accessToken expires. Use to proactively refresh. */
13
+ accessExpiresAt: number;
14
+ }
15
+ export interface TokenManagerConfig {
16
+ /** Function that exchanges a refresh token for a new TokenPair. */
17
+ refresh: (refreshToken: string) => Promise<TokenPair>;
18
+ /** Called when tokens become unavailable (refresh failed). */
19
+ onLoggedOut?: () => void;
20
+ /** Proactively refresh when accessToken expires within this many ms. Default 30s. */
21
+ proactiveRefreshLeadMs?: number;
22
+ }
23
+ export declare class TokenManager {
24
+ private readonly config;
25
+ private tokens;
26
+ private refreshPromise;
27
+ constructor(config: TokenManagerConfig);
28
+ setTokens(pair: TokenPair): void;
29
+ clear(): void;
30
+ hasTokens(): boolean;
31
+ /**
32
+ * Get a valid access token. Triggers refresh if expired or near-expiry.
33
+ * Returns null if not logged in.
34
+ */
35
+ getAccessToken(): Promise<string | null>;
36
+ /**
37
+ * Synchronous access token getter for interceptor usage. May return an
38
+ * expired token if no refresh has been triggered yet; the 401 handler
39
+ * will catch and retry.
40
+ */
41
+ getAccessTokenSync(): string | null;
42
+ /**
43
+ * Force a refresh now. Subsequent calls share the same in-flight promise.
44
+ */
45
+ refreshOnce(): Promise<TokenPair | null>;
46
+ }
47
+ //# sourceMappingURL=tokenManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenManager.d.ts","sourceRoot":"","sources":["../../src/auth/tokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACtD,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,cAAc,CAAmC;gBAE5B,MAAM,EAAE,kBAAkB;IAEvD,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAIhC,KAAK,IAAI,IAAI;IAKb,SAAS,IAAI,OAAO;IAIpB;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAU9C;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,GAAG,IAAI;IAInC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CAoB/C"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Token manager with refresh race protection.
3
+ *
4
+ * Key invariants:
5
+ * - Tokens live in MEMORY, not localStorage (which is XSS-readable)
6
+ * - One refresh in-flight at a time, others await it
7
+ * - Refresh failure clears tokens and fires `onLoggedOut`
8
+ */
9
+ export class TokenManager {
10
+ config;
11
+ tokens = null;
12
+ refreshPromise = null;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ setTokens(pair) {
17
+ this.tokens = pair;
18
+ }
19
+ clear() {
20
+ this.tokens = null;
21
+ this.config.onLoggedOut?.();
22
+ }
23
+ hasTokens() {
24
+ return this.tokens !== null;
25
+ }
26
+ /**
27
+ * Get a valid access token. Triggers refresh if expired or near-expiry.
28
+ * Returns null if not logged in.
29
+ */
30
+ async getAccessToken() {
31
+ if (!this.tokens)
32
+ return null;
33
+ const leadMs = this.config.proactiveRefreshLeadMs ?? 30_000;
34
+ if (this.tokens.accessExpiresAt - Date.now() <= leadMs) {
35
+ const refreshed = await this.refreshOnce();
36
+ return refreshed?.accessToken ?? null;
37
+ }
38
+ return this.tokens.accessToken;
39
+ }
40
+ /**
41
+ * Synchronous access token getter for interceptor usage. May return an
42
+ * expired token if no refresh has been triggered yet; the 401 handler
43
+ * will catch and retry.
44
+ */
45
+ getAccessTokenSync() {
46
+ return this.tokens?.accessToken ?? null;
47
+ }
48
+ /**
49
+ * Force a refresh now. Subsequent calls share the same in-flight promise.
50
+ */
51
+ async refreshOnce() {
52
+ if (this.refreshPromise) {
53
+ return this.refreshPromise.catch(() => null);
54
+ }
55
+ if (!this.tokens)
56
+ return null;
57
+ const refreshToken = this.tokens.refreshToken;
58
+ this.refreshPromise = (async () => {
59
+ try {
60
+ const fresh = await this.config.refresh(refreshToken);
61
+ this.tokens = fresh;
62
+ return fresh;
63
+ }
64
+ catch (err) {
65
+ this.clear();
66
+ throw err;
67
+ }
68
+ finally {
69
+ this.refreshPromise = null;
70
+ }
71
+ })();
72
+ return this.refreshPromise.catch(() => null);
73
+ }
74
+ }
75
+ //# sourceMappingURL=tokenManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenManager.js","sourceRoot":"","sources":["../../src/auth/tokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,MAAM,OAAO,YAAY;IAIM;IAHrB,MAAM,GAAqB,IAAI,CAAC;IAChC,cAAc,GAA8B,IAAI,CAAC;IAEzD,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D,SAAS,CAAC,IAAe;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;IAC9B,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,sBAAsB,IAAI,MAAM,CAAC;QAC5D,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,MAAM,EAAE,CAAC;YACvD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC3C,OAAO,SAAS,EAAE,WAAW,IAAI,IAAI,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,CAAC,KAAK,IAAI,EAAE;YAChC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;gBACtD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;gBACpB,OAAO,KAAK,CAAC;YACf,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,MAAM,GAAG,CAAC;YACZ,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Generate a fresh nonce. Use once per page load, embed in CSP header AND
3
+ * `<script nonce="...">`, `<style nonce="...">`.
4
+ */
5
+ export declare function generateCspNonce(): string;
6
+ /**
7
+ * Build a recommended baseline CSP header value for BFSI apps.
8
+ * The caller can tighten further per their backend / CDN.
9
+ */
10
+ export interface CspOptions {
11
+ nonce: string;
12
+ /** Allowed API origins, e.g. ['https://api.example.com']. */
13
+ connectSrc?: string[];
14
+ /** Allowed image origins. Default 'self' + 'data:'. */
15
+ imgSrc?: string[];
16
+ /** Where to send violation reports. */
17
+ reportUri?: string;
18
+ }
19
+ export declare function buildCsp(opts: CspOptions): string;
20
+ //# sourceMappingURL=csp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csp.d.ts","sourceRoot":"","sources":["../../src/compliance/csp.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAoBjD"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * CSP (Content Security Policy) helpers.
3
+ * Generates per-request nonces for inline scripts/styles where unavoidable.
4
+ */
5
+ import { toBase64, randomBytes } from '../encryption/util.js';
6
+ /**
7
+ * Generate a fresh nonce. Use once per page load, embed in CSP header AND
8
+ * `<script nonce="...">`, `<style nonce="...">`.
9
+ */
10
+ export function generateCspNonce() {
11
+ return toBase64(randomBytes(16));
12
+ }
13
+ export function buildCsp(opts) {
14
+ const connectSrc = ["'self'", ...(opts.connectSrc ?? [])].join(' ');
15
+ const imgSrc = ["'self'", "data:", ...(opts.imgSrc ?? [])].join(' ');
16
+ const directives = [
17
+ `default-src 'self'`,
18
+ `script-src 'self' 'nonce-${opts.nonce}'`,
19
+ `style-src 'self' 'nonce-${opts.nonce}'`,
20
+ `img-src ${imgSrc}`,
21
+ `font-src 'self' data:`,
22
+ `connect-src ${connectSrc}`,
23
+ `object-src 'none'`,
24
+ `base-uri 'self'`,
25
+ `form-action 'self'`,
26
+ `frame-ancestors 'none'`,
27
+ `upgrade-insecure-requests`,
28
+ ];
29
+ if (opts.reportUri) {
30
+ directives.push(`report-uri ${opts.reportUri}`);
31
+ }
32
+ return directives.join('; ');
33
+ }
34
+ //# sourceMappingURL=csp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csp.js","sourceRoot":"","sources":["../../src/compliance/csp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACnC,CAAC;AAgBD,MAAM,UAAU,QAAQ,CAAC,IAAgB;IACvC,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG;QACjB,oBAAoB;QACpB,4BAA4B,IAAI,CAAC,KAAK,GAAG;QACzC,2BAA2B,IAAI,CAAC,KAAK,GAAG;QACxC,WAAW,MAAM,EAAE;QACnB,uBAAuB;QACvB,eAAe,UAAU,EAAE;QAC3B,mBAAmB;QACnB,iBAAiB;QACjB,oBAAoB;QACpB,wBAAwB;QACxB,2BAA2B;KAC5B,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Compliance helpers — CSP nonce, safe-error envelope, locale-aware utilities.
3
+ *
4
+ * v0.1: minimal scaffolding. Full implementation in a follow-up.
5
+ */
6
+ export * from './csp.js';
7
+ export * from './safeError.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compliance/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Compliance helpers — CSP nonce, safe-error envelope, locale-aware utilities.
3
+ *
4
+ * v0.1: minimal scaffolding. Full implementation in a follow-up.
5
+ */
6
+ export * from './csp.js';
7
+ export * from './safeError.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compliance/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface SafeErrorView {
2
+ title: string;
3
+ description: string;
4
+ /** Short ref code to show user; correlate to log entry. */
5
+ ref: string;
6
+ }
7
+ /**
8
+ * Translate an ApiError into a user-safe view. Caller passes a `t()` function
9
+ * so messages can be i18n'd.
10
+ */
11
+ export declare function toSafeView(err: unknown, t: (key: string, params?: Record<string, unknown>) => string): SafeErrorView;
12
+ //# sourceMappingURL=safeError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeError.d.ts","sourceRoot":"","sources":["../../src/compliance/safeError.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,aAAa,CAyBpH"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Safe error envelope. Maps internal errors to user-facing messages.
3
+ * See packages/claude-toolkit/skills/bfsi-error-message/SKILL.md for rationale.
4
+ */
5
+ import { generateErrorRef } from '../audit/auditClient.js';
6
+ /**
7
+ * Translate an ApiError into a user-safe view. Caller passes a `t()` function
8
+ * so messages can be i18n'd.
9
+ */
10
+ export function toSafeView(err, t) {
11
+ const ref = generateErrorRef();
12
+ if (isApiError(err)) {
13
+ switch (err.kind) {
14
+ case 'network':
15
+ return { title: t('errors.network.title'), description: t('errors.network.description'), ref };
16
+ case 'timeout':
17
+ return { title: t('errors.timeout.title'), description: t('errors.timeout.description'), ref };
18
+ case 'unauthorized':
19
+ return { title: t('errors.session_expired.title'), description: t('errors.session_expired.description'), ref };
20
+ case 'forbidden':
21
+ return { title: t('errors.forbidden.title'), description: t('errors.forbidden.description'), ref };
22
+ case 'not_found':
23
+ return { title: t('errors.not_found.title'), description: t('errors.not_found.description'), ref };
24
+ case 'validation':
25
+ return { title: t('errors.validation.title'), description: t('errors.validation.description'), ref };
26
+ case 'rate_limited':
27
+ return { title: t('errors.rate_limited.title'), description: t('errors.rate_limited.description'), ref };
28
+ case 'server_error':
29
+ return { title: t('errors.server.title'), description: t('errors.server.description', { ref }), ref };
30
+ default:
31
+ return { title: t('errors.generic.title'), description: t('errors.generic.description', { ref }), ref };
32
+ }
33
+ }
34
+ return { title: t('errors.generic.title'), description: t('errors.generic.description', { ref }), ref };
35
+ }
36
+ function isApiError(err) {
37
+ return !!err && typeof err === 'object' && err.name === 'ApiError';
38
+ }
39
+ //# sourceMappingURL=safeError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeError.js","sourceRoot":"","sources":["../../src/compliance/safeError.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAU3D;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,CAA4D;IACnG,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,SAAS;gBACZ,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,4BAA4B,CAAC,EAAE,GAAG,EAAE,CAAC;YACjG,KAAK,SAAS;gBACZ,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,4BAA4B,CAAC,EAAE,GAAG,EAAE,CAAC;YACjG,KAAK,cAAc;gBACjB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,8BAA8B,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,oCAAoC,CAAC,EAAE,GAAG,EAAE,CAAC;YACjH,KAAK,WAAW;gBACd,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,wBAAwB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,8BAA8B,CAAC,EAAE,GAAG,EAAE,CAAC;YACrG,KAAK,WAAW;gBACd,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,wBAAwB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,8BAA8B,CAAC,EAAE,GAAG,EAAE,CAAC;YACrG,KAAK,YAAY;gBACf,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,yBAAyB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,+BAA+B,CAAC,EAAE,GAAG,EAAE,CAAC;YACvG,KAAK,cAAc;gBACjB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,2BAA2B,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,iCAAiC,CAAC,EAAE,GAAG,EAAE,CAAC;YAC3G,KAAK,cAAc;gBACjB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,qBAAqB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,2BAA2B,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;YACxG;gBACE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,4BAA4B,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;QAC5G,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,4BAA4B,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;AAC1G,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAK,GAAyB,CAAC,IAAI,KAAK,UAAU,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,22 @@
1
+ export type AesGcmKey = CryptoKey;
2
+ export declare function generateKey(): Promise<AesGcmKey>;
3
+ /**
4
+ * Import a raw 32-byte key. Use when you've derived a key (e.g. from PBKDF2)
5
+ * or received one securely from the backend.
6
+ */
7
+ export declare function importRawKey(rawBytes: Uint8Array): Promise<AesGcmKey>;
8
+ export declare function exportRawKey(key: AesGcmKey): Promise<Uint8Array>;
9
+ /**
10
+ * Encrypt a string. Returns base64( IV || ciphertext+tag ).
11
+ */
12
+ export declare function encrypt(key: AesGcmKey, plaintext: string): Promise<string>;
13
+ /**
14
+ * Decrypt a base64 string produced by `encrypt`. Throws on tamper.
15
+ */
16
+ export declare function decrypt(key: AesGcmKey, blob: string): Promise<string>;
17
+ /**
18
+ * Encrypt arbitrary bytes (e.g. another key, file content).
19
+ */
20
+ export declare function encryptBytes(key: AesGcmKey, plaintext: Uint8Array): Promise<string>;
21
+ export declare function decryptBytes(key: AesGcmKey, blob: string): Promise<Uint8Array>;
22
+ //# sourceMappingURL=aesgcm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aesgcm.d.ts","sourceRoot":"","sources":["../../src/encryption/aesgcm.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC;AAElC,wBAAsB,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAEtD;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAK3E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAEtE;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMhF;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW3E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzF;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAQpF"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * AES-GCM 256 symmetric encryption.
3
+ *
4
+ * Output format: base64( IV || ciphertext || authTag )
5
+ * IV is 12 bytes (96 bits, GCM standard).
6
+ * AuthTag is appended by Web Crypto (16 bytes).
7
+ *
8
+ * Decryption verifies the authTag — tampering produces a thrown error.
9
+ */
10
+ import { toBase64, fromBase64, toBytes, fromBytes, randomBytes, concatBytes } from './util.js';
11
+ const ALGO = { name: 'AES-GCM', length: 256 };
12
+ const IV_LENGTH = 12;
13
+ export async function generateKey() {
14
+ return crypto.subtle.generateKey(ALGO, true, ['encrypt', 'decrypt']);
15
+ }
16
+ /**
17
+ * Import a raw 32-byte key. Use when you've derived a key (e.g. from PBKDF2)
18
+ * or received one securely from the backend.
19
+ */
20
+ export async function importRawKey(rawBytes) {
21
+ if (rawBytes.length !== 32) {
22
+ throw new Error(`AES-GCM 256 requires 32 bytes, got ${rawBytes.length}`);
23
+ }
24
+ return crypto.subtle.importKey('raw', rawBytes, ALGO, true, ['encrypt', 'decrypt']);
25
+ }
26
+ export async function exportRawKey(key) {
27
+ return new Uint8Array(await crypto.subtle.exportKey('raw', key));
28
+ }
29
+ /**
30
+ * Encrypt a string. Returns base64( IV || ciphertext+tag ).
31
+ */
32
+ export async function encrypt(key, plaintext) {
33
+ const iv = randomBytes(IV_LENGTH);
34
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, toBytes(plaintext)));
35
+ return toBase64(concatBytes(iv, ciphertext));
36
+ }
37
+ /**
38
+ * Decrypt a base64 string produced by `encrypt`. Throws on tamper.
39
+ */
40
+ export async function decrypt(key, blob) {
41
+ const bytes = fromBase64(blob);
42
+ if (bytes.length < IV_LENGTH + 16) {
43
+ throw new Error('ciphertext too short');
44
+ }
45
+ const iv = bytes.slice(0, IV_LENGTH);
46
+ const ciphertext = bytes.slice(IV_LENGTH);
47
+ const plaintext = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext));
48
+ return fromBytes(plaintext);
49
+ }
50
+ /**
51
+ * Encrypt arbitrary bytes (e.g. another key, file content).
52
+ */
53
+ export async function encryptBytes(key, plaintext) {
54
+ const iv = randomBytes(IV_LENGTH);
55
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext));
56
+ return toBase64(concatBytes(iv, ciphertext));
57
+ }
58
+ export async function decryptBytes(key, blob) {
59
+ const bytes = fromBase64(blob);
60
+ if (bytes.length < IV_LENGTH + 16) {
61
+ throw new Error('ciphertext too short');
62
+ }
63
+ const iv = bytes.slice(0, IV_LENGTH);
64
+ const ciphertext = bytes.slice(IV_LENGTH);
65
+ return new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext));
66
+ }
67
+ //# sourceMappingURL=aesgcm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aesgcm.js","sourceRoot":"","sources":["../../src/encryption/aesgcm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { RsaPublicKey, RsaPrivateKey } from './rsaoaep.js';
2
+ export interface EnvelopeCiphertext {
3
+ /** AES-GCM ciphertext of the data, base64. */
4
+ ciphertext: string;
5
+ /** RSA-OAEP-encrypted DEK, base64. */
6
+ encryptedDek: string;
7
+ }
8
+ /**
9
+ * Encrypt plaintext with envelope encryption.
10
+ *
11
+ * Flow:
12
+ * 1. Generate a fresh AES-GCM key (the DEK)
13
+ * 2. Encrypt the plaintext with the DEK
14
+ * 3. Export the DEK as raw bytes
15
+ * 4. Encrypt the DEK bytes with the master RSA public key (the KEK)
16
+ * 5. Return both ciphertexts; throw away the DEK
17
+ */
18
+ export declare function encrypt(masterPublicKey: RsaPublicKey, plaintext: string): Promise<EnvelopeCiphertext>;
19
+ /**
20
+ * Decrypt envelope ciphertext. Requires the master private key.
21
+ * In production, this typically happens on the backend (HSM); the client
22
+ * gets either the decrypted plaintext or a temporarily-issued DEK.
23
+ */
24
+ export declare function decrypt(masterPrivateKey: RsaPrivateKey, envelope: EnvelopeCiphertext): Promise<string>;
25
+ /**
26
+ * Decrypt with a pre-unwrapped DEK (when the backend has unwrapped the DEK
27
+ * and given it to the client to do bulk decryption locally).
28
+ */
29
+ export declare function decryptWithDek(dekBytes: Uint8Array, ciphertext: string): Promise<string>;
30
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/encryption/envelope.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,eAAe,EAAE,YAAY,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAM7B;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,gBAAgB,EAAE,aAAa,EAC/B,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,UAAU,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAGjB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Envelope encryption: encrypt data with a per-record DEK, then encrypt
3
+ * the DEK with a master KEK (RSA-OAEP). This is the BFSI-standard pattern
4
+ * because:
5
+ * - Rotating the KEK only requires re-encrypting tiny DEKs, not large data
6
+ * - Each record has its own data key — compromise of one doesn't expose others
7
+ * - The master private KEK never leaves the HSM/KMS on the backend
8
+ */
9
+ import * as aesgcm from './aesgcm.js';
10
+ import * as rsaoaep from './rsaoaep.js';
11
+ /**
12
+ * Encrypt plaintext with envelope encryption.
13
+ *
14
+ * Flow:
15
+ * 1. Generate a fresh AES-GCM key (the DEK)
16
+ * 2. Encrypt the plaintext with the DEK
17
+ * 3. Export the DEK as raw bytes
18
+ * 4. Encrypt the DEK bytes with the master RSA public key (the KEK)
19
+ * 5. Return both ciphertexts; throw away the DEK
20
+ */
21
+ export async function encrypt(masterPublicKey, plaintext) {
22
+ const dek = await aesgcm.generateKey();
23
+ const ciphertext = await aesgcm.encrypt(dek, plaintext);
24
+ const dekBytes = await aesgcm.exportRawKey(dek);
25
+ const encryptedDek = await rsaoaep.encrypt(masterPublicKey, dekBytes);
26
+ return { ciphertext, encryptedDek };
27
+ }
28
+ /**
29
+ * Decrypt envelope ciphertext. Requires the master private key.
30
+ * In production, this typically happens on the backend (HSM); the client
31
+ * gets either the decrypted plaintext or a temporarily-issued DEK.
32
+ */
33
+ export async function decrypt(masterPrivateKey, envelope) {
34
+ const dekBytes = await rsaoaep.decrypt(masterPrivateKey, envelope.encryptedDek);
35
+ const dek = await aesgcm.importRawKey(dekBytes);
36
+ return aesgcm.decrypt(dek, envelope.ciphertext);
37
+ }
38
+ /**
39
+ * Decrypt with a pre-unwrapped DEK (when the backend has unwrapped the DEK
40
+ * and given it to the client to do bulk decryption locally).
41
+ */
42
+ export async function decryptWithDek(dekBytes, ciphertext) {
43
+ const dek = await aesgcm.importRawKey(dekBytes);
44
+ return aesgcm.decrypt(dek, ciphertext);
45
+ }
46
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/encryption/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAUxC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,eAA6B,EAC7B,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IACtE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,gBAA+B,EAC/B,QAA4B;IAE5B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IAChF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAoB,EACpB,UAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Encryption module — Web Crypto wrappers for AES-GCM, RSA-OAEP, PBKDF2.
3
+ *
4
+ * Always use these wrappers rather than calling `crypto.subtle` directly.
5
+ * They handle IV/nonce generation, framing, and base64 transport correctly.
6
+ *
7
+ * Anti-patterns to avoid (see references/bfsi-encrypt-helper):
8
+ * - Math.random() for IVs / keys
9
+ * - Reusing IVs across messages
10
+ * - AES-ECB
11
+ * - md5 / sha1 for security
12
+ * - btoa() / XOR / custom "scrambling" as encryption
13
+ */
14
+ export * as aesgcm from './aesgcm.js';
15
+ export * as rsaoaep from './rsaoaep.js';
16
+ export * as pbkdf2 from './pbkdf2.js';
17
+ export * as envelope from './envelope.js';
18
+ export * from './util.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/encryption/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,cAAc,WAAW,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Encryption module — Web Crypto wrappers for AES-GCM, RSA-OAEP, PBKDF2.
3
+ *
4
+ * Always use these wrappers rather than calling `crypto.subtle` directly.
5
+ * They handle IV/nonce generation, framing, and base64 transport correctly.
6
+ *
7
+ * Anti-patterns to avoid (see references/bfsi-encrypt-helper):
8
+ * - Math.random() for IVs / keys
9
+ * - Reusing IVs across messages
10
+ * - AES-ECB
11
+ * - md5 / sha1 for security
12
+ * - btoa() / XOR / custom "scrambling" as encryption
13
+ */
14
+ export * as aesgcm from './aesgcm.js';
15
+ export * as rsaoaep from './rsaoaep.js';
16
+ export * as pbkdf2 from './pbkdf2.js';
17
+ export * as envelope from './envelope.js';
18
+ export * from './util.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/encryption/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,cAAc,WAAW,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface DeriveKeyOptions {
2
+ iterations?: number;
3
+ /** Output length in bits. Default 256 (32 bytes). */
4
+ outputLengthBits?: number;
5
+ /** Algorithm key will be used for. Default AES-GCM 256. */
6
+ algorithm?: 'AES-GCM' | 'HMAC';
7
+ }
8
+ /**
9
+ * Derive an AES-GCM key from a password and salt.
10
+ * Salt must be stored alongside the ciphertext (it's not secret, but it's per-record).
11
+ */
12
+ export declare function deriveKey(password: string, salt: Uint8Array, opts?: DeriveKeyOptions): Promise<CryptoKey>;
13
+ /**
14
+ * Derive raw bytes (not a CryptoKey) — useful when you need to interoperate
15
+ * with code expecting a raw byte string.
16
+ */
17
+ export declare function deriveBytes(password: string, salt: Uint8Array, opts?: {
18
+ iterations?: number;
19
+ outputLengthBits?: number;
20
+ }): Promise<Uint8Array>;
21
+ //# sourceMappingURL=pbkdf2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbkdf2.d.ts","sourceRoot":"","sources":["../../src/encryption/pbkdf2.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,SAAS,CAAC,CA4BpB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAAC,UAAU,CAAC,CA2BrB"}