@defai.digital/ax-cli 3.5.4 → 3.6.1

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 (162) hide show
  1. package/.ax-cli/checkpoints/2025-11-20/checkpoint-11e9e0ba-c39d-4fd2-aa77-bc818811c921.json +69 -0
  2. package/.ax-cli/checkpoints/2025-11-20/checkpoint-2b260b98-b418-4c7c-9694-e2b94967e662.json +24 -0
  3. package/.ax-cli/checkpoints/2025-11-20/checkpoint-7e03601e-e8ab-4cd7-9841-a74b66adf78f.json +69 -0
  4. package/.ax-cli/checkpoints/2025-11-20/checkpoint-7f9c6562-771f-4fd0-adcf-9e7e9ac34ae8.json +44 -0
  5. package/.ax-cli/checkpoints/2025-11-20/checkpoint-e1ebe666-4c3a-4367-ba5c-27fe512a9c70.json +24 -0
  6. package/.ax-cli/checkpoints/2025-11-21/checkpoint-15743e7d-430c-4d76-b6fc-955d7a5c250c.json +44 -0
  7. package/.ax-cli/checkpoints/2025-11-21/checkpoint-25cf7679-0b3f-4988-83d7-704548fbba91.json +69 -0
  8. package/.ax-cli/checkpoints/2025-11-21/checkpoint-54aedbac-6db0-464e-8ebb-dbb3979e6dca.json +24 -0
  9. package/.ax-cli/checkpoints/2025-11-21/checkpoint-7658aed8-fe5d-4222-903f-1a7c63717ea7.json +24 -0
  10. package/.ax-cli/checkpoints/2025-11-21/checkpoint-c9c13497-40dc-4294-a327-6a5fc854eaa1.json +69 -0
  11. package/.ax-cli/memory.json +15 -8
  12. package/README.md +423 -82
  13. package/ax.config.json +333 -0
  14. package/config-defaults/messages.yaml +75 -0
  15. package/config-defaults/models.yaml +66 -0
  16. package/config-defaults/prompts.yaml +156 -0
  17. package/config-defaults/settings.yaml +86 -0
  18. package/dist/agent/chat-history-manager.d.ts +56 -0
  19. package/dist/agent/chat-history-manager.js +150 -0
  20. package/dist/agent/chat-history-manager.js.map +1 -0
  21. package/dist/agent/llm-agent.js +1 -1
  22. package/dist/agent/llm-agent.js.map +1 -1
  23. package/dist/agent/tool-manager.d.ts +39 -0
  24. package/dist/agent/tool-manager.js +76 -0
  25. package/dist/agent/tool-manager.js.map +1 -0
  26. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js +7 -9
  27. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js.map +1 -1
  28. package/dist/analyzers/code-smells/detectors/dead-code-detector.js +1 -1
  29. package/dist/analyzers/code-smells/detectors/dead-code-detector.js.map +1 -1
  30. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js +22 -10
  31. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js.map +1 -1
  32. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js +1 -1
  33. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js.map +1 -1
  34. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js +1 -1
  35. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js.map +1 -1
  36. package/dist/analyzers/code-smells/detectors/large-class-detector.js +4 -1
  37. package/dist/analyzers/code-smells/detectors/large-class-detector.js.map +1 -1
  38. package/dist/analyzers/code-smells/detectors/long-method-detector.js +4 -1
  39. package/dist/analyzers/code-smells/detectors/long-method-detector.js.map +1 -1
  40. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js +4 -1
  41. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js.map +1 -1
  42. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js +4 -5
  43. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js.map +1 -1
  44. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js +4 -1
  45. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js.map +1 -1
  46. package/dist/commands/memory.js +1 -1
  47. package/dist/commands/memory.js.map +1 -1
  48. package/dist/commands/setup.js +19 -6
  49. package/dist/commands/setup.js.map +1 -1
  50. package/dist/index.js +7 -0
  51. package/dist/index.js.bak +664 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/llm/client.d.ts +1 -0
  54. package/dist/llm/client.js +44 -0
  55. package/dist/llm/client.js.map +1 -1
  56. package/dist/mcp/health.js +4 -2
  57. package/dist/mcp/health.js.map +1 -1
  58. package/dist/mcp/ssrf-protection.d.ts +86 -0
  59. package/dist/mcp/ssrf-protection.js +313 -0
  60. package/dist/mcp/ssrf-protection.js.map +1 -0
  61. package/dist/mcp/validation.d.ts +4 -0
  62. package/dist/mcp/validation.js +122 -11
  63. package/dist/mcp/validation.js.map +1 -1
  64. package/dist/schemas/settings-schemas.d.ts +53 -0
  65. package/dist/schemas/settings-schemas.js +47 -0
  66. package/dist/schemas/settings-schemas.js.map +1 -1
  67. package/dist/tools/bash.d.ts +3 -2
  68. package/dist/tools/bash.js +31 -2
  69. package/dist/tools/bash.js.map +1 -1
  70. package/dist/tools/search.d.ts +1 -1
  71. package/dist/tools/search.js +121 -128
  72. package/dist/tools/search.js.map +1 -1
  73. package/dist/tools/text-editor.js +52 -15
  74. package/dist/tools/text-editor.js.map +1 -1
  75. package/dist/tools/web-search/index.d.ts +0 -2
  76. package/dist/tools/web-search/index.js +0 -2
  77. package/dist/tools/web-search/index.js.map +1 -1
  78. package/dist/tools/web-search/router.d.ts +0 -2
  79. package/dist/tools/web-search/router.js +2 -37
  80. package/dist/tools/web-search/router.js.map +1 -1
  81. package/dist/tools/web-search/web-search-tool.js +2 -12
  82. package/dist/tools/web-search/web-search-tool.js.map +1 -1
  83. package/dist/ui/components/chat-history.js +1 -1
  84. package/dist/ui/components/chat-history.js.map +1 -1
  85. package/dist/ui/components/chat-input.d.ts +4 -1
  86. package/dist/ui/components/chat-input.js +133 -52
  87. package/dist/ui/components/chat-input.js.map +1 -1
  88. package/dist/ui/components/chat-interface.js +5 -4
  89. package/dist/ui/components/chat-interface.js.map +1 -1
  90. package/dist/ui/components/confirmation-dialog.js +1 -1
  91. package/dist/ui/components/confirmation-dialog.js.map +1 -1
  92. package/dist/ui/components/keyboard-hints.js +2 -0
  93. package/dist/ui/components/keyboard-hints.js.map +1 -1
  94. package/dist/ui/components/status-bar.js +3 -13
  95. package/dist/ui/components/status-bar.js.map +1 -1
  96. package/dist/ui/components/welcome-panel.js +4 -0
  97. package/dist/ui/components/welcome-panel.js.map +1 -1
  98. package/dist/ui/hooks/use-chat-reducer.d.ts +61 -0
  99. package/dist/ui/hooks/use-chat-reducer.js +118 -0
  100. package/dist/ui/hooks/use-chat-reducer.js.map +1 -0
  101. package/dist/ui/hooks/use-enhanced-input.d.ts +44 -0
  102. package/dist/ui/hooks/use-enhanced-input.js +364 -0
  103. package/dist/ui/hooks/use-enhanced-input.js.map +1 -0
  104. package/dist/ui/hooks/use-input-handler.d.ts +48 -0
  105. package/dist/ui/hooks/use-input-handler.js +1446 -0
  106. package/dist/ui/hooks/use-input-handler.js.map +1 -0
  107. package/dist/utils/audit-logger.d.ts +205 -0
  108. package/dist/utils/audit-logger.js +269 -0
  109. package/dist/utils/audit-logger.js.map +1 -0
  110. package/dist/utils/command-security.d.ts +85 -0
  111. package/dist/utils/command-security.js +200 -0
  112. package/dist/utils/command-security.js.map +1 -0
  113. package/dist/utils/config-loader.js +3 -3
  114. package/dist/utils/config-loader.js.map +1 -1
  115. package/dist/utils/encryption.d.ts +78 -0
  116. package/dist/utils/encryption.js +216 -0
  117. package/dist/utils/encryption.js.map +1 -0
  118. package/dist/utils/error-sanitizer.d.ts +119 -0
  119. package/dist/utils/error-sanitizer.js +253 -0
  120. package/dist/utils/error-sanitizer.js.map +1 -0
  121. package/dist/utils/input-sanitizer.d.ts +210 -0
  122. package/dist/utils/input-sanitizer.js +362 -0
  123. package/dist/utils/input-sanitizer.js.map +1 -0
  124. package/dist/utils/json-utils.d.ts +13 -0
  125. package/dist/utils/json-utils.js +55 -1
  126. package/dist/utils/json-utils.js.map +1 -1
  127. package/dist/utils/paste-collapse.d.ts +46 -0
  128. package/dist/utils/paste-collapse.js +77 -0
  129. package/dist/utils/paste-collapse.js.map +1 -0
  130. package/dist/utils/paste-utils.d.ts +99 -0
  131. package/dist/utils/paste-utils.js +239 -0
  132. package/dist/utils/paste-utils.js.map +1 -0
  133. package/dist/utils/path-security.d.ts +90 -0
  134. package/dist/utils/path-security.js +328 -0
  135. package/dist/utils/path-security.js.map +1 -0
  136. package/dist/utils/process-pool.d.ts +105 -0
  137. package/dist/utils/process-pool.js +326 -0
  138. package/dist/utils/process-pool.js.map +1 -0
  139. package/dist/utils/rate-limiter.d.ts +221 -0
  140. package/dist/utils/rate-limiter.js +317 -0
  141. package/dist/utils/rate-limiter.js.map +1 -0
  142. package/dist/utils/settings-manager.js +99 -6
  143. package/dist/utils/settings-manager.js.map +1 -1
  144. package/dist/utils/streaming-analyzer.js +9 -21
  145. package/dist/utils/streaming-analyzer.js.map +1 -1
  146. package/package.json +3 -7
  147. package/packages/schemas/dist/index.d.ts +14 -0
  148. package/packages/schemas/dist/index.d.ts.map +1 -0
  149. package/packages/schemas/dist/index.js +19 -0
  150. package/packages/schemas/dist/index.js.map +1 -0
  151. package/packages/schemas/dist/public/core/brand-types.d.ts +308 -0
  152. package/packages/schemas/dist/public/core/brand-types.d.ts.map +1 -0
  153. package/packages/schemas/dist/public/core/brand-types.js +243 -0
  154. package/packages/schemas/dist/public/core/brand-types.js.map +1 -0
  155. package/packages/schemas/dist/public/core/enums.d.ts +227 -0
  156. package/packages/schemas/dist/public/core/enums.d.ts.map +1 -0
  157. package/packages/schemas/dist/public/core/enums.js +222 -0
  158. package/packages/schemas/dist/public/core/enums.js.map +1 -0
  159. package/packages/schemas/dist/public/core/id-types.d.ts +286 -0
  160. package/packages/schemas/dist/public/core/id-types.d.ts.map +1 -0
  161. package/packages/schemas/dist/public/core/id-types.js +136 -0
  162. package/packages/schemas/dist/public/core/id-types.js.map +1 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Command Security Utilities
