@phuetz/code-buddy 0.1.25 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1049 -741
- package/dist/agent/codebuddy-agent.d.ts +5 -0
- package/dist/agent/codebuddy-agent.js +46 -1
- package/dist/agent/codebuddy-agent.js.map +1 -1
- package/dist/agent/execution/agent-executor.d.ts +12 -0
- package/dist/agent/execution/agent-executor.js +147 -6
- package/dist/agent/execution/agent-executor.js.map +1 -1
- package/dist/agent/lessons-tracker.d.ts +50 -0
- package/dist/agent/lessons-tracker.js +234 -0
- package/dist/agent/lessons-tracker.js.map +1 -0
- package/dist/agent/message-queue.d.ts +39 -2
- package/dist/agent/message-queue.js +67 -2
- package/dist/agent/message-queue.js.map +1 -1
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/index.js.map +1 -1
- package/dist/agent/middleware/workflow-guard.d.ts +21 -0
- package/dist/agent/middleware/workflow-guard.js +94 -0
- package/dist/agent/middleware/workflow-guard.js.map +1 -0
- package/dist/agent/orchestrator/supervisor-agent.d.ts +9 -0
- package/dist/agent/orchestrator/supervisor-agent.js +21 -1
- package/dist/agent/orchestrator/supervisor-agent.js.map +1 -1
- package/dist/agent/repo-profiler.d.ts +61 -0
- package/dist/agent/repo-profiler.js +295 -0
- package/dist/agent/repo-profiler.js.map +1 -0
- package/dist/agent/response-constraint.d.ts +61 -0
- package/dist/agent/response-constraint.js +91 -0
- package/dist/agent/response-constraint.js.map +1 -0
- package/dist/agent/todo-tracker.d.ts +67 -0
- package/dist/agent/todo-tracker.js +245 -0
- package/dist/agent/todo-tracker.js.map +1 -0
- package/dist/agent/tool-handler.d.ts +11 -0
- package/dist/agent/tool-handler.js +79 -1
- package/dist/agent/tool-handler.js.map +1 -1
- package/dist/agent/types.d.ts +20 -2
- package/dist/agent/wide-research.d.ts +93 -0
- package/dist/agent/wide-research.js +232 -0
- package/dist/agent/wide-research.js.map +1 -0
- package/dist/channels/index.d.ts +2 -0
- package/dist/channels/index.js +2 -0
- package/dist/channels/index.js.map +1 -1
- package/dist/channels/pro/callback-router.d.ts +54 -0
- package/dist/channels/pro/callback-router.js +178 -0
- package/dist/channels/pro/callback-router.js.map +1 -0
- package/dist/channels/pro/ci-watcher.d.ts +86 -0
- package/dist/channels/pro/ci-watcher.js +343 -0
- package/dist/channels/pro/ci-watcher.js.map +1 -0
- package/dist/channels/pro/diff-first.d.ts +63 -0
- package/dist/channels/pro/diff-first.js +187 -0
- package/dist/channels/pro/diff-first.js.map +1 -0
- package/dist/channels/pro/enhanced-commands.d.ts +83 -0
- package/dist/channels/pro/enhanced-commands.js +218 -0
- package/dist/channels/pro/enhanced-commands.js.map +1 -0
- package/dist/channels/pro/index.d.ts +19 -0
- package/dist/channels/pro/index.js +21 -0
- package/dist/channels/pro/index.js.map +1 -0
- package/dist/channels/pro/pro-features.d.ts +79 -0
- package/dist/channels/pro/pro-features.js +203 -0
- package/dist/channels/pro/pro-features.js.map +1 -0
- package/dist/channels/pro/run-commands.d.ts +59 -0
- package/dist/channels/pro/run-commands.js +122 -0
- package/dist/channels/pro/run-commands.js.map +1 -0
- package/dist/channels/pro/run-tracker.d.ts +74 -0
- package/dist/channels/pro/run-tracker.js +252 -0
- package/dist/channels/pro/run-tracker.js.map +1 -0
- package/dist/channels/pro/scoped-auth.d.ts +97 -0
- package/dist/channels/pro/scoped-auth.js +340 -0
- package/dist/channels/pro/scoped-auth.js.map +1 -0
- package/dist/channels/pro/text-formatter.d.ts +27 -0
- package/dist/channels/pro/text-formatter.js +269 -0
- package/dist/channels/pro/text-formatter.js.map +1 -0
- package/dist/channels/pro/types.d.ts +242 -0
- package/dist/channels/pro/types.js +14 -0
- package/dist/channels/pro/types.js.map +1 -0
- package/dist/channels/streaming-policy.d.ts +66 -0
- package/dist/channels/streaming-policy.js +266 -0
- package/dist/channels/streaming-policy.js.map +1 -0
- package/dist/channels/telegram/ci-watcher.d.ts +5 -0
- package/dist/channels/telegram/ci-watcher.js +5 -0
- package/dist/channels/telegram/ci-watcher.js.map +1 -0
- package/dist/channels/telegram/client.d.ts +28 -0
- package/dist/channels/telegram/client.js +147 -1
- package/dist/channels/telegram/client.js.map +1 -1
- package/dist/channels/telegram/diff-first.d.ts +5 -0
- package/dist/channels/telegram/diff-first.js +5 -0
- package/dist/channels/telegram/diff-first.js.map +1 -0
- package/dist/channels/telegram/enhanced-commands.d.ts +6 -0
- package/dist/channels/telegram/enhanced-commands.js +6 -0
- package/dist/channels/telegram/enhanced-commands.js.map +1 -0
- package/dist/channels/telegram/index.d.ts +6 -0
- package/dist/channels/telegram/index.js +6 -0
- package/dist/channels/telegram/index.js.map +1 -1
- package/dist/channels/telegram/pro-formatter.d.ts +30 -0
- package/dist/channels/telegram/pro-formatter.js +276 -0
- package/dist/channels/telegram/pro-formatter.js.map +1 -0
- package/dist/channels/telegram/run-commands.d.ts +5 -0
- package/dist/channels/telegram/run-commands.js +6 -0
- package/dist/channels/telegram/run-commands.js.map +1 -0
- package/dist/channels/telegram/run-tracker.d.ts +5 -0
- package/dist/channels/telegram/run-tracker.js +5 -0
- package/dist/channels/telegram/run-tracker.js.map +1 -0
- package/dist/channels/telegram/scoped-auth.d.ts +6 -0
- package/dist/channels/telegram/scoped-auth.js +5 -0
- package/dist/channels/telegram/scoped-auth.js.map +1 -0
- package/dist/channels/telegram/types.d.ts +34 -0
- package/dist/codebuddy/client.js +14 -1
- package/dist/codebuddy/client.js.map +1 -1
- package/dist/commands/dev/index.d.ts +12 -0
- package/dist/commands/dev/index.js +231 -0
- package/dist/commands/dev/index.js.map +1 -0
- package/dist/commands/dev/workflows.d.ts +31 -0
- package/dist/commands/dev/workflows.js +214 -0
- package/dist/commands/dev/workflows.js.map +1 -0
- package/dist/commands/execpolicy.d.ts +17 -0
- package/dist/commands/execpolicy.js +155 -0
- package/dist/commands/execpolicy.js.map +1 -0
- package/dist/commands/knowledge.d.ts +13 -0
- package/dist/commands/knowledge.js +142 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/lessons.d.ts +11 -0
- package/dist/commands/lessons.js +129 -0
- package/dist/commands/lessons.js.map +1 -0
- package/dist/commands/pairing.d.ts +14 -0
- package/dist/commands/pairing.js +132 -0
- package/dist/commands/pairing.js.map +1 -0
- package/dist/commands/research/index.d.ts +13 -0
- package/dist/commands/research/index.js +91 -0
- package/dist/commands/research/index.js.map +1 -0
- package/dist/commands/run-cli/index.d.ts +11 -0
- package/dist/commands/run-cli/index.js +49 -0
- package/dist/commands/run-cli/index.js.map +1 -0
- package/dist/commands/slash/builtin-commands.js +70 -2
- package/dist/commands/slash/builtin-commands.js.map +1 -1
- package/dist/commands/todos.d.ts +9 -0
- package/dist/commands/todos.js +119 -0
- package/dist/commands/todos.js.map +1 -0
- package/dist/config/toml-config.d.ts +21 -0
- package/dist/config/toml-config.js +15 -0
- package/dist/config/toml-config.js.map +1 -1
- package/dist/context/enhanced-compression.js +12 -1
- package/dist/context/enhanced-compression.js.map +1 -1
- package/dist/context/observation-variator.d.ts +44 -0
- package/dist/context/observation-variator.js +83 -0
- package/dist/context/observation-variator.js.map +1 -0
- package/dist/context/precompaction-flush.d.ts +40 -0
- package/dist/context/precompaction-flush.js +134 -0
- package/dist/context/precompaction-flush.js.map +1 -0
- package/dist/context/restorable-compression.d.ts +80 -0
- package/dist/context/restorable-compression.js +228 -0
- package/dist/context/restorable-compression.js.map +1 -0
- package/dist/daemon/daily-reset.d.ts +77 -0
- package/dist/daemon/daily-reset.js +175 -0
- package/dist/daemon/daily-reset.js.map +1 -0
- package/dist/daemon/index.d.ts +1 -0
- package/dist/daemon/index.js +1 -0
- package/dist/daemon/index.js.map +1 -1
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -1
- package/dist/knowledge/knowledge-manager.d.ts +77 -0
- package/dist/knowledge/knowledge-manager.js +244 -0
- package/dist/knowledge/knowledge-manager.js.map +1 -0
- package/dist/memory/semantic-memory-search.d.ts +7 -0
- package/dist/memory/semantic-memory-search.js +49 -5
- package/dist/memory/semantic-memory-search.js.map +1 -1
- package/dist/observability/run-store.d.ts +133 -0
- package/dist/observability/run-store.js +419 -0
- package/dist/observability/run-store.js.map +1 -0
- package/dist/observability/run-viewer.d.ts +33 -0
- package/dist/observability/run-viewer.js +254 -0
- package/dist/observability/run-viewer.js.map +1 -0
- package/dist/optimization/cache-breakpoints.d.ts +52 -0
- package/dist/optimization/cache-breakpoints.js +97 -0
- package/dist/optimization/cache-breakpoints.js.map +1 -0
- package/dist/persistence/session-store.d.ts +3 -1
- package/dist/persistence/session-store.js +1 -1
- package/dist/persistence/session-store.js.map +1 -1
- package/dist/prompts/system-base.js +51 -7
- package/dist/prompts/system-base.js.map +1 -1
- package/dist/prompts/variation-injector.d.ts +55 -0
- package/dist/prompts/variation-injector.js +171 -0
- package/dist/prompts/variation-injector.js.map +1 -0
- package/dist/prompts/workflow-rules.d.ts +10 -0
- package/dist/prompts/workflow-rules.js +79 -0
- package/dist/prompts/workflow-rules.js.map +1 -0
- package/dist/sandbox/execpolicy.d.ts +45 -0
- package/dist/sandbox/execpolicy.js +80 -0
- package/dist/sandbox/execpolicy.js.map +1 -1
- package/dist/sandbox/os-sandbox.d.ts +25 -0
- package/dist/sandbox/os-sandbox.js +73 -0
- package/dist/sandbox/os-sandbox.js.map +1 -1
- package/dist/scheduler/cron-scheduler.d.ts +9 -0
- package/dist/scheduler/cron-scheduler.js +17 -1
- package/dist/scheduler/cron-scheduler.js.map +1 -1
- package/dist/security/security-audit.d.ts +10 -0
- package/dist/security/security-audit.js +116 -0
- package/dist/security/security-audit.js.map +1 -1
- package/dist/security/shell-env-policy.d.ts +45 -0
- package/dist/security/shell-env-policy.js +141 -0
- package/dist/security/shell-env-policy.js.map +1 -0
- package/dist/security/ssrf-guard.d.ts +61 -0
- package/dist/security/ssrf-guard.js +382 -0
- package/dist/security/ssrf-guard.js.map +1 -0
- package/dist/security/write-policy.d.ts +57 -0
- package/dist/security/write-policy.js +117 -0
- package/dist/security/write-policy.js.map +1 -0
- package/dist/services/prompt-builder.js +37 -0
- package/dist/services/prompt-builder.js.map +1 -1
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/ask-human-tool.d.ts +62 -0
- package/dist/tools/ask-human-tool.js +112 -0
- package/dist/tools/ask-human-tool.js.map +1 -0
- package/dist/tools/bash/bash-tool.d.ts +15 -0
- package/dist/tools/bash/bash-tool.js +62 -0
- package/dist/tools/bash/bash-tool.js.map +1 -1
- package/dist/tools/bash/command-validator.d.ts +1 -0
- package/dist/tools/bash/command-validator.js +5 -0
- package/dist/tools/bash/command-validator.js.map +1 -1
- package/dist/tools/create-skill-tool.d.ts +87 -0
- package/dist/tools/create-skill-tool.js +142 -0
- package/dist/tools/create-skill-tool.js.map +1 -0
- package/dist/tools/fetch-tool.js +5 -3
- package/dist/tools/fetch-tool.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan-tool.d.ts +22 -0
- package/dist/tools/plan-tool.js +128 -0
- package/dist/tools/plan-tool.js.map +1 -0
- package/dist/tools/registry/attention-tools.d.ts +32 -0
- package/dist/tools/registry/attention-tools.js +225 -0
- package/dist/tools/registry/attention-tools.js.map +1 -0
- package/dist/tools/registry/index.d.ts +9 -1
- package/dist/tools/registry/index.js +30 -2
- package/dist/tools/registry/index.js.map +1 -1
- package/dist/tools/registry/knowledge-tools.d.ts +46 -0
- package/dist/tools/registry/knowledge-tools.js +293 -0
- package/dist/tools/registry/knowledge-tools.js.map +1 -0
- package/dist/tools/registry/lessons-tools.d.ts +48 -0
- package/dist/tools/registry/lessons-tools.js +359 -0
- package/dist/tools/registry/lessons-tools.js.map +1 -0
- package/dist/tools/registry/plan-tools.d.ts +2 -0
- package/dist/tools/registry/plan-tools.js +7 -0
- package/dist/tools/registry/plan-tools.js.map +1 -0
- package/dist/tools/registry/script-tools.d.ts +2 -0
- package/dist/tools/registry/script-tools.js +7 -0
- package/dist/tools/registry/script-tools.js.map +1 -0
- package/dist/tools/registry/tool-aliases.d.ts +44 -0
- package/dist/tools/registry/tool-aliases.js +130 -0
- package/dist/tools/registry/tool-aliases.js.map +1 -0
- package/dist/tools/run-script-tool.d.ts +13 -0
- package/dist/tools/run-script-tool.js +146 -0
- package/dist/tools/run-script-tool.js.map +1 -0
- package/dist/tools/web-search.d.ts +25 -0
- package/dist/tools/web-search.js +68 -6
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/config-validation/schema.d.ts +2 -2
- package/dist/utils/debug-logger.d.ts +1 -1
- package/dist/utils/stable-json.d.ts +27 -0
- package/dist/utils/stable-json.js +50 -0
- package/dist/utils/stable-json.js.map +1 -0
- package/dist/webhooks/webhook-manager.d.ts +7 -0
- package/dist/webhooks/webhook-manager.js +29 -0
- package/dist/webhooks/webhook-manager.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Environment Policy — Codex-inspired subprocess env control
|
|
3
|
+
*
|
|
4
|
+
* Controls which environment variables are passed to every subprocess
|
|
5
|
+
* the agent spawns. Prevents accidental leakage of API keys and
|
|
6
|
+
* credentials to untrusted subprocess environments.
|
|
7
|
+
*
|
|
8
|
+
* Config (via [shell_env] in .codebuddy/config.toml):
|
|
9
|
+
*
|
|
10
|
+
* [shell_env]
|
|
11
|
+
* inherit = "all" # all | core | none
|
|
12
|
+
* exclude = ["*SECRET*", "*TOKEN*", "*KEY*", "*PASSWORD*"]
|
|
13
|
+
* include_only = [] # if set, only these vars pass (overrides exclude)
|
|
14
|
+
* # set = { NODE_ENV = "production" } # always-injected overrides
|
|
15
|
+
*
|
|
16
|
+
* Defaults strip variables matching common credential patterns while
|
|
17
|
+
* preserving PATH, HOME, USER, SHELL, TERM, LANG, etc.
|
|
18
|
+
*/
|
|
19
|
+
/** Baseline inheritance mode */
|
|
20
|
+
export type EnvInheritMode = 'all' | 'core' | 'none';
|
|
21
|
+
export interface ShellEnvPolicyConfig {
|
|
22
|
+
/** How many env vars to start with */
|
|
23
|
+
inherit?: EnvInheritMode;
|
|
24
|
+
/** Glob-style patterns to strip from inherited env */
|
|
25
|
+
exclude?: string[];
|
|
26
|
+
/** If non-empty, ONLY these vars are passed (overrides exclude) */
|
|
27
|
+
include_only?: string[];
|
|
28
|
+
/** Key/value pairs always injected into every subprocess env */
|
|
29
|
+
set?: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
export declare class ShellEnvPolicy {
|
|
32
|
+
private config;
|
|
33
|
+
constructor(config?: ShellEnvPolicyConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Build a filtered environment object for subprocess spawning.
|
|
36
|
+
* Returns a new object — never mutates process.env.
|
|
37
|
+
*/
|
|
38
|
+
buildEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a specific env var would be passed through.
|
|
41
|
+
*/
|
|
42
|
+
wouldPass(key: string): boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare function getShellEnvPolicy(config?: ShellEnvPolicyConfig): ShellEnvPolicy;
|
|
45
|
+
export declare function resetShellEnvPolicy(): void;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Environment Policy — Codex-inspired subprocess env control
|
|
3
|
+
*
|
|
4
|
+
* Controls which environment variables are passed to every subprocess
|
|
5
|
+
* the agent spawns. Prevents accidental leakage of API keys and
|
|
6
|
+
* credentials to untrusted subprocess environments.
|
|
7
|
+
*
|
|
8
|
+
* Config (via [shell_env] in .codebuddy/config.toml):
|
|
9
|
+
*
|
|
10
|
+
* [shell_env]
|
|
11
|
+
* inherit = "all" # all | core | none
|
|
12
|
+
* exclude = ["*SECRET*", "*TOKEN*", "*KEY*", "*PASSWORD*"]
|
|
13
|
+
* include_only = [] # if set, only these vars pass (overrides exclude)
|
|
14
|
+
* # set = { NODE_ENV = "production" } # always-injected overrides
|
|
15
|
+
*
|
|
16
|
+
* Defaults strip variables matching common credential patterns while
|
|
17
|
+
* preserving PATH, HOME, USER, SHELL, TERM, LANG, etc.
|
|
18
|
+
*/
|
|
19
|
+
import { logger } from '../utils/logger.js';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Core variable sets
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/** Always-safe variables for 'core' mode */
|
|
24
|
+
const CORE_VARS = new Set([
|
|
25
|
+
'PATH', 'HOME', 'USER', 'LOGNAME', 'SHELL', 'TERM', 'TERM_PROGRAM',
|
|
26
|
+
'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ', 'TMPDIR', 'TEMP', 'TMP',
|
|
27
|
+
'PWD', 'OLDPWD', 'SHLVL', 'COLORTERM', 'CLICOLOR',
|
|
28
|
+
// Node.js / npm
|
|
29
|
+
'NODE_ENV', 'NODE_PATH', 'NPM_CONFIG_PREFIX',
|
|
30
|
+
// Common CI vars (non-sensitive)
|
|
31
|
+
'CI', 'GITHUB_ACTIONS', 'GITLAB_CI',
|
|
32
|
+
]);
|
|
33
|
+
/** Default exclusion glob patterns (credential-like names) */
|
|
34
|
+
const DEFAULT_EXCLUDE_PATTERNS = [
|
|
35
|
+
'*_KEY', '*_SECRET', '*_TOKEN', '*_PASSWORD', '*_PASSWD',
|
|
36
|
+
'*_CREDENTIAL', '*_CREDENTIALS', '*_CERT', '*_PRIVATE*',
|
|
37
|
+
'AWS_*', 'OPENAI_*', 'ANTHROPIC_*', 'GOOGLE_*API*',
|
|
38
|
+
'GROK_API*', 'MORPH_API*', 'EXA_API*', 'BRAVE_API*',
|
|
39
|
+
'PERPLEXITY_API*', 'OPENROUTER_API*', 'PICOVOICE_*',
|
|
40
|
+
'DATABASE_URL', 'MONGO_*', 'REDIS_*', 'POSTGRES_*', 'MYSQL_*',
|
|
41
|
+
'JWT_SECRET', 'SESSION_SECRET', 'COOKIE_SECRET',
|
|
42
|
+
'SLACK_*TOKEN*', 'TELEGRAM_*TOKEN*', 'DISCORD_*TOKEN*',
|
|
43
|
+
'STRIPE_*', 'TWILIO_*', 'SENDGRID_*',
|
|
44
|
+
];
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Glob-style pattern matching (lightweight, no deps)
|
|
47
|
+
// ============================================================================
|
|
48
|
+
function globMatch(pattern, str) {
|
|
49
|
+
// Convert glob to regex: * → [^_]* within a word segment, handle leading/trailing *
|
|
50
|
+
const regexStr = pattern
|
|
51
|
+
.toUpperCase()
|
|
52
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex special chars
|
|
53
|
+
.replace(/\*/g, '.*');
|
|
54
|
+
try {
|
|
55
|
+
return new RegExp(`^${regexStr}$`).test(str.toUpperCase());
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function matchesAny(patterns, key) {
|
|
62
|
+
return patterns.some(p => globMatch(p, key));
|
|
63
|
+
}
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// ShellEnvPolicy
|
|
66
|
+
// ============================================================================
|
|
67
|
+
export class ShellEnvPolicy {
|
|
68
|
+
config;
|
|
69
|
+
constructor(config = {}) {
|
|
70
|
+
this.config = {
|
|
71
|
+
inherit: config.inherit ?? 'all',
|
|
72
|
+
exclude: config.exclude ?? DEFAULT_EXCLUDE_PATTERNS,
|
|
73
|
+
include_only: config.include_only ?? [],
|
|
74
|
+
set: config.set ?? {},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build a filtered environment object for subprocess spawning.
|
|
79
|
+
* Returns a new object — never mutates process.env.
|
|
80
|
+
*/
|
|
81
|
+
buildEnv(source = process.env) {
|
|
82
|
+
let env = {};
|
|
83
|
+
// Step 1: baseline from inherit mode
|
|
84
|
+
if (this.config.inherit === 'all') {
|
|
85
|
+
env = { ...source };
|
|
86
|
+
}
|
|
87
|
+
else if (this.config.inherit === 'core') {
|
|
88
|
+
for (const key of Object.keys(source)) {
|
|
89
|
+
if (CORE_VARS.has(key)) {
|
|
90
|
+
env[key] = source[key];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 'none' starts with empty {}
|
|
95
|
+
// Step 2: apply include_only whitelist (takes priority over exclude)
|
|
96
|
+
if (this.config.include_only.length > 0) {
|
|
97
|
+
const whitelisted = {};
|
|
98
|
+
for (const key of Object.keys(env)) {
|
|
99
|
+
if (matchesAny(this.config.include_only, key)) {
|
|
100
|
+
whitelisted[key] = env[key];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
env = whitelisted;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Step 3: apply exclude patterns
|
|
107
|
+
for (const key of Object.keys(env)) {
|
|
108
|
+
if (matchesAny(this.config.exclude, key)) {
|
|
109
|
+
delete env[key];
|
|
110
|
+
logger.debug(`ShellEnvPolicy: stripped env var ${key}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Step 4: inject forced overrides
|
|
115
|
+
for (const [key, value] of Object.entries(this.config.set)) {
|
|
116
|
+
env[key] = value;
|
|
117
|
+
}
|
|
118
|
+
return env;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Check if a specific env var would be passed through.
|
|
122
|
+
*/
|
|
123
|
+
wouldPass(key) {
|
|
124
|
+
const built = this.buildEnv({ [key]: 'test' });
|
|
125
|
+
return key in built;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// ============================================================================
|
|
129
|
+
// Singleton
|
|
130
|
+
// ============================================================================
|
|
131
|
+
let _policy = null;
|
|
132
|
+
export function getShellEnvPolicy(config) {
|
|
133
|
+
if (!_policy) {
|
|
134
|
+
_policy = new ShellEnvPolicy(config);
|
|
135
|
+
}
|
|
136
|
+
return _policy;
|
|
137
|
+
}
|
|
138
|
+
export function resetShellEnvPolicy() {
|
|
139
|
+
_policy = null;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=shell-env-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-env-policy.js","sourceRoot":"","sources":["../../src/security/shell-env-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF Guard — OpenClaw-inspired server-side request forgery protection
|
|
3
|
+
*
|
|
4
|
+
* Applied to all outbound HTTP calls made by the agent (web_fetch, media
|
|
5
|
+
* download, webhook delivery). Blocks all private/loopback/link-local
|
|
6
|
+
* addresses including advanced bypass vectors:
|
|
7
|
+
*
|
|
8
|
+
* - RFC 1918 / loopback / link-local IPv4
|
|
9
|
+
* - IPv4-mapped IPv6 (::ffff:127.0.0.1), full-form variants
|
|
10
|
+
* - NAT64 prefix (64:ff9b::/96, 64:ff9b:1::/48)
|
|
11
|
+
* - 6to4 (2002::/16)
|
|
12
|
+
* - Teredo (2001:0000::/32)
|
|
13
|
+
* - Octal, hex, short, packed IPv4 literals (0177.0.0.1, 127.1, 2130706433)
|
|
14
|
+
* - Sensitive headers stripped on cross-origin redirects
|
|
15
|
+
*
|
|
16
|
+
* Fails **closed** on parse errors (unknown format → blocked).
|
|
17
|
+
*/
|
|
18
|
+
export interface SSRFCheckResult {
|
|
19
|
+
safe: boolean;
|
|
20
|
+
reason?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface SSRFGuardConfig {
|
|
23
|
+
/** Additional allowed hosts (exact hostname or *.domain.com wildcard) */
|
|
24
|
+
allowedHosts?: string[];
|
|
25
|
+
/** Additional blocked CIDR-like ranges (for extension) */
|
|
26
|
+
extraBlockedHosts?: string[];
|
|
27
|
+
/** Resolve DNS and check each returned IP (default: true) */
|
|
28
|
+
resolveDns?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare class SSRFGuard {
|
|
31
|
+
private config;
|
|
32
|
+
constructor(config?: SSRFGuardConfig);
|
|
33
|
+
/**
|
|
34
|
+
* Check if a URL is safe to fetch.
|
|
35
|
+
* Resolves the hostname to IP(s) and validates each one.
|
|
36
|
+
*
|
|
37
|
+
* @returns `{safe: true}` if the URL is safe, or `{safe: false, reason}` otherwise.
|
|
38
|
+
*/
|
|
39
|
+
isSafeUrl(rawUrl: string): Promise<SSRFCheckResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Synchronous check for IP literals only (no DNS).
|
|
42
|
+
* Use for fast path when URL is already an IP literal.
|
|
43
|
+
*/
|
|
44
|
+
isSafeUrlSync(rawUrl: string): SSRFCheckResult;
|
|
45
|
+
private isAllowedHost;
|
|
46
|
+
/** Returns null if not an IP literal */
|
|
47
|
+
private checkIpLiteral;
|
|
48
|
+
private checkIPv4String;
|
|
49
|
+
private checkIPv4Uint32;
|
|
50
|
+
private checkIPv6;
|
|
51
|
+
}
|
|
52
|
+
export declare function getSSRFGuard(config?: SSRFGuardConfig): SSRFGuard;
|
|
53
|
+
export declare function resetSSRFGuard(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Convenience wrapper — use in web_fetch, webhook delivery, media download.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const check = await assertSafeUrl(url);
|
|
59
|
+
* if (!check.safe) throw new Error(`SSRF blocked: ${check.reason}`);
|
|
60
|
+
*/
|
|
61
|
+
export declare function assertSafeUrl(url: string): Promise<SSRFCheckResult>;
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF Guard — OpenClaw-inspired server-side request forgery protection
|
|
3
|
+
*
|
|
4
|
+
* Applied to all outbound HTTP calls made by the agent (web_fetch, media
|
|
5
|
+
* download, webhook delivery). Blocks all private/loopback/link-local
|
|
6
|
+
* addresses including advanced bypass vectors:
|
|
7
|
+
*
|
|
8
|
+
* - RFC 1918 / loopback / link-local IPv4
|
|
9
|
+
* - IPv4-mapped IPv6 (::ffff:127.0.0.1), full-form variants
|
|
10
|
+
* - NAT64 prefix (64:ff9b::/96, 64:ff9b:1::/48)
|
|
11
|
+
* - 6to4 (2002::/16)
|
|
12
|
+
* - Teredo (2001:0000::/32)
|
|
13
|
+
* - Octal, hex, short, packed IPv4 literals (0177.0.0.1, 127.1, 2130706433)
|
|
14
|
+
* - Sensitive headers stripped on cross-origin redirects
|
|
15
|
+
*
|
|
16
|
+
* Fails **closed** on parse errors (unknown format → blocked).
|
|
17
|
+
*/
|
|
18
|
+
import * as dns from 'dns/promises';
|
|
19
|
+
import { logger } from '../utils/logger.js';
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Private IP range matchers (IPv4)
|
|
22
|
+
// ============================================================================
|
|
23
|
+
/** Parse decimal, octal (0177.0.0.1), hex (0x7f000001), short forms (127.1) to uint32 */
|
|
24
|
+
function parseIPv4ToUint32(host) {
|
|
25
|
+
// Hex: 0x7f000001
|
|
26
|
+
if (/^0x[0-9a-f]+$/i.test(host)) {
|
|
27
|
+
const n = parseInt(host, 16);
|
|
28
|
+
return isNaN(n) ? null : n >>> 0;
|
|
29
|
+
}
|
|
30
|
+
// Pure decimal integer: 2130706433
|
|
31
|
+
if (/^\d+$/.test(host)) {
|
|
32
|
+
const n = parseInt(host, 10);
|
|
33
|
+
return isNaN(n) ? null : n >>> 0;
|
|
34
|
+
}
|
|
35
|
+
// Dotted notation: handles decimal, octal, hex per-octet and short forms
|
|
36
|
+
const parts = host.split('.');
|
|
37
|
+
if (parts.length < 1 || parts.length > 4)
|
|
38
|
+
return null;
|
|
39
|
+
const octets = [];
|
|
40
|
+
for (const part of parts) {
|
|
41
|
+
let val;
|
|
42
|
+
if (/^0x[0-9a-f]+$/i.test(part)) {
|
|
43
|
+
val = parseInt(part, 16);
|
|
44
|
+
}
|
|
45
|
+
else if (/^0[0-7]+$/.test(part)) {
|
|
46
|
+
val = parseInt(part, 8); // octal
|
|
47
|
+
}
|
|
48
|
+
else if (/^\d+$/.test(part)) {
|
|
49
|
+
val = parseInt(part, 10);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (isNaN(val) || val < 0)
|
|
55
|
+
return null;
|
|
56
|
+
octets.push(val);
|
|
57
|
+
}
|
|
58
|
+
// Short-form expansion: 127.1 → 127.0.0.1, 10.1.2 → 10.1.0.2
|
|
59
|
+
while (octets.length < 4) {
|
|
60
|
+
const last = octets.pop();
|
|
61
|
+
// last octet expands into remaining spots (like inet_aton)
|
|
62
|
+
octets.push(0);
|
|
63
|
+
octets.push(last);
|
|
64
|
+
}
|
|
65
|
+
if (octets.some(o => o > 255))
|
|
66
|
+
return null;
|
|
67
|
+
return ((octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]) >>> 0;
|
|
68
|
+
}
|
|
69
|
+
function isPrivateIPv4(uint32) {
|
|
70
|
+
// 0.0.0.0/8 — This network
|
|
71
|
+
if ((uint32 & 0xff000000) === 0x00000000)
|
|
72
|
+
return true;
|
|
73
|
+
// 10.0.0.0/8
|
|
74
|
+
if ((uint32 & 0xff000000) === 0x0a000000)
|
|
75
|
+
return true;
|
|
76
|
+
// 100.64.0.0/10 — Shared address space (RFC 6598)
|
|
77
|
+
if ((uint32 & 0xffc00000) === 0x64400000)
|
|
78
|
+
return true;
|
|
79
|
+
// 127.0.0.0/8 — Loopback
|
|
80
|
+
if ((uint32 & 0xff000000) === 0x7f000000)
|
|
81
|
+
return true;
|
|
82
|
+
// 169.254.0.0/16 — Link-local / AWS metadata
|
|
83
|
+
if ((uint32 & 0xffff0000) === 0xa9fe0000)
|
|
84
|
+
return true;
|
|
85
|
+
// 172.16.0.0/12
|
|
86
|
+
if ((uint32 & 0xfff00000) === 0xac100000)
|
|
87
|
+
return true;
|
|
88
|
+
// 192.0.0.0/24 — IETF protocol assignments
|
|
89
|
+
if ((uint32 & 0xffffff00) === 0xc0000000)
|
|
90
|
+
return true;
|
|
91
|
+
// 192.168.0.0/16
|
|
92
|
+
if ((uint32 & 0xffff0000) === 0xc0a80000)
|
|
93
|
+
return true;
|
|
94
|
+
// 198.18.0.0/15 — Benchmark testing
|
|
95
|
+
if ((uint32 & 0xfffe0000) === 0xc6120000)
|
|
96
|
+
return true;
|
|
97
|
+
// 198.51.100.0/24 — TEST-NET-2
|
|
98
|
+
if ((uint32 & 0xffffff00) === 0xc6336400)
|
|
99
|
+
return true;
|
|
100
|
+
// 203.0.113.0/24 — TEST-NET-3
|
|
101
|
+
if ((uint32 & 0xffffff00) === 0xcb007100)
|
|
102
|
+
return true;
|
|
103
|
+
// 224.0.0.0/4 — Multicast
|
|
104
|
+
if ((uint32 & 0xf0000000) === 0xe0000000)
|
|
105
|
+
return true;
|
|
106
|
+
// 240.0.0.0/4 — Reserved
|
|
107
|
+
if ((uint32 & 0xf0000000) === 0xf0000000)
|
|
108
|
+
return true;
|
|
109
|
+
// 255.255.255.255
|
|
110
|
+
if (uint32 === 0xffffffff)
|
|
111
|
+
return true;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// IPv6 private range detection
|
|
116
|
+
// ============================================================================
|
|
117
|
+
/** Expand a possibly compressed IPv6 address to 8 groups of uint16 */
|
|
118
|
+
function expandIPv6(address) {
|
|
119
|
+
try {
|
|
120
|
+
// Handle IPv4-mapped: ::ffff:1.2.3.4
|
|
121
|
+
const v4mapped = address.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);
|
|
122
|
+
if (v4mapped) {
|
|
123
|
+
const v4 = parseIPv4ToUint32(v4mapped[1]);
|
|
124
|
+
if (v4 === null)
|
|
125
|
+
return null;
|
|
126
|
+
return [0, 0, 0, 0, 0, 0xffff, (v4 >>> 16) & 0xffff, v4 & 0xffff];
|
|
127
|
+
}
|
|
128
|
+
if (!address.includes(':'))
|
|
129
|
+
return null;
|
|
130
|
+
// Split on ::
|
|
131
|
+
const halves = address.split('::');
|
|
132
|
+
if (halves.length > 2)
|
|
133
|
+
return null;
|
|
134
|
+
const parseGroups = (s) => {
|
|
135
|
+
if (s === '')
|
|
136
|
+
return [];
|
|
137
|
+
return s.split(':').map(g => {
|
|
138
|
+
// Handle embedded IPv4 in last two groups
|
|
139
|
+
if (g.includes('.')) {
|
|
140
|
+
const v4 = parseIPv4ToUint32(g);
|
|
141
|
+
return v4 !== null ? [((v4 >>> 16) & 0xffff), v4 & 0xffff] : null;
|
|
142
|
+
}
|
|
143
|
+
const n = parseInt(g, 16);
|
|
144
|
+
return isNaN(n) ? null : [n];
|
|
145
|
+
}).reduce((acc, val) => {
|
|
146
|
+
if (acc === null || val === null)
|
|
147
|
+
return null;
|
|
148
|
+
return [...acc, ...(Array.isArray(val[0]) ? val[0] : val)];
|
|
149
|
+
}, []);
|
|
150
|
+
};
|
|
151
|
+
if (halves.length === 1) {
|
|
152
|
+
const groups = parseGroups(halves[0]);
|
|
153
|
+
if (!groups || groups.length !== 8)
|
|
154
|
+
return null;
|
|
155
|
+
return groups;
|
|
156
|
+
}
|
|
157
|
+
const left = parseGroups(halves[0]) ?? [];
|
|
158
|
+
const right = parseGroups(halves[1]) ?? [];
|
|
159
|
+
const fill = new Array(8 - left.length - right.length).fill(0);
|
|
160
|
+
const groups = [...left, ...fill, ...right];
|
|
161
|
+
if (groups.length !== 8)
|
|
162
|
+
return null;
|
|
163
|
+
return groups;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function isPrivateIPv6(address) {
|
|
170
|
+
const addr = address.toLowerCase().replace(/^\[|\]$/g, ''); // strip brackets
|
|
171
|
+
// ::1 — loopback
|
|
172
|
+
if (addr === '::1')
|
|
173
|
+
return true;
|
|
174
|
+
// :: — unspecified
|
|
175
|
+
if (addr === '::')
|
|
176
|
+
return true;
|
|
177
|
+
const groups = expandIPv6(addr);
|
|
178
|
+
if (!groups)
|
|
179
|
+
return false; // parse error → caller should handle
|
|
180
|
+
const g = groups;
|
|
181
|
+
// ::ffff:0:0/96 — IPv4-mapped
|
|
182
|
+
if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0xffff) {
|
|
183
|
+
const v4 = (g[6] << 16) | g[7];
|
|
184
|
+
return isPrivateIPv4(v4 >>> 0);
|
|
185
|
+
}
|
|
186
|
+
// 0:0:0:0:0:0::/96 — IPv4-compatible (deprecated but still mapped)
|
|
187
|
+
if (g[0] === 0 && g[1] === 0 && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) {
|
|
188
|
+
const v4 = (g[6] << 16) | g[7];
|
|
189
|
+
if (v4 !== 0 && v4 !== 1)
|
|
190
|
+
return isPrivateIPv4(v4 >>> 0);
|
|
191
|
+
}
|
|
192
|
+
// 64:ff9b::/96 — NAT64 (RFC 6052)
|
|
193
|
+
if (g[0] === 0x0064 && g[1] === 0xff9b && g[2] === 0 && g[3] === 0 && g[4] === 0 && g[5] === 0) {
|
|
194
|
+
const v4 = (g[6] << 16) | g[7];
|
|
195
|
+
return isPrivateIPv4(v4 >>> 0);
|
|
196
|
+
}
|
|
197
|
+
// 64:ff9b:1::/48 — NAT64 (RFC 8215)
|
|
198
|
+
if (g[0] === 0x0064 && g[1] === 0xff9b && g[2] === 0x0001)
|
|
199
|
+
return true;
|
|
200
|
+
// 2002::/16 — 6to4 (RFC 3056): embedded IPv4 is in groups [1] and [2]
|
|
201
|
+
if (g[0] === 0x2002) {
|
|
202
|
+
const v4 = (g[1] << 16) | g[2];
|
|
203
|
+
return isPrivateIPv4(v4 >>> 0);
|
|
204
|
+
}
|
|
205
|
+
// 2001:0000::/32 — Teredo (RFC 4380)
|
|
206
|
+
if (g[0] === 0x2001 && g[1] === 0x0000)
|
|
207
|
+
return true;
|
|
208
|
+
// fc00::/7 — Unique local
|
|
209
|
+
if ((g[0] & 0xfe00) === 0xfc00)
|
|
210
|
+
return true;
|
|
211
|
+
// fe80::/10 — Link-local
|
|
212
|
+
if ((g[0] & 0xffc0) === 0xfe80)
|
|
213
|
+
return true;
|
|
214
|
+
// ff00::/8 — Multicast
|
|
215
|
+
if ((g[0] & 0xff00) === 0xff00)
|
|
216
|
+
return true;
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// SSRFGuard
|
|
221
|
+
// ============================================================================
|
|
222
|
+
export class SSRFGuard {
|
|
223
|
+
config;
|
|
224
|
+
constructor(config = {}) {
|
|
225
|
+
this.config = {
|
|
226
|
+
allowedHosts: config.allowedHosts ?? [],
|
|
227
|
+
extraBlockedHosts: config.extraBlockedHosts ?? [],
|
|
228
|
+
resolveDns: config.resolveDns ?? true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Check if a URL is safe to fetch.
|
|
233
|
+
* Resolves the hostname to IP(s) and validates each one.
|
|
234
|
+
*
|
|
235
|
+
* @returns `{safe: true}` if the URL is safe, or `{safe: false, reason}` otherwise.
|
|
236
|
+
*/
|
|
237
|
+
async isSafeUrl(rawUrl) {
|
|
238
|
+
let parsed;
|
|
239
|
+
try {
|
|
240
|
+
parsed = new URL(rawUrl);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return { safe: false, reason: 'Invalid URL (parse error)' };
|
|
244
|
+
}
|
|
245
|
+
// Only allow http/https
|
|
246
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
247
|
+
return { safe: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
248
|
+
}
|
|
249
|
+
const host = parsed.hostname.toLowerCase();
|
|
250
|
+
// Check allowlist first
|
|
251
|
+
if (this.isAllowedHost(host)) {
|
|
252
|
+
return { safe: true };
|
|
253
|
+
}
|
|
254
|
+
// Check extra blocked hosts
|
|
255
|
+
if (this.config.extraBlockedHosts.some(h => host === h || host.endsWith('.' + h))) {
|
|
256
|
+
return { safe: false, reason: `Host on blocked list: ${host}` };
|
|
257
|
+
}
|
|
258
|
+
// Check if host is an IP literal
|
|
259
|
+
const ipCheck = this.checkIpLiteral(host);
|
|
260
|
+
if (ipCheck !== null)
|
|
261
|
+
return ipCheck;
|
|
262
|
+
// Resolve DNS and check each returned address
|
|
263
|
+
if (this.config.resolveDns) {
|
|
264
|
+
try {
|
|
265
|
+
const addresses = await dns.lookup(host, { all: true });
|
|
266
|
+
for (const { address, family } of addresses) {
|
|
267
|
+
const result = family === 6
|
|
268
|
+
? this.checkIPv6(address)
|
|
269
|
+
: this.checkIPv4String(address);
|
|
270
|
+
if (!result.safe) {
|
|
271
|
+
return { safe: false, reason: `Host ${host} resolves to private IP: ${address} — ${result.reason}` };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
// DNS resolution failure → fail closed
|
|
277
|
+
return { safe: false, reason: `DNS resolution failed for ${host}: ${err}` };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return { safe: true };
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Synchronous check for IP literals only (no DNS).
|
|
284
|
+
* Use for fast path when URL is already an IP literal.
|
|
285
|
+
*/
|
|
286
|
+
isSafeUrlSync(rawUrl) {
|
|
287
|
+
let parsed;
|
|
288
|
+
try {
|
|
289
|
+
parsed = new URL(rawUrl);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return { safe: false, reason: 'Invalid URL' };
|
|
293
|
+
}
|
|
294
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
295
|
+
return { safe: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
296
|
+
}
|
|
297
|
+
const host = parsed.hostname;
|
|
298
|
+
const ipCheck = this.checkIpLiteral(host);
|
|
299
|
+
if (ipCheck !== null)
|
|
300
|
+
return ipCheck;
|
|
301
|
+
// Cannot verify hostname without DNS — return safe (async version required)
|
|
302
|
+
return { safe: true };
|
|
303
|
+
}
|
|
304
|
+
isAllowedHost(host) {
|
|
305
|
+
return this.config.allowedHosts.some(allowed => {
|
|
306
|
+
if (allowed.startsWith('*.')) {
|
|
307
|
+
return host.endsWith(allowed.slice(1));
|
|
308
|
+
}
|
|
309
|
+
return host === allowed;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/** Returns null if not an IP literal */
|
|
313
|
+
checkIpLiteral(host) {
|
|
314
|
+
// IPv6 literal in brackets [::1]
|
|
315
|
+
if (host.startsWith('[') && host.endsWith(']')) {
|
|
316
|
+
return this.checkIPv6(host.slice(1, -1));
|
|
317
|
+
}
|
|
318
|
+
// Try parsing as IPv4 (handles octal/hex/short forms)
|
|
319
|
+
const v4 = parseIPv4ToUint32(host);
|
|
320
|
+
if (v4 !== null) {
|
|
321
|
+
return this.checkIPv4Uint32(v4);
|
|
322
|
+
}
|
|
323
|
+
// Try parsing as plain IPv6 (no brackets)
|
|
324
|
+
if (host.includes(':')) {
|
|
325
|
+
return this.checkIPv6(host);
|
|
326
|
+
}
|
|
327
|
+
return null; // Not an IP literal
|
|
328
|
+
}
|
|
329
|
+
checkIPv4String(address) {
|
|
330
|
+
const v4 = parseIPv4ToUint32(address);
|
|
331
|
+
if (v4 === null)
|
|
332
|
+
return { safe: false, reason: `Could not parse IPv4 address: ${address}` };
|
|
333
|
+
return this.checkIPv4Uint32(v4);
|
|
334
|
+
}
|
|
335
|
+
checkIPv4Uint32(uint32) {
|
|
336
|
+
if (isPrivateIPv4(uint32)) {
|
|
337
|
+
const a = [(uint32 >>> 24) & 0xff, (uint32 >>> 16) & 0xff, (uint32 >>> 8) & 0xff, uint32 & 0xff];
|
|
338
|
+
return { safe: false, reason: `Private/reserved IPv4: ${a.join('.')}` };
|
|
339
|
+
}
|
|
340
|
+
return { safe: true };
|
|
341
|
+
}
|
|
342
|
+
checkIPv6(address) {
|
|
343
|
+
if (isPrivateIPv6(address)) {
|
|
344
|
+
return { safe: false, reason: `Private/reserved IPv6: ${address}` };
|
|
345
|
+
}
|
|
346
|
+
// Expand to verify parse succeeded
|
|
347
|
+
const groups = expandIPv6(address.toLowerCase());
|
|
348
|
+
if (groups === null) {
|
|
349
|
+
return { safe: false, reason: `Could not parse IPv6 address: ${address}` };
|
|
350
|
+
}
|
|
351
|
+
return { safe: true };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// Singleton
|
|
356
|
+
// ============================================================================
|
|
357
|
+
let _guard = null;
|
|
358
|
+
export function getSSRFGuard(config) {
|
|
359
|
+
if (!_guard)
|
|
360
|
+
_guard = new SSRFGuard(config);
|
|
361
|
+
return _guard;
|
|
362
|
+
}
|
|
363
|
+
export function resetSSRFGuard() {
|
|
364
|
+
_guard = null;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Convenience wrapper — use in web_fetch, webhook delivery, media download.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* const check = await assertSafeUrl(url);
|
|
371
|
+
* if (!check.safe) throw new Error(`SSRF blocked: ${check.reason}`);
|
|
372
|
+
*/
|
|
373
|
+
export async function assertSafeUrl(url) {
|
|
374
|
+
try {
|
|
375
|
+
return await getSSRFGuard().isSafeUrl(url);
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
logger.warn('SSRFGuard check failed', { url, err });
|
|
379
|
+
return { safe: false, reason: `SSRF guard error: ${err}` };
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=ssrf-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-guard.js","sourceRoot":"","sources":["../../src/security/ssrf-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAoB5C,+EAA+E;AAC/E,mCAAmC;AACnC,+EAA+E;AAE/E,yFAAyF;AACzF,SAAS,iBAAiB,CAAC,IAAY;IACrC,kBAAkB;IAClB,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,yEAAyE;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAW,CAAC;QAChB,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ;QACnC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,6DAA6D;IAC7D,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAG,CAAC;QAC3B,2DAA2D;QAC3D,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,2BAA2B;IAC3B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,aAAa;IACb,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,kDAAkD;IAClD,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,yBAAyB;IACzB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,6CAA6C;IAC7C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,gBAAgB;IAChB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,2CAA2C;IAC3C,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,iBAAiB;IACjB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,oCAAoC;IACpC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,+BAA+B;IAC/B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,8BAA8B;IAC9B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,0BAA0B;IAC1B,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,yBAAyB;IACzB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACtD,kBAAkB;IAClB,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAEvC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,+BAA+B;AAC/B,+EAA+E;AAE/E,sEAAsE;AACtE,SAAS,UAAU,CAAC,OAAe;IACjC,IAAI,CAAC;QACH,qCAAqC;QACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACjE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,EAAE,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,EAAE,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC7B,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAExC,cAAc;QACd,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAEnC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAmB,EAAE;YACjD,IAAI,CAAC,KAAK,EAAE;gBAAE,OAAO,EAAE,CAAC;YACxB,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC1B,0CAA0C;gBAC1C,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;oBAChC,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACpE,CAAC;gBACD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC,MAAM,CAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBACtC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI;oBAAE,OAAO,IAAI,CAAC;gBAC9C,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAa,CAAC,CAAC;YACzE,CAAC,EAAE,EAAE,CAAC,CAAC;QACT,CAAC,CAAC;QAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAChD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB;IAE7E,iBAAiB;IACjB,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAChC,mBAAmB;IACnB,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC,CAAC,qCAAqC;IAEhE,MAAM,CAAC,GAAG,MAAM,CAAC;IAEjB,8BAA8B;IAC9B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QAC1F,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,mEAAmE;IACnE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACrF,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;YAAE,OAAO,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,kCAAkC;IAClC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/F,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,oCAAoC;IACpC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAEvE,sEAAsE;IACtE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAEpD,0BAA0B;IAC1B,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAE5C,yBAAyB;IACzB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAE5C,uBAAuB;IACvB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAE5C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,OAAO,SAAS;IACZ,MAAM,CAA4B;IAE1C,YAAY,SAA0B,EAAE;QACtC,IAAI,CAAC,MAAM,GAAG;YACZ,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;YACvC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,EAAE;YACjD,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;SACtC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,MAAc;QAC5B,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC;QAC9D,CAAC;QAED,wBAAwB;QACxB,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QACzE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAE3C,wBAAwB;QACxB,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,4BAA4B;QAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,IAAI,EAAE,EAAE,CAAC;QAClE,CAAC;QAED,iCAAiC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC;QAErC,8CAA8C;QAC9C,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxD,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;oBAC5C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;wBACzB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;wBACzB,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;oBAClC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;wBACjB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,4BAA4B,OAAO,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;oBACvG,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,uCAAuC;gBACvC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,6BAA6B,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;YAC9E,CAAC;QACH,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,MAAc;QAC1B,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;QAChD,CAAC;QAED,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QACzE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC;QAErC,4EAA4E;QAC5E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,aAAa,CAAC,IAAY;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YAC7C,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;YACD,OAAO,IAAI,KAAK,OAAO,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,wCAAwC;IAChC,cAAc,CAAC,IAAY;QACjC,iCAAiC;QACjC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;QAED,sDAAsD;QACtD,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;QAED,0CAA0C;QAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,OAAO,IAAI,CAAC,CAAC,oBAAoB;IACnC,CAAC;IAEO,eAAe,CAAC,OAAe;QACrC,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,iCAAiC,OAAO,EAAE,EAAE,CAAC;QAC5F,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAEO,eAAe,CAAC,MAAc;QACpC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;YACjG,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QAC1E,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,SAAS,CAAC,OAAe;QAC/B,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,OAAO,EAAE,EAAE,CAAC;QACtE,CAAC;QACD,mCAAmC;QACnC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,iCAAiC,OAAO,EAAE,EAAE,CAAC;QAC7E,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;CACF;AAED,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,IAAI,MAAM,GAAqB,IAAI,CAAC;AAEpC,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,GAAG,EAAE,EAAE,CAAC;IAC7D,CAAC;AACH,CAAC"}
|