@aictrl/hush 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.
@@ -0,0 +1,152 @@
1
+ import blessed from 'blessed';
2
+ import contrib from 'blessed-contrib';
3
+ /**
4
+ * hush 🛡️ Dashboard v2 - Terminal Edition
5
+ * Aligned with the official brand book and dashboard mockup.
6
+ */
7
+ export class Dashboard {
8
+ screen;
9
+ grid;
10
+ // Components
11
+ log;
12
+ piiBreakdown;
13
+ vaultGauge;
14
+ latencySpark;
15
+ // Hero Stats (Boxes)
16
+ statBoxes;
17
+ // State
18
+ stats = {
19
+ redactedCount: 0,
20
+ requestCount: 0,
21
+ leaks: 0,
22
+ types: new Map(),
23
+ latency: [],
24
+ };
25
+ constructor() {
26
+ this.screen = blessed.screen({
27
+ smartCSR: true,
28
+ title: 'hush 🛡️ | Semantic Security Gateway'
29
+ });
30
+ this.grid = new contrib.grid({ rows: 12, cols: 12, screen: this.screen });
31
+ // --- ROW 1: HERO STATS (0-2) ---
32
+ this.statBoxes = {
33
+ protection: this.grid.set(0, 0, 2, 3, blessed.box, {
34
+ label: ' PROTECTION ',
35
+ content: '{center}{green-fg}ACTIVE{/green-fg}{/center}\n{center}127.0.0.1:4000{/center}',
36
+ tags: true,
37
+ border: { type: 'line', fg: 'green' }
38
+ }),
39
+ piiCount: this.grid.set(0, 3, 2, 3, blessed.box, {
40
+ label: ' PII PROTECTED ',
41
+ content: '{center}{bold}0{/bold}{/center}',
42
+ tags: true,
43
+ border: { type: 'line', fg: 'blue' }
44
+ }),
45
+ activePatterns: this.grid.set(0, 6, 2, 3, blessed.box, {
46
+ label: ' PATTERNS ',
47
+ content: '{center}{bold}6{/bold}{/center}',
48
+ tags: true,
49
+ border: { type: 'line', fg: 'yellow' }
50
+ }),
51
+ leakCount: this.grid.set(0, 9, 2, 3, blessed.box, {
52
+ label: ' LEAKS ',
53
+ content: '{center}{bold}0{/bold}{/center}',
54
+ tags: true,
55
+ border: { type: 'line', fg: 'white' }
56
+ })
57
+ };
58
+ // --- ROW 2: LIVE FEED & TYPE BREAKDOWN (2-9) ---
59
+ this.log = this.grid.set(2, 0, 7, 8, contrib.log, {
60
+ fg: 'green',
61
+ selectedFg: 'green',
62
+ label: ' Live Redaction Feed ',
63
+ border: { type: 'line', fg: 'cyan' }
64
+ });
65
+ this.piiBreakdown = this.grid.set(2, 8, 7, 4, contrib.bar, {
66
+ label: ' PII by Type ',
67
+ barWidth: 4,
68
+ barSpacing: 6,
69
+ xOffset: 0,
70
+ maxHeight: 10,
71
+ });
72
+ // --- ROW 3: VAULT & LATENCY (9-12) ---
73
+ this.vaultGauge = this.grid.set(9, 0, 3, 4, contrib.gauge, {
74
+ label: ' Vault Capacity ',
75
+ percent: [0],
76
+ });
77
+ this.latencySpark = this.grid.set(9, 4, 3, 8, contrib.sparkline, {
78
+ label: ' Redaction Latency (ms) ',
79
+ tags: true,
80
+ style: { fg: 'blue' }
81
+ });
82
+ // Quit keys
83
+ this.screen.key(['escape', 'q', 'C-c'], () => {
84
+ return process.exit(0);
85
+ });
86
+ this.render();
87
+ }
88
+ logRedaction(type, token) {
89
+ this.stats.redactedCount++;
90
+ this.stats.types.set(type, (this.stats.types.get(type) || 0) + 1);
91
+ // Log entry with color highlighting
92
+ const typeColor = this.getTypeColor(type);
93
+ this.log.log(`{${typeColor}-fg}${type.padEnd(5)}{/${typeColor}-fg} | {grey-fg}PROTECTED{/grey-fg} → {white-fg}${token}{/white-fg}`);
94
+ this.updateUI();
95
+ }
96
+ logRequest(path, durationMs = 0) {
97
+ this.stats.requestCount++;
98
+ if (durationMs > 0) {
99
+ this.stats.latency.push(durationMs);
100
+ if (this.stats.latency.length > 50)
101
+ this.stats.latency.shift();
102
+ }
103
+ this.updateUI();
104
+ }
105
+ getTypeColor(type) {
106
+ const colors = {
107
+ 'EML': 'blue',
108
+ 'IP4': 'yellow',
109
+ 'SEC': 'red',
110
+ 'CC': 'magenta',
111
+ 'PHN': 'green'
112
+ };
113
+ return colors[type] || 'white';
114
+ }
115
+ updateUI() {
116
+ // Update Stat Boxes
117
+ this.statBoxes.piiCount.setContent(`{center}{bold}${this.stats.redactedCount}{/bold}{/center}`);
118
+ this.statBoxes.protection.setContent(`{center}{green-fg}ACTIVE{/green-fg}{/center}\n{center}${this.stats.requestCount} REQS{/center}`);
119
+ // Update Breakdown Bar Chart
120
+ const barData = {
121
+ titles: Array.from(this.stats.types.keys()),
122
+ data: Array.from(this.stats.types.values())
123
+ };
124
+ if (barData.titles.length > 0) {
125
+ this.piiBreakdown.setData(barData);
126
+ }
127
+ // Update Latency Sparkline
128
+ if (this.stats.latency.length > 0) {
129
+ this.latencySpark.setData(['Latency'], [this.stats.latency]);
130
+ }
131
+ // Update Vault Gauge (Simulated/Placeholder for now)
132
+ const vaultPercent = Math.min(100, Math.round((this.stats.redactedCount / 1000) * 100));
133
+ this.vaultGauge.setData([vaultPercent]);
134
+ this.render();
135
+ }
136
+ render() {
137
+ this.screen.render();
138
+ }
139
+ /**
140
+ * Get current dashboard statistics (for testing and programmatic access).
141
+ */
142
+ getStats() {
143
+ return {
144
+ redactedCount: this.stats.redactedCount,
145
+ requestCount: this.stats.requestCount,
146
+ leaks: this.stats.leaks,
147
+ types: new Map(this.stats.types),
148
+ latency: [...this.stats.latency],
149
+ };
150
+ }
151
+ }
152
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/lib/dashboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import pino from 'pino';
2
+ /**
3
+ * Root logger instance.
4
+ *
5
+ * - JSON output in production (compatible with Google Cloud Logging)
6
+ * - pino-pretty in development for human-readable output
7
+ * - Redacts sensitive fields (tokens, passwords, API keys)
8
+ * - Configurable via LOG_LEVEL env var
9
+ */
10
+ export declare const logger: pino.Logger<never, boolean>;
11
+ /**
12
+ * Create a child logger scoped to a component.
13
+ *
14
+ * @example
15
+ * const log = createLogger('ws');
16
+ * log.info({ clientId }, 'Client connected');
17
+ */
18
+ export declare function createLogger(component: string): pino.Logger<never, boolean>;
19
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAiBxB;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,6BAmCjB,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,+BAE7C"}
@@ -0,0 +1,69 @@
1
+ import pino from 'pino';
2
+ const isProduction = process.env.NODE_ENV === 'production';
3
+ const isDashboard = process.env.HUSH_DASHBOARD === 'true' || process.argv.includes('--dashboard');
4
+ /**
5
+ * Pino level → Google Cloud Logging severity mapping.
6
+ */
7
+ const severityMap = {
8
+ trace: 'DEBUG',
9
+ debug: 'DEBUG',
10
+ info: 'INFO',
11
+ warn: 'WARNING',
12
+ error: 'ERROR',
13
+ fatal: 'CRITICAL',
14
+ };
15
+ /**
16
+ * Root logger instance.
17
+ *
18
+ * - JSON output in production (compatible with Google Cloud Logging)
19
+ * - pino-pretty in development for human-readable output
20
+ * - Redacts sensitive fields (tokens, passwords, API keys)
21
+ * - Configurable via LOG_LEVEL env var
22
+ */
23
+ export const logger = pino({
24
+ level: process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug'),
25
+ formatters: {
26
+ level(label) {
27
+ return { severity: severityMap[label] || 'DEFAULT', level: label };
28
+ },
29
+ },
30
+ redact: {
31
+ paths: [
32
+ 'token',
33
+ 'accessToken',
34
+ 'refreshToken',
35
+ 'apiKey',
36
+ 'password',
37
+ 'idToken',
38
+ 'authorization',
39
+ 'secret',
40
+ 'clientSecret',
41
+ '*.token',
42
+ '*.accessToken',
43
+ '*.refreshToken',
44
+ '*.apiKey',
45
+ '*.password',
46
+ '*.idToken',
47
+ '*.authorization',
48
+ '*.secret',
49
+ '*.clientSecret',
50
+ ],
51
+ censor: '[REDACTED]',
52
+ },
53
+ // Security: In dashboard mode, we MUST avoid stdout/stderr to prevent TUI corruption.
54
+ // We use standard pino-pretty for dev, and no transport for prod.
55
+ transport: isDashboard
56
+ ? { target: 'pino/file', options: { destination: 'hush.log', mkdir: true } }
57
+ : (isProduction ? undefined : { target: 'pino-pretty', options: { colorize: true } }),
58
+ });
59
+ /**
60
+ * Create a child logger scoped to a component.
61
+ *
62
+ * @example
63
+ * const log = createLogger('ws');
64
+ * log.info({ clientId }, 'Client connected');
65
+ */
66
+ export function createLogger(component) {
67
+ return logger.child({ component });
68
+ }
69
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAC3D,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AAElG;;GAEG;AACH,MAAM,WAAW,GAA2B;IAC1C,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,UAAU;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,UAAU,EAAE;QACV,KAAK,CAAC,KAAa;YACjB,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACrE,CAAC;KACF;IACD,MAAM,EAAE;QACN,KAAK,EAAE;YACL,OAAO;YACP,aAAa;YACb,cAAc;YACd,QAAQ;YACR,UAAU;YACV,SAAS;YACT,eAAe;YACf,QAAQ;YACR,cAAc;YACd,SAAS;YACT,eAAe;YACf,gBAAgB;YAChB,UAAU;YACV,YAAY;YACZ,WAAW;YACX,iBAAiB;YACjB,UAAU;YACV,gBAAgB;SACjB;QACD,MAAM,EAAE,YAAY;KACrB;IACD,sFAAsF;IACtF,kEAAkE;IAClE,SAAS,EAAE,WAAW;QACpB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC5E,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;CACxF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Semantic Redactor Middleware
3
+ *
4
+ * Identifies and swaps PII (emails, keys, IP addresses) for persistent tokens.
5
+ * Interoperable with TokenVault for re-hydration.
6
+ */
7
+ /**
8
+ * Result of a redaction operation.
9
+ */
10
+ export interface RedactionResult {
11
+ /** The redacted content (string or object) */
12
+ content: any;
13
+ /** Whether any redaction took place */
14
+ hasRedacted: boolean;
15
+ /** Map of tokens to their original values */
16
+ tokens: Map<string, string>;
17
+ }
18
+ /**
19
+ * Redactor class for identifying and masking sensitive information.
20
+ */
21
+ export declare class Redactor {
22
+ /**
23
+ * Common PII Regex patterns.
24
+ */
25
+ private static readonly PATTERNS;
26
+ /**
27
+ * Redact sensitive information from a JSON object or string.
28
+ *
29
+ * @param input - The string or object to redact.
30
+ * @returns A RedactionResult containing the masked content and the token map.
31
+ */
32
+ redact(input: any): RedactionResult;
33
+ }
34
+ //# sourceMappingURL=redactor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactor.d.ts","sourceRoot":"","sources":["../../src/middleware/redactor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,OAAO,EAAE,GAAG,CAAC;IACb,uCAAuC;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAa9B;IAEF;;;;;OAKG;IACI,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,eAAe;CAoG3C"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Semantic Redactor Middleware
3
+ *
4
+ * Identifies and swaps PII (emails, keys, IP addresses) for persistent tokens.
5
+ * Interoperable with TokenVault for re-hydration.
6
+ */
7
+ /**
8
+ * Redactor class for identifying and masking sensitive information.
9
+ */
10
+ export class Redactor {
11
+ /**
12
+ * Common PII Regex patterns.
13
+ */
14
+ static PATTERNS = {
15
+ /** Email regex (ReDoS-safe: single character class with no nested quantifiers) */
16
+ EMAIL: /\b[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,253}\.[a-zA-Z]{2,63}\b/g,
17
+ /** IPv4 address regex */
18
+ IPV4: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
19
+ /** IPv6 address regex */
20
+ IPV6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/g,
21
+ /** Generic API Key / Secret pattern (robust version) */
22
+ SECRET: /(?:api[-_]?key|secret|password|token|bearer|auth)["']?\s*[:=]\s*["']?([a-zA-Z0-9\-_!@#$%^&*()=+]{16,})["']?/gi,
23
+ /** Credit Card (basic) */
24
+ CREDIT_CARD: /\b(?:\d[ -]*?){13,16}\b/g,
25
+ /** Phone Numbers (robust version) */
26
+ PHONE: /(?:^|[\s:;])(?:\+\d{1,3}[-. ]?)?\(?\d{2,4}\)?[-. ]\d{3,4}[-. ]\d{3,4}(?:\s*(?:ext|x)\s*\d+)?/g,
27
+ };
28
+ /**
29
+ * Redact sensitive information from a JSON object or string.
30
+ *
31
+ * @param input - The string or object to redact.
32
+ * @returns A RedactionResult containing the masked content and the token map.
33
+ */
34
+ redact(input) {
35
+ const tokens = new Map();
36
+ let hasRedacted = false;
37
+ // Deep copy input for safe modification if it's an object
38
+ const output = typeof input === 'object' && input !== null
39
+ ? JSON.parse(JSON.stringify(input))
40
+ : input;
41
+ const SENSITIVE_KEYS = ['apikey', 'secret', 'password', 'token', 'bearer', 'auth', 'credential'];
42
+ const process = (node, keyName) => {
43
+ // Check if the current key is sensitive
44
+ if (keyName && typeof node === 'string') {
45
+ const normalizedKey = keyName.toLowerCase().replace(/[-_]/g, '');
46
+ if (SENSITIVE_KEYS.some(k => normalizedKey.includes(k))) {
47
+ hasRedacted = true;
48
+ const token = `[SENSITIVE_SECRET_${tokens.size + 1}]`;
49
+ tokens.set(token, node);
50
+ return token;
51
+ }
52
+ }
53
+ if (typeof node === 'string') {
54
+ let text = node;
55
+ // Redact Emails
56
+ text = text.replace(Redactor.PATTERNS.EMAIL, (match) => {
57
+ hasRedacted = true;
58
+ const token = `[USER_EMAIL_${tokens.size + 1}]`;
59
+ tokens.set(token, match);
60
+ return token;
61
+ });
62
+ // Redact IP Addresses (v4)
63
+ text = text.replace(Redactor.PATTERNS.IPV4, (match) => {
64
+ hasRedacted = true;
65
+ const token = `[NETWORK_IP_${tokens.size + 1}]`;
66
+ tokens.set(token, match);
67
+ return token;
68
+ });
69
+ // Redact IP Addresses (v6)
70
+ text = text.replace(Redactor.PATTERNS.IPV6, (match) => {
71
+ hasRedacted = true;
72
+ const token = `[NETWORK_IP_V6_${tokens.size + 1}]`;
73
+ tokens.set(token, match);
74
+ return token;
75
+ });
76
+ // Redact Secrets in text (e.g. "api_key=...")
77
+ text = text.replace(Redactor.PATTERNS.SECRET, (match, p1) => {
78
+ hasRedacted = true;
79
+ const token = `[SENSITIVE_SECRET_${tokens.size + 1}]`;
80
+ tokens.set(token, p1);
81
+ return match.replace(p1, token);
82
+ });
83
+ // Redact Credit Cards
84
+ text = text.replace(Redactor.PATTERNS.CREDIT_CARD, (match) => {
85
+ hasRedacted = true;
86
+ const token = `[PAYMENT_CARD_${tokens.size + 1}]`;
87
+ tokens.set(token, match);
88
+ return token;
89
+ });
90
+ // Redact Phone Numbers
91
+ text = text.replace(Redactor.PATTERNS.PHONE, (match) => {
92
+ hasRedacted = true;
93
+ const token = `[PHONE_NUMBER_${tokens.size + 1}]`;
94
+ tokens.set(token, match);
95
+ return token;
96
+ });
97
+ return text;
98
+ }
99
+ if (Array.isArray(node)) {
100
+ return node.map(item => process(item));
101
+ }
102
+ if (node !== null && typeof node === 'object') {
103
+ const obj = {};
104
+ for (const [key, value] of Object.entries(node)) {
105
+ obj[key] = process(value, key);
106
+ }
107
+ return obj;
108
+ }
109
+ return node;
110
+ };
111
+ const redactedContent = process(output);
112
+ return {
113
+ content: redactedContent,
114
+ hasRedacted,
115
+ tokens
116
+ };
117
+ }
118
+ }
119
+ //# sourceMappingURL=redactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactor.js","sourceRoot":"","sources":["../../src/middleware/redactor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Local Token Vault
3
+ *
4
+ * Persistently stores the original cleartext values for tokens generated by the Redactor.
5
+ * Allows the local Proxy to re-hydrate results before returning them to the agent.
6
+ */
7
+ /**
8
+ * Vault for storing and re-applying redacted tokens.
9
+ */
10
+ export declare class TokenVault {
11
+ private vault;
12
+ private readonly ttl;
13
+ /**
14
+ * @param ttlMs - Time to live in milliseconds (default: 1 hour)
15
+ */
16
+ constructor(ttlMs?: number);
17
+ /**
18
+ * Save a set of tokens and their original values to the vault.
19
+ *
20
+ * @param tokens - Map of tokens to cleartext values.
21
+ */
22
+ saveTokens(tokens: Map<string, string>): void;
23
+ /**
24
+ * Re-hydrate a string or object containing tokens back into cleartext.
25
+ *
26
+ * @param input - The string or object containing tokens.
27
+ * @returns The original cleartext content.
28
+ */
29
+ rehydrate(input: any): any;
30
+ /**
31
+ * Create a stateful rehydrator for processing streaming chunks.
32
+ * Handles cases where tokens are split across chunks.
33
+ */
34
+ createStreamingRehydrator(): (chunk: string) => string;
35
+ /**
36
+ * Remove expired tokens from the vault.
37
+ */
38
+ private prune;
39
+ /**
40
+ * Get the original value for a specific token.
41
+ *
42
+ * @param token - The token to look up.
43
+ * @returns The original cleartext or undefined if not found.
44
+ */
45
+ get(token: string): string | undefined;
46
+ /**
47
+ * Clear the vault for a new session.
48
+ */
49
+ clear(): void;
50
+ /**
51
+ * Get the number of tokens currently in the vault.
52
+ */
53
+ get size(): number;
54
+ }
55
+ //# sourceMappingURL=token-vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-vault.d.ts","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAgE;IAC7E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;OAEG;gBACS,KAAK,GAAE,MAAuB;IAI1C;;;;OAIG;IACI,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAQpD;;;;;OAKG;IACI,SAAS,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG;IA0CjC;;;OAGG;IACI,yBAAyB,KAGtB,OAAO,MAAM,KAAG,MAAM;IA6BhC;;OAEG;IACH,OAAO,CAAC,KAAK;IASb;;;;;OAKG;IACI,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7C;;OAEG;IACI,KAAK,IAAI,IAAI;IAIpB;;OAEG;IACH,IAAW,IAAI,IAAI,MAAM,CAExB;CACF"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Local Token Vault
3
+ *
4
+ * Persistently stores the original cleartext values for tokens generated by the Redactor.
5
+ * Allows the local Proxy to re-hydrate results before returning them to the agent.
6
+ */
7
+ /**
8
+ * Vault for storing and re-applying redacted tokens.
9
+ */
10
+ export class TokenVault {
11
+ vault = new Map();
12
+ ttl;
13
+ /**
14
+ * @param ttlMs - Time to live in milliseconds (default: 1 hour)
15
+ */
16
+ constructor(ttlMs = 60 * 60 * 1000) {
17
+ this.ttl = ttlMs;
18
+ }
19
+ /**
20
+ * Save a set of tokens and their original values to the vault.
21
+ *
22
+ * @param tokens - Map of tokens to cleartext values.
23
+ */
24
+ saveTokens(tokens) {
25
+ const now = Date.now();
26
+ for (const [token, value] of tokens) {
27
+ this.vault.set(token, { value, timestamp: now });
28
+ }
29
+ this.prune();
30
+ }
31
+ /**
32
+ * Re-hydrate a string or object containing tokens back into cleartext.
33
+ *
34
+ * @param input - The string or object containing tokens.
35
+ * @returns The original cleartext content.
36
+ */
37
+ rehydrate(input) {
38
+ // Return early if no tokens in vault
39
+ if (this.vault.size === 0)
40
+ return input;
41
+ // Security: Use structuredClone for safe deep copies (addresses review)
42
+ let output;
43
+ try {
44
+ output = typeof input === 'object' && input !== null
45
+ ? structuredClone(input)
46
+ : input;
47
+ }
48
+ catch (e) {
49
+ output = input;
50
+ }
51
+ const process = (node) => {
52
+ if (typeof node === 'string') {
53
+ let text = node;
54
+ // Efficiently replace all tokens
55
+ for (const [token, entry] of this.vault.entries()) {
56
+ text = text.split(token).join(entry.value);
57
+ }
58
+ return text;
59
+ }
60
+ if (Array.isArray(node)) {
61
+ return node.map(item => process(item));
62
+ }
63
+ if (node !== null && typeof node === 'object') {
64
+ const obj = {};
65
+ for (const [key, value] of Object.entries(node)) {
66
+ obj[key] = process(value);
67
+ }
68
+ return obj;
69
+ }
70
+ return node;
71
+ };
72
+ return process(output);
73
+ }
74
+ /**
75
+ * Create a stateful rehydrator for processing streaming chunks.
76
+ * Handles cases where tokens are split across chunks.
77
+ */
78
+ createStreamingRehydrator() {
79
+ let buffer = '';
80
+ return (chunk) => {
81
+ buffer += chunk;
82
+ // Check if any vault token could be split across chunks (partial match at end)
83
+ let holdBack = 0;
84
+ for (const [token] of this.vault.entries()) {
85
+ // Check if the end of the buffer is a prefix of any token
86
+ for (let prefixLen = 1; prefixLen < token.length; prefixLen++) {
87
+ const prefix = token.substring(0, prefixLen);
88
+ if (buffer.endsWith(prefix)) {
89
+ holdBack = Math.max(holdBack, prefixLen);
90
+ }
91
+ }
92
+ }
93
+ // Split buffer into releasable text and held-back portion
94
+ const releaseEnd = buffer.length - holdBack;
95
+ let text = buffer.substring(0, releaseEnd);
96
+ buffer = buffer.substring(releaseEnd);
97
+ // Replace all vault tokens in the releasable text
98
+ for (const [token, entry] of this.vault.entries()) {
99
+ text = text.split(token).join(entry.value);
100
+ }
101
+ return text;
102
+ };
103
+ }
104
+ /**
105
+ * Remove expired tokens from the vault.
106
+ */
107
+ prune() {
108
+ const now = Date.now();
109
+ for (const [token, entry] of this.vault.entries()) {
110
+ if (now - entry.timestamp > this.ttl) {
111
+ this.vault.delete(token);
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Get the original value for a specific token.
117
+ *
118
+ * @param token - The token to look up.
119
+ * @returns The original cleartext or undefined if not found.
120
+ */
121
+ get(token) {
122
+ const entry = this.vault.get(token);
123
+ return entry?.value;
124
+ }
125
+ /**
126
+ * Clear the vault for a new session.
127
+ */
128
+ clear() {
129
+ this.vault.clear();
130
+ }
131
+ /**
132
+ * Get the number of tokens currently in the vault.
133
+ */
134
+ get size() {
135
+ return this.vault.size;
136
+ }
137
+ }
138
+ //# sourceMappingURL=token-vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-vault.js","sourceRoot":"","sources":["../../src/vault/token-vault.ts"],"names":[],"mappings":"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"}