3
+ *
4
+ * Provides secure command execution with whitelisting and validation.
5
+ * Prevents command injection vulnerabilities (REQ-SEC-001).
6
+ *
7
+ * @module command-security
8
+ */
9
+ import { execFile } from 'child_process';
10
+ import { promisify } from 'util';
11
+ const execFileAsync = promisify(execFile);
12
+ /**
13
+ * Whitelist of safe commands allowed for execution.
14
+ * Only these commands can be executed via the BashTool.
15
+ *
16
+ * CRITICAL: Do not add arbitrary commands without security review.
17
+ */
18
+ export const SAFE_COMMANDS = [
19
+ 'ls',
20
+ 'grep',
21
+ 'find',
22
+ 'cat',
23
+ 'head',
24
+ 'tail',
25
+ 'wc',
26
+ 'sort',
27
+ 'uniq',
28
+ 'cut',
29
+ 'awk',
30
+ 'sed',
31
+ 'pwd',
32
+ 'echo',
33
+ 'date',
34
+ 'whoami',
35
+ 'hostname',
36
+ 'git',
37
+ 'rg',
38
+ 'fd',
39
+ 'rm', // File deletion (safe with validation)
40
+ 'mkdir', // Directory creation
41
+ 'touch', // File creation
42
+ 'cp', // File copy
43
+ 'mv', // File move/rename
44
+ ];
45
+ /**
46
+ * Environment variables safe to pass to child processes.
47
+ * Only these will be included in the child process environment.
48
+ */
49
+ const SAFE_ENV_VARS = [
50
+ 'PATH',
51
+ 'HOME',
52
+ 'USER',
53
+ 'LANG',
54
+ 'LC_ALL',
55
+ 'TERM',
56
+ 'TMPDIR',
57
+ 'PWD',
58
+ ];
59
+ /**
60
+ * Shell metacharacters that are forbidden in command arguments.
61
+ * These could enable command injection if not properly validated.
62
+ */
63
+ const SHELL_METACHARACTERS = /[;&|`$(){}[\]<>'"\\*?~!#]/;
64
+ /**
65
+ * Sanitize environment variables for child process.
66
+ * Only includes safe environment variables to prevent injection.
67
+ *
68
+ * @param env - Original process environment
69
+ * @returns Sanitized environment object
70
+ */
71
+ export function sanitizeEnv(env) {
72
+ const sanitized = {};
73
+ for (const key of SAFE_ENV_VARS) {
74
+ if (env[key]) {
75
+ sanitized[key] = env[key];
76
+ }
77
+ }
78
+ return sanitized;
79
+ }
80
+ /**
81
+ * Parse a command string into command and arguments.
82
+ * Validates that the command is in the whitelist.
83
+ *
84
+ * @param commandString - Full command string (e.g., "ls -la /tmp")
85
+ * @returns Parsed command structure
86
+ * @throws Error if command is not whitelisted
87
+ */
88
+ export function parseCommand(commandString) {
89
+ const trimmed = commandString.trim();
90
+ if (!trimmed) {
91
+ throw new Error('Empty command string');
92
+ }
93
+ // Simple split by whitespace
94
+ const parts = trimmed.split(/\s+/);
95
+ const command = parts[0];
96
+ const args = parts.slice(1);
97
+ // Validate command is in whitelist
98
+ if (!SAFE_COMMANDS.includes(command)) {
99
+ throw new Error(`Command '${command}' not in whitelist. Allowed commands: ${SAFE_COMMANDS.join(', ')}`);
100
+ }
101
+ return {
102
+ command: command,
103
+ args,
104
+ };
105
+ }
106
+ /**
107
+ * Validate command arguments for shell metacharacters.
108
+ * Prevents command injection via argument injection.
109
+ *
110
+ * @param args - Command arguments to validate
111
+ * @returns Validation result
112
+ */
113
+ export function validateArguments(args) {
114
+ const errors = [];
115
+ for (let i = 0; i < args.length; i++) {
116
+ const arg = args[i];
117
+ // Check for shell metacharacters
118
+ if (SHELL_METACHARACTERS.test(arg)) {
119
+ errors.push(`Argument ${i} contains forbidden shell metacharacters: "${arg}"`);
120
+ }
121
+ // Check for null bytes
122
+ if (arg.includes('\0')) {
123
+ errors.push(`Argument ${i} contains null byte`);
124
+ }
125
+ // Check length (prevent buffer overflow)
126
+ if (arg.length > 10000) {
127
+ errors.push(`Argument ${i} exceeds maximum length (10000 chars)`);
128
+ }
129
+ }
130
+ return {
131
+ valid: errors.length === 0,
132
+ errors,
133
+ };
134
+ }
135
+ /**
136
+ * Execute a safe command with validation.
137
+ * Uses execFile to avoid shell invocation and command injection.
138
+ *
139
+ * SECURITY: This function uses execFile instead of spawn('bash', ['-c'])
140
+ * to prevent command injection attacks.
141
+ *
142
+ * @param commandString - Command to execute
143
+ * @param options - Execution options
144
+ * @returns Tool result with output or error
145
+ */
146
+ export async function executeSafeCommand(commandString, options = {}) {
147
+ try {
148
+ // 1. Parse command into command + args
149
+ const parsed = parseCommand(commandString);
150
+ // 2. Validate arguments
151
+ const validation = validateArguments(parsed.args);
152
+ if (!validation.valid) {
153
+ return {
154
+ success: false,
155
+ error: `Command validation failed:\n${validation.errors.join('\n')}`,
156
+ };
157
+ }
158
+ // 3. Prepare execution options
159
+ const execOptions = {
160
+ cwd: options.cwd || process.cwd(),
161
+ env: sanitizeEnv(process.env),
162
+ timeout: options.timeout || 30000, // 30 second default
163
+ maxBuffer: options.maxBuffer || 1024 * 1024, // 1MB default
164
+ };
165
+ // 4. Execute using execFile (no shell invocation)
166
+ const { stdout, stderr } = await execFileAsync(parsed.command, parsed.args, execOptions);
167
+ // 5. Return successful result
168
+ return {
169
+ success: true,
170
+ output: stdout || stderr || 'Command completed successfully',
171
+ };
172
+ }
173
+ catch (error) {
174
+ // Handle execution errors
175
+ const errorMessage = error.message || String(error);
176
+ const exitCode = error.code || 'unknown';
177
+ return {
178
+ success: false,
179
+ error: `Command execution failed (exit code: ${exitCode}): ${errorMessage}`,
180
+ };
181
+ }
182
+ }
183
+ /**
184
+ * Check if a command is safe to execute.
185
+ *
186
+ * @param command - Command name to check
187
+ * @returns True if command is in whitelist
188
+ */
189
+ export function isSafeCommand(command) {
190
+ return SAFE_COMMANDS.includes(command);
191
+ }
192
+ /**
193
+ * Get list of safe commands (for documentation/help).
194
+ *
195
+ * @returns Array of safe command names
196
+ */
197
+ export function getSafeCommands() {
198
+ return SAFE_COMMANDS;
199
+ }
200
+ //# sourceMappingURL=command-security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-security.js","sourceRoot":"","sources":["../../src/utils/command-security.ts"],"names":[],"mappings":"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"}
@@ -16,9 +16,9 @@ const configCache = new Map();
16
16
  * Get the config directory path
17
17
  */
18
18
  function getConfigDir() {
19
- // In development: src/utils -> ../../config
20
- // In production: dist/utils -> ../../config
21
- return join(__dirname, '../../config');
19
+ // In development: src/utils -> ../../config-defaults
20
+ // In production: dist/utils -> ../../config-defaults
21
+ return join(__dirname, '../../config-defaults');
22
22
  }
23
23
  /**
24
24
  * Load a YAML configuration file with optional schema validation
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEzH,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,kCAAkC;AAClC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAe,CAAC;AAE3C;;GAEG;AACH,SAAS,YAAY;IACnB,qDAAqD;IACrD,qDAAqD;IACrD,OAAO,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAU,QAAgB,EAAE,MAAuB;IAC/E,oBAAoB;IACpB,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAM,CAAC;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,QAAQ,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEvC,mCAAmC;QACnC,IAAI,MAAM,EAAE,CAAC;YACX,qDAAqD;YACrD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAChF,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;QAED,sDAAsD;QACtD,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO,MAAW,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,KAAM,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAyBD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAa,aAAa,EAAE,gBAAgB,CAAC,CAAC;AACrE,CAAC;AAsDD,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,CAAe,eAAe,EAAE,kBAAkB,CAAC,CAAC;AAC3E,CAAC;AA8BD,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAc,cAAc,EAAE,iBAAiB,CAAC,CAAC;AACxE,CAAC;AAkBD,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,CAAe,eAAe,EAAE,kBAAkB,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,SAA0C;IACxF,+EAA+E;IAC/E,OAAO,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9D,OAAO,SAAS,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * API Key Encryption Utilities
3
+ *
4
+ * Provides secure encryption/decryption for API keys stored in configuration
5
+ * files (REQ-SEC-003).
6
+ *
7
+ * Uses Node.js crypto module with:
8
+ * - AES-256-GCM for encryption (authenticated encryption)
9
+ * - PBKDF2 for key derivation from machine-specific identifier
10
+ * - Random IV for each encryption
11
+ * - Authentication tag verification
12
+ *
13
+ * @module encryption
14
+ */
15
+ /**
16
+ * Encrypted value format
17
+ */
18
+ export interface EncryptedValue {
19
+ encrypted: string;
20
+ iv: string;
21
+ tag: string;
22
+ version: number;
23
+ }
24
+ /**
25
+ * Encrypt a string value (typically an API key).
26
+ *
27
+ * @param plaintext - The value to encrypt
28
+ * @returns Encrypted value object with iv, tag, and encrypted data
29
+ */
30
+ export declare function encrypt(plaintext: string): EncryptedValue;
31
+ /**
32
+ * Decrypt an encrypted value.
33
+ *
34
+ * @param encryptedValue - The encrypted value object
35
+ * @returns Decrypted plaintext
36
+ * @throws Error if decryption fails (wrong machine, corrupted data, etc.)
37
+ */
38
+ export declare function decrypt(encryptedValue: EncryptedValue): string;
39
+ /**
40
+ * Check if a value is encrypted (has the expected structure).
41
+ *
42
+ * @param value - Value to check
43
+ * @returns True if value appears to be encrypted
44
+ */
45
+ export declare function isEncrypted(value: unknown): value is EncryptedValue;
46
+ /**
47
+ * Encrypt an object's sensitive fields.
48
+ *
49
+ * @param obj - Object containing sensitive fields
50
+ * @param fieldsToEncrypt - Array of field names to encrypt
51
+ * @returns New object with encrypted fields
52
+ */
53
+ export declare function encryptFields<T extends Record<string, any>>(obj: T, fieldsToEncrypt: string[]): T;
54
+ /**
55
+ * Decrypt an object's encrypted fields.
56
+ *
57
+ * @param obj - Object containing encrypted fields
58
+ * @param fieldsToDecrypt - Array of field names to decrypt
59
+ * @returns New object with decrypted fields
60
+ */
61
+ export declare function decryptFields<T extends Record<string, any>>(obj: T, fieldsToDecrypt: string[]): T;
62
+ /**
63
+ * Test if encryption is working (for diagnostics).
64
+ *
65
+ * @returns True if encryption/decryption round-trip works
66
+ */
67
+ export declare function testEncryption(): boolean;
68
+ /**
69
+ * Get encryption info for diagnostics.
70
+ */
71
+ export declare function getEncryptionInfo(): {
72
+ algorithm: string;
73
+ keyLength: number;
74
+ ivLength: number;
75
+ pbkdf2Iterations: number;
76
+ version: number;
77
+ machineId: string;
78
+ };
@@ -0,0 +1,216 @@
1
+ /**
2
+ * API Key Encryption Utilities
3
+ *
4
+ * Provides secure encryption/decryption for API keys stored in configuration
5
+ * files (REQ-SEC-003).
6
+ *
7
+ * Uses Node.js crypto module with:
8
+ * - AES-256-GCM for encryption (authenticated encryption)
9
+ * - PBKDF2 for key derivation from machine-specific identifier
10
+ * - Random IV for each encryption
11
+ * - Authentication tag verification
12
+ *
13
+ * @module encryption
14
+ */
15
+ import crypto from 'crypto';
16
+ import os from 'os';
17
+ /**
18
+ * Encryption configuration
19
+ */
20
+ const ENCRYPTION_CONFIG = {
21
+ algorithm: 'aes-256-gcm',
22
+ keyLength: 32, // 256 bits
23
+ ivLength: 16, // 128 bits
24
+ saltLength: 32, // 256 bits
25
+ tagLength: 16, // 128 bits
26
+ pbkdf2Iterations: 100000, // OWASP recommendation
27
+ version: 1,
28
+ };
29
+ /**
30
+ * Get a machine-specific identifier for key derivation.
31
+ * Uses hostname + platform + arch to create a unique-per-machine string.
32
+ *
33
+ * Note: This is not cryptographically strong protection (attacker with file
34
+ * access can derive the key), but it prevents casual browsing of config files
35
+ * and provides defense in depth.
36
+ */
37
+ function getMachineIdentifier() {
38
+ const hostname = os.hostname();
39
+ const platform = os.platform();
40
+ const arch = os.arch();
41
+ // Combine machine-specific data
42
+ return `${hostname}-${platform}-${arch}`;
43
+ }
44
+ /**
45
+ * Derive an encryption key from machine identifier and salt using PBKDF2.
46
+ *
47
+ * @param salt - Salt for key derivation
48
+ * @returns Derived encryption key
49
+ */
50
+ function deriveKey(salt) {
51
+ const machineId = getMachineIdentifier();
52
+ return crypto.pbkdf2Sync(machineId, salt, ENCRYPTION_CONFIG.pbkdf2Iterations, ENCRYPTION_CONFIG.keyLength, 'sha256');
53
+ }
54
+ /**
55
+ * Encrypt a string value (typically an API key).
56
+ *
57
+ * @param plaintext - The value to encrypt
58
+ * @returns Encrypted value object with iv, tag, and encrypted data
59
+ */
60
+ export function encrypt(plaintext) {
61
+ // Generate random salt and IV
62
+ const salt = crypto.randomBytes(ENCRYPTION_CONFIG.saltLength);
63
+ const iv = crypto.randomBytes(ENCRYPTION_CONFIG.ivLength);
64
+ // Derive key from machine identifier
65
+ const key = deriveKey(salt);
66
+ // Create cipher
67
+ const cipher = crypto.createCipheriv(ENCRYPTION_CONFIG.algorithm, key, iv);
68
+ // Encrypt the plaintext
69
+ let encrypted = cipher.update(plaintext, 'utf8', 'base64');
70
+ encrypted += cipher.final('base64');
71
+ // Get authentication tag
72
+ const tag = cipher.getAuthTag();
73
+ // Return encrypted value with metadata
74
+ // Store salt in the IV field for simplicity (both are public)
75
+ const saltAndIv = Buffer.concat([salt, iv]);
76
+ return {
77
+ encrypted,
78
+ iv: saltAndIv.toString('base64'),
79
+ tag: tag.toString('base64'),
80
+ version: ENCRYPTION_CONFIG.version,
81
+ };
82
+ }
83
+ /**
84
+ * Decrypt an encrypted value.
85
+ *
86
+ * @param encryptedValue - The encrypted value object
87
+ * @returns Decrypted plaintext
88
+ * @throws Error if decryption fails (wrong machine, corrupted data, etc.)
89
+ */
90
+ export function decrypt(encryptedValue) {
91
+ try {
92
+ // Check version
93
+ if (encryptedValue.version !== ENCRYPTION_CONFIG.version) {
94
+ throw new Error(`Unsupported encryption version: ${encryptedValue.version}`);
95
+ }
96
+ // Extract salt and IV
97
+ const saltAndIv = Buffer.from(encryptedValue.iv, 'base64');
98
+ if (saltAndIv.length !== ENCRYPTION_CONFIG.saltLength + ENCRYPTION_CONFIG.ivLength) {
99
+ throw new Error('Invalid encrypted data: incorrect salt/IV length');
100
+ }
101
+ const salt = saltAndIv.subarray(0, ENCRYPTION_CONFIG.saltLength);
102
+ const iv = saltAndIv.subarray(ENCRYPTION_CONFIG.saltLength);
103
+ // Derive key from machine identifier
104
+ const key = deriveKey(salt);
105
+ // Create decipher
106
+ const decipher = crypto.createDecipheriv(ENCRYPTION_CONFIG.algorithm, key, iv);
107
+ // Set authentication tag
108
+ const tag = Buffer.from(encryptedValue.tag, 'base64');
109
+ decipher.setAuthTag(tag);
110
+ // Decrypt
111
+ let decrypted = decipher.update(encryptedValue.encrypted, 'base64', 'utf8');
112
+ decrypted += decipher.final('utf8');
113
+ return decrypted;
114
+ }
115
+ catch (error) {
116
+ // Provide a user-friendly error message
117
+ if (error instanceof Error) {
118
+ if (error.message.includes('Unsupported state or unable to authenticate data')) {
119
+ throw new Error('Failed to decrypt API key. This may be due to: ' +
120
+ '(1) moving config to a different machine, ' +
121
+ '(2) corrupted config file, or ' +
122
+ '(3) config file was manually edited. ' +
123
+ 'Please re-enter your API key.');
124
+ }
125
+ throw new Error(`Decryption failed: ${error.message}`);
126
+ }
127
+ throw new Error('Decryption failed: Unknown error');
128
+ }
129
+ }
130
+ /**
131
+ * Check if a value is encrypted (has the expected structure).
132
+ *
133
+ * @param value - Value to check
134
+ * @returns True if value appears to be encrypted
135
+ */
136
+ export function isEncrypted(value) {
137
+ if (typeof value !== 'object' || value === null) {
138
+ return false;
139
+ }
140
+ const obj = value;
141
+ return (typeof obj.encrypted === 'string' &&
142
+ typeof obj.iv === 'string' &&
143
+ typeof obj.tag === 'string' &&
144
+ typeof obj.version === 'number');
145
+ }
146
+ /**
147
+ * Encrypt an object's sensitive fields.
148
+ *
149
+ * @param obj - Object containing sensitive fields
150
+ * @param fieldsToEncrypt - Array of field names to encrypt
151
+ * @returns New object with encrypted fields
152
+ */
153
+ export function encryptFields(obj, fieldsToEncrypt) {
154
+ const result = { ...obj };
155
+ for (const field of fieldsToEncrypt) {
156
+ if (field in result && typeof result[field] === 'string') {
157
+ // Don't re-encrypt already encrypted values
158
+ if (!isEncrypted(result[field])) {
159
+ result[field] = encrypt(result[field]);
160
+ }
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ /**
166
+ * Decrypt an object's encrypted fields.
167
+ *
168
+ * @param obj - Object containing encrypted fields
169
+ * @param fieldsToDecrypt - Array of field names to decrypt
170
+ * @returns New object with decrypted fields
171
+ */
172
+ export function decryptFields(obj, fieldsToDecrypt) {
173
+ const result = { ...obj };
174
+ for (const field of fieldsToDecrypt) {
175
+ if (field in result && isEncrypted(result[field])) {
176
+ try {
177
+ result[field] = decrypt(result[field]);
178
+ }
179
+ catch (error) {
180
+ // If decryption fails, leave the field as-is and let caller handle it
181
+ console.error(`Failed to decrypt field "${field}":`, error instanceof Error ? error.message : String(error));
182
+ }
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ /**
188
+ * Test if encryption is working (for diagnostics).
189
+ *
190
+ * @returns True if encryption/decryption round-trip works
191
+ */
192
+ export function testEncryption() {
193
+ try {
194
+ const testValue = 'test-api-key-12345';
195
+ const encrypted = encrypt(testValue);
196
+ const decrypted = decrypt(encrypted);
197
+ return decrypted === testValue;
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }
203
+ /**
204
+ * Get encryption info for diagnostics.
205
+ */
206
+ export function getEncryptionInfo() {
207
+ return {
208
+ algorithm: ENCRYPTION_CONFIG.algorithm,
209
+ keyLength: ENCRYPTION_CONFIG.keyLength,
210
+ ivLength: ENCRYPTION_CONFIG.ivLength,
211
+ pbkdf2Iterations: ENCRYPTION_CONFIG.pbkdf2Iterations,
212
+ version: ENCRYPTION_CONFIG.version,
213
+ machineId: getMachineIdentifier(),
214
+ };
215
+ }
216
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/utils/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Error Message Sanitization (REQ-SEC-010)
3
+ *
4
+ * Sanitizes error messages to prevent information disclosure
5
+ * Removes:
6
+ * - File system paths
7
+ * - API keys and secrets
8
+ * - Stack traces (for user-facing errors)
9
+ * - Internal implementation details
10
+ *
11
+ * Security: CVSS 6.5 (Medium Priority)
12
+ */
13
+ /**
14
+ * Sanitized error structure
15
+ */
16
+ export interface SanitizedError {
17
+ /**
18
+ * Sanitized error message (safe for user display)
19
+ */
20
+ message: string;
21
+ /**
22
+ * Error code (for documentation lookup)
23
+ */
24
+ code?: string;
25
+ /**
26
+ * Generic error category
27
+ */
28
+ category: string;
29
+ /**
30
+ * Suggested action for user
31
+ */
32
+ suggestion?: string;
33
+ /**
34
+ * Original error (for internal logging only)
35
+ */
36
+ originalError?: Error;
37
+ }
38
+ /**
39
+ * Error categories for user-friendly messages
40
+ */
41
+ export declare enum ErrorCategory {
42
+ NETWORK = "NETWORK",
43
+ FILE_SYSTEM = "FILE_SYSTEM",
44
+ VALIDATION = "VALIDATION",
45
+ AUTHENTICATION = "AUTHENTICATION",
46
+ RATE_LIMIT = "RATE_LIMIT",
47
+ API_ERROR = "API_ERROR",
48
+ INTERNAL = "INTERNAL",
49
+ USER_INPUT = "USER_INPUT"
50
+ }
51
+ /**
52
+ * Sanitize error message by removing sensitive information
53
+ *
54
+ * @param message - Raw error message
55
+ * @returns Sanitized message safe for user display
56
+ */
57
+ export declare function sanitizeErrorMessage(message: string): string;
58
+ /**
59
+ * Sanitize stack trace by removing sensitive paths
60
+ *
61
+ * @param stack - Raw stack trace
62
+ * @returns Sanitized stack trace
63
+ */
64
+ export declare function sanitizeStackTrace(stack: string): string;
65
+ /**
66
+ * Remove stack trace entirely (for user-facing errors)
67
+ *
68
+ * @param message - Error message with potential stack trace
69
+ * @returns Message without stack trace
70
+ */
71
+ export declare function removeStackTrace(message: string): string;
72
+ /**
73
+ * Categorize error and create user-friendly message
74
+ *
75
+ * @param error - Error object
76
+ * @returns Sanitized error with category and suggestion
77
+ */
78
+ export declare function sanitizeError(error: Error | unknown): SanitizedError;
79
+ /**
80
+ * Format sanitized error for user display
81
+ *
82
+ * @param sanitizedError - Sanitized error object
83
+ * @returns Formatted error message
84
+ */
85
+ export declare function formatUserError(sanitizedError: SanitizedError): string;
86
+ /**
87
+ * Create internal log message with full details (not sanitized)
88
+ *
89
+ * @param error - Original error
90
+ * @param context - Additional context
91
+ * @returns Detailed log message
92
+ */
93
+ export declare function createInternalLogMessage(error: Error | unknown, context?: Record<string, unknown>): string;
94
+ /**
95
+ * Safe error wrapper for user-facing operations
96
+ *
97
+ * @param operation - Async operation to execute
98
+ * @param errorHandler - Optional custom error handler
99
+ * @returns Result or sanitized error
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const result = await safeExecute(
104
+ * () => riskyOperation(),
105
+ * (error) => console.error('Internal error:', error)
106
+ * );
107
+ *
108
+ * if (!result.success) {
109
+ * console.log(formatUserError(result.error));
110
+ * }
111
+ * ```
112
+ */
113
+ export declare function safeExecute<T>(operation: () => Promise<T>, errorHandler?: (error: Error, sanitized: SanitizedError) => void): Promise<{
114
+ success: true;
115
+ data: T;
116
+ } | {
117
+ success: false;
118
+ error: SanitizedError;
119
+ }>;