@n8n/n8n-nodes-langchain 1.117.0 → 1.118.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.
- package/dist/credentials/McpOAuth2Api.credentials.js +45 -0
- package/dist/credentials/McpOAuth2Api.credentials.js.map +1 -0
- package/dist/known/credentials.json +10 -0
- package/dist/known/nodes.json +4 -0
- package/dist/nodes/Guardrails/Guardrails.node.js +73 -0
- package/dist/nodes/Guardrails/Guardrails.node.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/jailbreak.js +50 -0
- package/dist/nodes/Guardrails/actions/checks/jailbreak.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/keywords.js +66 -0
- package/dist/nodes/Guardrails/actions/checks/keywords.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/nsfw.js +53 -0
- package/dist/nodes/Guardrails/actions/checks/nsfw.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/pii.js +232 -0
- package/dist/nodes/Guardrails/actions/checks/pii.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/secretKeys.js +201 -0
- package/dist/nodes/Guardrails/actions/checks/secretKeys.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/topicalAlignment.js +38 -0
- package/dist/nodes/Guardrails/actions/checks/topicalAlignment.js.map +1 -0
- package/dist/nodes/Guardrails/actions/checks/urls.js +245 -0
- package/dist/nodes/Guardrails/actions/checks/urls.js.map +1 -0
- package/dist/nodes/Guardrails/actions/process.js +220 -0
- package/dist/nodes/Guardrails/actions/process.js.map +1 -0
- package/dist/nodes/Guardrails/actions/types.js +35 -0
- package/dist/nodes/Guardrails/actions/types.js.map +1 -0
- package/dist/nodes/Guardrails/description.js +454 -0
- package/dist/nodes/Guardrails/description.js.map +1 -0
- package/dist/nodes/Guardrails/guardrails.svg +11 -0
- package/dist/nodes/Guardrails/helpers/base.js +67 -0
- package/dist/nodes/Guardrails/helpers/base.js.map +1 -0
- package/dist/nodes/Guardrails/helpers/common.js +45 -0
- package/dist/nodes/Guardrails/helpers/common.js.map +1 -0
- package/dist/nodes/Guardrails/helpers/configureNodeInputs.js +50 -0
- package/dist/nodes/Guardrails/helpers/configureNodeInputs.js.map +1 -0
- package/dist/nodes/Guardrails/helpers/mappers.js +100 -0
- package/dist/nodes/Guardrails/helpers/mappers.js.map +1 -0
- package/dist/nodes/Guardrails/helpers/model.js +144 -0
- package/dist/nodes/Guardrails/helpers/model.js.map +1 -0
- package/dist/nodes/Guardrails/helpers/preflight.js +61 -0
- package/dist/nodes/Guardrails/helpers/preflight.js.map +1 -0
- package/dist/nodes/agents/Agent/V1/AgentV1.node.js +6 -0
- package/dist/nodes/agents/Agent/V1/AgentV1.node.js.map +1 -1
- package/dist/nodes/agents/Agent/V2/AgentV2.node.js +8 -0
- package/dist/nodes/agents/Agent/V2/AgentV2.node.js.map +1 -1
- package/dist/nodes/agents/Agent/V3/AgentV3.node.js +8 -0
- package/dist/nodes/agents/Agent/V3/AgentV3.node.js.map +1 -1
- package/dist/nodes/agents/Agent/agents/SqlAgent/description.js +10 -0
- package/dist/nodes/agents/Agent/agents/SqlAgent/description.js.map +1 -1
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js +22 -0
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js.map +1 -1
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/execute.js +8 -3
- package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/execute.js.map +1 -1
- package/dist/nodes/chains/ChainLLM/methods/config.js +4 -0
- package/dist/nodes/chains/ChainLLM/methods/config.js.map +1 -1
- package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js +6 -0
- package/dist/nodes/chains/ChainRetrievalQA/ChainRetrievalQa.node.js.map +1 -1
- package/dist/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.js +448 -24
- package/dist/nodes/llms/LMChatOpenAi/LmChatOpenAi.node.js.map +1 -1
- package/dist/nodes/llms/LMChatOpenAi/common.js +155 -0
- package/dist/nodes/llms/LMChatOpenAi/common.js.map +1 -0
- package/dist/nodes/llms/LMChatOpenAi/types.js +17 -0
- package/dist/nodes/llms/LMChatOpenAi/types.js.map +1 -0
- package/dist/nodes/mcp/McpClientTool/McpClientTool.node.js +48 -3
- package/dist/nodes/mcp/McpClientTool/McpClientTool.node.js.map +1 -1
- package/dist/nodes/mcp/McpClientTool/loadOptions.js +2 -1
- package/dist/nodes/mcp/McpClientTool/loadOptions.js.map +1 -1
- package/dist/nodes/mcp/McpClientTool/types.js.map +1 -1
- package/dist/nodes/mcp/McpClientTool/utils.js +66 -4
- package/dist/nodes/mcp/McpClientTool/utils.js.map +1 -1
- package/dist/nodes/trigger/ChatTrigger/ChatTrigger.node.js +45 -2
- package/dist/nodes/trigger/ChatTrigger/ChatTrigger.node.js.map +1 -1
- package/dist/nodes/vendors/OpenAi/helpers/utils.js +5 -0
- package/dist/nodes/vendors/OpenAi/helpers/utils.js.map +1 -1
- package/dist/nodes/vendors/OpenAi/v1/actions/assistant/message.operation.js +6 -12
- package/dist/nodes/vendors/OpenAi/v1/actions/assistant/message.operation.js.map +1 -1
- package/dist/nodes/vendors/OpenAi/v2/actions/text/response.operation.js +31 -6
- package/dist/nodes/vendors/OpenAi/v2/actions/text/response.operation.js.map +1 -1
- package/dist/types/credentials.json +1 -0
- package/dist/types/nodes.json +12 -11
- package/dist/utils/descriptions.js +18 -0
- package/dist/utils/descriptions.js.map +1 -1
- package/dist/utils/helpers.js +4 -1
- package/dist/utils/helpers.js.map +1 -1
- package/package.json +10 -8
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var secretKeys_exports = {};
|
|
20
|
+
__export(secretKeys_exports, {
|
|
21
|
+
createSecretKeysCheckFn: () => createSecretKeysCheckFn,
|
|
22
|
+
secretKeysCheck: () => secretKeysCheck
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(secretKeys_exports);
|
|
25
|
+
const COMMON_KEY_PREFIXES = [
|
|
26
|
+
"key-",
|
|
27
|
+
"sk-",
|
|
28
|
+
"sk_",
|
|
29
|
+
"pk_",
|
|
30
|
+
"pk-",
|
|
31
|
+
"ghp_",
|
|
32
|
+
"AKIA",
|
|
33
|
+
"xox",
|
|
34
|
+
"SG.",
|
|
35
|
+
"hf_",
|
|
36
|
+
"api-",
|
|
37
|
+
"apikey-",
|
|
38
|
+
"token-",
|
|
39
|
+
"secret-",
|
|
40
|
+
"SHA:",
|
|
41
|
+
"Bearer "
|
|
42
|
+
];
|
|
43
|
+
const ALLOWED_EXTENSIONS = [
|
|
44
|
+
".py",
|
|
45
|
+
".js",
|
|
46
|
+
".html",
|
|
47
|
+
".css",
|
|
48
|
+
".json",
|
|
49
|
+
".md",
|
|
50
|
+
".txt",
|
|
51
|
+
".csv",
|
|
52
|
+
".xml",
|
|
53
|
+
".yaml",
|
|
54
|
+
".yml",
|
|
55
|
+
".ini",
|
|
56
|
+
".conf",
|
|
57
|
+
".config",
|
|
58
|
+
".log",
|
|
59
|
+
".sql",
|
|
60
|
+
".sh",
|
|
61
|
+
".bat",
|
|
62
|
+
".dll",
|
|
63
|
+
".so",
|
|
64
|
+
".dylib",
|
|
65
|
+
".jar",
|
|
66
|
+
".war",
|
|
67
|
+
".php",
|
|
68
|
+
".rb",
|
|
69
|
+
".go",
|
|
70
|
+
".rs",
|
|
71
|
+
".ts",
|
|
72
|
+
".jsx",
|
|
73
|
+
".vue",
|
|
74
|
+
".cpp",
|
|
75
|
+
".c",
|
|
76
|
+
".h",
|
|
77
|
+
".cs",
|
|
78
|
+
".fs",
|
|
79
|
+
".vb",
|
|
80
|
+
".doc",
|
|
81
|
+
".docx",
|
|
82
|
+
".xls",
|
|
83
|
+
".xlsx",
|
|
84
|
+
".ppt",
|
|
85
|
+
".pptx",
|
|
86
|
+
".pdf",
|
|
87
|
+
".jpg",
|
|
88
|
+
".jpeg",
|
|
89
|
+
".png"
|
|
90
|
+
];
|
|
91
|
+
const CONFIGS = {
|
|
92
|
+
strict: {
|
|
93
|
+
min_length: 10,
|
|
94
|
+
min_entropy: 3,
|
|
95
|
+
// Lowered from 3.5 to be more reasonable
|
|
96
|
+
min_diversity: 2,
|
|
97
|
+
strict_mode: true
|
|
98
|
+
},
|
|
99
|
+
balanced: {
|
|
100
|
+
min_length: 10,
|
|
101
|
+
// Lowered to catch more common keys
|
|
102
|
+
min_entropy: 3.8,
|
|
103
|
+
min_diversity: 3,
|
|
104
|
+
strict_mode: false
|
|
105
|
+
},
|
|
106
|
+
permissive: {
|
|
107
|
+
min_length: 30,
|
|
108
|
+
min_entropy: 4,
|
|
109
|
+
min_diversity: 2,
|
|
110
|
+
// Lowered from 3 to be more reasonable
|
|
111
|
+
strict_mode: false
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
function entropy(s) {
|
|
115
|
+
if (s.length === 0) return 0;
|
|
116
|
+
const counts = {};
|
|
117
|
+
for (const c of s) {
|
|
118
|
+
counts[c] = (counts[c] || 0) + 1;
|
|
119
|
+
}
|
|
120
|
+
let entropy2 = 0;
|
|
121
|
+
for (const count of Object.values(counts)) {
|
|
122
|
+
const probability = count / s.length;
|
|
123
|
+
entropy2 -= probability * Math.log2(probability);
|
|
124
|
+
}
|
|
125
|
+
return entropy2;
|
|
126
|
+
}
|
|
127
|
+
function charDiversity(s) {
|
|
128
|
+
return [
|
|
129
|
+
s.split("").some((c) => c === c.toLowerCase() && c !== c.toUpperCase()),
|
|
130
|
+
// lowercase
|
|
131
|
+
s.split("").some((c) => c === c.toUpperCase() && c !== c.toLowerCase()),
|
|
132
|
+
// uppercase
|
|
133
|
+
s.split("").some((c) => /\d/.test(c)),
|
|
134
|
+
// digits
|
|
135
|
+
s.split("").some((c) => !/\w/.test(c))
|
|
136
|
+
// special characters
|
|
137
|
+
].filter(Boolean).length;
|
|
138
|
+
}
|
|
139
|
+
function containsAllowedPattern(text) {
|
|
140
|
+
const urlPattern = /^https?:\/\/[a-zA-Z0-9.-]+\/?[a-zA-Z0-9.\/_-]*$/i;
|
|
141
|
+
if (urlPattern.test(text)) {
|
|
142
|
+
if (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
const extPattern = new RegExp(
|
|
148
|
+
`^[^\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace(".", "\\.")).join("|")})$`,
|
|
149
|
+
"i"
|
|
150
|
+
);
|
|
151
|
+
return extPattern.test(text);
|
|
152
|
+
}
|
|
153
|
+
function isSecretCandidate(s, cfg, customRegex) {
|
|
154
|
+
if (customRegex) {
|
|
155
|
+
for (const pattern of customRegex) {
|
|
156
|
+
try {
|
|
157
|
+
const regex = new RegExp(pattern);
|
|
158
|
+
if (regex.test(s)) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!cfg.strict_mode && containsAllowedPattern(s)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const longEnough = s.length >= cfg.min_length;
|
|
170
|
+
const diverse = charDiversity(s) >= cfg.min_diversity;
|
|
171
|
+
if (COMMON_KEY_PREFIXES.some((prefix) => s.startsWith(prefix))) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
if (!(longEnough && diverse)) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return entropy(s) >= cfg.min_entropy;
|
|
178
|
+
}
|
|
179
|
+
function detectSecretKeys(text, cfg, config) {
|
|
180
|
+
const words = text.split(/\s+/).map((w) => w.replace(/[*#]/g, ""));
|
|
181
|
+
const secrets = words.filter((w) => isSecretCandidate(w, cfg, config.customRegex));
|
|
182
|
+
return {
|
|
183
|
+
guardrailName: "secretKeys",
|
|
184
|
+
tripwireTriggered: secrets.length > 0,
|
|
185
|
+
info: {
|
|
186
|
+
maskEntities: { SECRET: secrets },
|
|
187
|
+
detectedSecrets: secrets
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const secretKeysCheck = (data, config) => {
|
|
192
|
+
const cfg = CONFIGS[config.threshold];
|
|
193
|
+
return detectSecretKeys(data, cfg, config);
|
|
194
|
+
};
|
|
195
|
+
const createSecretKeysCheckFn = (config) => (input) => secretKeysCheck(input, config);
|
|
196
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
197
|
+
0 && (module.exports = {
|
|
198
|
+
createSecretKeysCheckFn,
|
|
199
|
+
secretKeysCheck
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=secretKeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/secretKeys.ts"],"sourcesContent":["/**\n * Secret key detection guardrail module.\n *\n * This module provides functions and configuration for detecting potential API keys,\n * secrets, and credentials in text. It includes entropy and diversity checks, pattern\n * recognition, and a guardrail check_fn for runtime enforcement.\n */\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type SecretKeysConfig = {\n\tthreshold: 'strict' | 'balanced' | 'permissive';\n\tcustomRegex?: string[];\n};\n\n/**\n * Common key prefixes used in secret keys.\n */\nconst COMMON_KEY_PREFIXES = [\n\t'key-',\n\t'sk-',\n\t'sk_',\n\t'pk_',\n\t'pk-',\n\t'ghp_',\n\t'AKIA',\n\t'xox',\n\t'SG.',\n\t'hf_',\n\t'api-',\n\t'apikey-',\n\t'token-',\n\t'secret-',\n\t'SHA:',\n\t'Bearer ',\n];\n\n/**\n * File extensions to ignore when strict_mode is False.\n */\nconst ALLOWED_EXTENSIONS = [\n\t'.py',\n\t'.js',\n\t'.html',\n\t'.css',\n\t'.json',\n\t'.md',\n\t'.txt',\n\t'.csv',\n\t'.xml',\n\t'.yaml',\n\t'.yml',\n\t'.ini',\n\t'.conf',\n\t'.config',\n\t'.log',\n\t'.sql',\n\t'.sh',\n\t'.bat',\n\t'.dll',\n\t'.so',\n\t'.dylib',\n\t'.jar',\n\t'.war',\n\t'.php',\n\t'.rb',\n\t'.go',\n\t'.rs',\n\t'.ts',\n\t'.jsx',\n\t'.vue',\n\t'.cpp',\n\t'.c',\n\t'.h',\n\t'.cs',\n\t'.fs',\n\t'.vb',\n\t'.doc',\n\t'.docx',\n\t'.xls',\n\t'.xlsx',\n\t'.ppt',\n\t'.pptx',\n\t'.pdf',\n\t'.jpg',\n\t'.jpeg',\n\t'.png',\n];\n\n/**\n * Configuration presets for different sensitivity levels.\n */\nconst CONFIGS: Record<\n\tstring,\n\t{\n\t\tmin_length: number;\n\t\tmin_entropy: number;\n\t\tmin_diversity: number;\n\t\tstrict_mode: boolean;\n\t}\n> = {\n\tstrict: {\n\t\tmin_length: 10,\n\t\tmin_entropy: 3.0, // Lowered from 3.5 to be more reasonable\n\t\tmin_diversity: 2,\n\t\tstrict_mode: true,\n\t},\n\tbalanced: {\n\t\tmin_length: 10, // Lowered to catch more common keys\n\t\tmin_entropy: 3.8,\n\t\tmin_diversity: 3,\n\t\tstrict_mode: false,\n\t},\n\tpermissive: {\n\t\tmin_length: 30,\n\t\tmin_entropy: 4.0,\n\t\tmin_diversity: 2, // Lowered from 3 to be more reasonable\n\t\tstrict_mode: false,\n\t},\n};\n\n/**\n * Calculate the Shannon entropy of a string.\n */\nfunction entropy(s: string): number {\n\tif (s.length === 0) return 0;\n\n\tconst counts: Record<string, number> = {};\n\tfor (const c of s) {\n\t\tcounts[c] = (counts[c] || 0) + 1;\n\t}\n\n\tlet entropy = 0;\n\tfor (const count of Object.values(counts)) {\n\t\tconst probability = count / s.length;\n\t\tentropy -= probability * Math.log2(probability);\n\t}\n\n\treturn entropy;\n}\n\n/**\n * Count the number of character types present in a string.\n */\nfunction charDiversity(s: string): number {\n\treturn [\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toLowerCase() && c !== c.toUpperCase()), // lowercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toUpperCase() && c !== c.toLowerCase()), // uppercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => /\\d/.test(c)), // digits\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => !/\\w/.test(c)), // special characters\n\t].filter(Boolean).length;\n}\n\n/**\n * Check if text contains allowed URL or file extension patterns.\n */\nfunction containsAllowedPattern(text: string): boolean {\n\t// Check if it's a URL pattern\n\tconst urlPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/?[a-zA-Z0-9.\\/_-]*$/i;\n\tif (urlPattern.test(text)) {\n\t\t// If it's a URL, check if it contains any secret patterns\n\t\t// If it contains secrets, don't allow it\n\t\tif (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Regex for allowed file extensions - must end with the extension\n\tconst extPattern = new RegExp(\n\t\t`^[^\\\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace('.', '\\\\.')).join('|')})$`,\n\t\t'i',\n\t);\n\treturn extPattern.test(text);\n}\n\n/**\n * Check if a string is a secret key using the specified criteria.\n */\nfunction isSecretCandidate(\n\ts: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tcustomRegex?: string[],\n): boolean {\n\t// Check custom patterns first if provided\n\tif (customRegex) {\n\t\tfor (const pattern of customRegex) {\n\t\t\ttry {\n\t\t\t\tconst regex = new RegExp(pattern);\n\t\t\t\tif (regex.test(s)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern, skip\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!cfg.strict_mode && containsAllowedPattern(s)) {\n\t\treturn false;\n\t}\n\n\tconst longEnough = s.length >= cfg.min_length;\n\tconst diverse = charDiversity(s) >= cfg.min_diversity;\n\n\t// Check common prefixes first - these should always be detected\n\tif (COMMON_KEY_PREFIXES.some((prefix) => s.startsWith(prefix))) {\n\t\treturn true;\n\t}\n\n\t// For other candidates, check length and diversity\n\tif (!(longEnough && diverse)) {\n\t\treturn false;\n\t}\n\n\treturn entropy(s) >= cfg.min_entropy;\n}\n\n/**\n * Detect potential secret keys in text.\n */\nfunction detectSecretKeys(\n\ttext: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tconfig: SecretKeysConfig,\n): GuardrailResult {\n\tconst words = text.split(/\\s+/).map((w) => w.replace(/[*#]/g, ''));\n\tconst secrets = words.filter((w) => isSecretCandidate(w, cfg, config.customRegex));\n\n\treturn {\n\t\tguardrailName: 'secretKeys',\n\t\ttripwireTriggered: secrets.length > 0,\n\t\tinfo: {\n\t\t\tmaskEntities: { SECRET: secrets },\n\t\t\tdetectedSecrets: secrets,\n\t\t},\n\t};\n}\n\n/**\n * Async guardrail function for secret key and credential detection.\n *\n * Scans the input for likely secrets or credentials (e.g., API keys, tokens)\n * using entropy, diversity, and pattern rules.\n *\n * @param data Input text to scan.\n * @param config Configuration for secret detection.\n * @returns GuardrailResult indicating if secrets were detected, with findings in info.\n */\nexport const secretKeysCheck = (data: string, config: SecretKeysConfig): GuardrailResult => {\n\tconst cfg = CONFIGS[config.threshold];\n\treturn detectSecretKeys(data, cfg, config);\n};\n\nexport const createSecretKeysCheckFn: CreateCheckFn<SecretKeysConfig> =\n\t(config) => (input: string) =>\n\t\tsecretKeysCheck(input, config);\n"],"mappings":"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","names":["entropy"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var topicalAlignment_exports = {};
|
|
20
|
+
__export(topicalAlignment_exports, {
|
|
21
|
+
TOPICAL_ALIGNMENT_SYSTEM_PROMPT: () => TOPICAL_ALIGNMENT_SYSTEM_PROMPT,
|
|
22
|
+
createTopicalAlignmentCheckFn: () => createTopicalAlignmentCheckFn
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(topicalAlignment_exports);
|
|
25
|
+
var import_model = require("../../helpers/model");
|
|
26
|
+
const TOPICAL_ALIGNMENT_SYSTEM_PROMPT = `You are a content analysis system that determines if text stays on topic.
|
|
27
|
+
|
|
28
|
+
BUSINESS SCOPE: [INSERT BUSINESS SCOPE HERE]
|
|
29
|
+
|
|
30
|
+
Determine if the text stays within the defined business scope. Flag any content
|
|
31
|
+
that strays from the allowed topics.`;
|
|
32
|
+
const createTopicalAlignmentCheckFn = (config) => (0, import_model.createLLMCheckFn)("topicalAlignment", config);
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
TOPICAL_ALIGNMENT_SYSTEM_PROMPT,
|
|
36
|
+
createTopicalAlignmentCheckFn
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=topicalAlignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/topicalAlignment.ts"],"sourcesContent":["import { createLLMCheckFn } from '../../helpers/model';\nimport type { CreateCheckFn, LLMConfig } from '../types';\n\nexport const TOPICAL_ALIGNMENT_SYSTEM_PROMPT = `You are a content analysis system that determines if text stays on topic.\n\nBUSINESS SCOPE: [INSERT BUSINESS SCOPE HERE]\n\nDetermine if the text stays within the defined business scope. Flag any content\nthat strays from the allowed topics.`;\n\nexport const createTopicalAlignmentCheckFn: CreateCheckFn<LLMConfig> = (config) =>\n\tcreateLLMCheckFn('topicalAlignment', config);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiC;AAG1B,MAAM,kCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAOxC,MAAM,gCAA0D,CAAC,eACvE,+BAAiB,oBAAoB,MAAM;","names":[]}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var urls_exports = {};
|
|
20
|
+
__export(urls_exports, {
|
|
21
|
+
createUrlsCheckFn: () => createUrlsCheckFn,
|
|
22
|
+
urls: () => urls
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(urls_exports);
|
|
25
|
+
function ipToInt(ip) {
|
|
26
|
+
const parts = ip.split(".").map(Number);
|
|
27
|
+
if (parts.length !== 4 || parts.some((part) => part < 0 || part > 255)) {
|
|
28
|
+
throw new Error(`Invalid IP address: ${ip}`);
|
|
29
|
+
}
|
|
30
|
+
return (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3];
|
|
31
|
+
}
|
|
32
|
+
function detectUrls(text) {
|
|
33
|
+
const PUNCTUATION_CLEANUP = /[.,;:!?)\\]]+$/;
|
|
34
|
+
const detectedUrls = [];
|
|
35
|
+
const schemePatterns = [
|
|
36
|
+
/https?:\/\/[^\s<>"{}|\\^`\[\]]+/gi,
|
|
37
|
+
/ftp:\/\/[^\s<>"{}|\\^`\[\]]+/gi,
|
|
38
|
+
/data:[^\s<>"{}|\\^`\[\]]+/gi,
|
|
39
|
+
/javascript:[^\s<>"{}|\\^`\[\]]+/gi,
|
|
40
|
+
/vbscript:[^\s<>"{}|\\^`\[\]]+/gi,
|
|
41
|
+
/mailto:[^\s<>"{}|\\^`\[\]]+/gi
|
|
42
|
+
];
|
|
43
|
+
const schemeUrls = /* @__PURE__ */ new Set();
|
|
44
|
+
for (const pattern of schemePatterns) {
|
|
45
|
+
const matches = text.match(pattern) || [];
|
|
46
|
+
for (let match of matches) {
|
|
47
|
+
match = match.replace(PUNCTUATION_CLEANUP, "");
|
|
48
|
+
if (match) {
|
|
49
|
+
detectedUrls.push(match);
|
|
50
|
+
if (match.includes("://")) {
|
|
51
|
+
const domainPart = match.split("://", 2)[1].split("/")[0].split("?")[0].split("#")[0];
|
|
52
|
+
schemeUrls.add(domainPart.toLowerCase());
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const domainPattern = /\b(?:www\.)?[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-zA-Z]{2,}(?:\/[^\s]*)?/gi;
|
|
58
|
+
const domainMatches = text.match(domainPattern) || [];
|
|
59
|
+
for (let match of domainMatches) {
|
|
60
|
+
match = match.replace(PUNCTUATION_CLEANUP, "");
|
|
61
|
+
if (match) {
|
|
62
|
+
const domainPart = match.split("/")[0].split("?")[0].split("#")[0].toLowerCase();
|
|
63
|
+
if (!schemeUrls.has(domainPart)) {
|
|
64
|
+
detectedUrls.push(match);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const ipPattern = /\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?::[0-9]+)?(?:\/[^\s]*)?/g;
|
|
69
|
+
const ipMatches = text.match(ipPattern) || [];
|
|
70
|
+
for (let match of ipMatches) {
|
|
71
|
+
match = match.replace(PUNCTUATION_CLEANUP, "");
|
|
72
|
+
if (match) {
|
|
73
|
+
const ipPart = match.split("/")[0].split("?")[0].split("#")[0].toLowerCase();
|
|
74
|
+
if (!schemeUrls.has(ipPart)) {
|
|
75
|
+
detectedUrls.push(match);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const finalUrls = [];
|
|
80
|
+
const schemeUrlDomains = /* @__PURE__ */ new Set();
|
|
81
|
+
for (const url of detectedUrls) {
|
|
82
|
+
if (url.includes("://")) {
|
|
83
|
+
try {
|
|
84
|
+
const parsed = new URL(url);
|
|
85
|
+
if (parsed.hostname) {
|
|
86
|
+
schemeUrlDomains.add(parsed.hostname.toLowerCase());
|
|
87
|
+
const bareDomain = parsed.hostname.toLowerCase().replace(/^www\./, "");
|
|
88
|
+
schemeUrlDomains.add(bareDomain);
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
}
|
|
92
|
+
finalUrls.push(url);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const url of detectedUrls) {
|
|
96
|
+
if (!url.includes("://")) {
|
|
97
|
+
const urlLower = url.toLowerCase().replace(/^www\./, "");
|
|
98
|
+
if (!schemeUrlDomains.has(urlLower)) {
|
|
99
|
+
finalUrls.push(url);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return [...new Set(finalUrls.filter((url) => url))];
|
|
104
|
+
}
|
|
105
|
+
function validateUrlSecurity(urlString, config) {
|
|
106
|
+
try {
|
|
107
|
+
let parsedUrl;
|
|
108
|
+
let originalScheme;
|
|
109
|
+
if (urlString.includes("://")) {
|
|
110
|
+
parsedUrl = new URL(urlString);
|
|
111
|
+
originalScheme = parsedUrl.protocol.replace(":", "");
|
|
112
|
+
} else if (urlString.includes(":") && urlString.split(":", 1)[0].match(/^(data|javascript|vbscript|mailto)$/)) {
|
|
113
|
+
parsedUrl = new URL(urlString);
|
|
114
|
+
originalScheme = parsedUrl.protocol.replace(":", "");
|
|
115
|
+
} else {
|
|
116
|
+
parsedUrl = new URL(`http://${urlString}`);
|
|
117
|
+
originalScheme = "http";
|
|
118
|
+
}
|
|
119
|
+
if (!parsedUrl.protocol) {
|
|
120
|
+
return { parsedUrl: null, reason: "Invalid URL format" };
|
|
121
|
+
}
|
|
122
|
+
const specialSchemes = /* @__PURE__ */ new Set(["data:", "javascript:", "vbscript:", "mailto:"]);
|
|
123
|
+
if (!specialSchemes.has(parsedUrl.protocol) && !parsedUrl.hostname) {
|
|
124
|
+
return { parsedUrl: null, reason: "Invalid URL format" };
|
|
125
|
+
}
|
|
126
|
+
if (!config.allowedSchemes.includes(originalScheme)) {
|
|
127
|
+
return { parsedUrl: null, reason: `Blocked scheme: ${originalScheme}` };
|
|
128
|
+
}
|
|
129
|
+
if (config.blockUserinfo && (parsedUrl.username || parsedUrl.password)) {
|
|
130
|
+
return { parsedUrl: null, reason: "Contains userinfo (potential credential injection)" };
|
|
131
|
+
}
|
|
132
|
+
return { parsedUrl, reason: "" };
|
|
133
|
+
} catch (error) {
|
|
134
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
135
|
+
return { parsedUrl: null, reason: `Invalid URL format: ${errorMessage}` };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function isUrlAllowed(parsedUrl, allowList, allowSubdomains) {
|
|
139
|
+
if (allowList.length === 0) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const urlHost = parsedUrl.hostname?.toLowerCase();
|
|
143
|
+
if (!urlHost) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
for (const allowedEntry of allowList) {
|
|
147
|
+
const entry = allowedEntry.toLowerCase().trim();
|
|
148
|
+
if (entry.includes("://")) {
|
|
149
|
+
try {
|
|
150
|
+
const allowedUrl = new URL(entry);
|
|
151
|
+
const allowedHost = allowedUrl.hostname?.toLowerCase();
|
|
152
|
+
const allowedPath = allowedUrl.pathname;
|
|
153
|
+
if (urlHost === allowedHost) {
|
|
154
|
+
if (!allowedPath || allowedPath === "/" || parsedUrl.pathname.startsWith(allowedPath)) {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Invalid URL in allow list: "${entry}" - ${error instanceof Error ? error.message : error}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
if (/^\d+\.\d+\.\d+\.\d+/.test(entry.split("/")[0])) {
|
|
167
|
+
if (entry === urlHost) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
if (entry.includes("/") && urlHost.match(/^\d+\.\d+\.\d+\.\d+$/)) {
|
|
171
|
+
const [network, prefixStr] = entry.split("/");
|
|
172
|
+
const prefix = parseInt(prefixStr);
|
|
173
|
+
if (prefix >= 0 && prefix <= 32) {
|
|
174
|
+
const networkInt = ipToInt(network);
|
|
175
|
+
const hostInt = ipToInt(urlHost);
|
|
176
|
+
const mask = 4294967295 << 32 - prefix >>> 0;
|
|
177
|
+
if ((networkInt & mask) === (hostInt & mask)) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (/^\d+\.\d+/.test(entry)) {
|
|
186
|
+
console.warn(
|
|
187
|
+
`Warning: Malformed IP address in allow list: "${entry}" - ${error instanceof Error ? error.message : error}`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const allowedDomain = entry.replace(/^www\./, "");
|
|
192
|
+
const urlDomain = urlHost.replace(/^www\./, "");
|
|
193
|
+
if (urlDomain === allowedDomain) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (allowSubdomains && urlDomain.endsWith(`.${allowedDomain}`)) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const urls = (data, config) => {
|
|
203
|
+
const detectedUrls = detectUrls(data);
|
|
204
|
+
const allowed = [];
|
|
205
|
+
const blocked = [];
|
|
206
|
+
const blockedReasons = [];
|
|
207
|
+
for (const urlString of detectedUrls) {
|
|
208
|
+
const { parsedUrl, reason } = validateUrlSecurity(urlString, config);
|
|
209
|
+
if (parsedUrl === null) {
|
|
210
|
+
blocked.push(urlString);
|
|
211
|
+
blockedReasons.push(`${urlString}: ${reason}`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const hostlessSchemes = /* @__PURE__ */ new Set(["data:", "javascript:", "vbscript:", "mailto:"]);
|
|
215
|
+
if (hostlessSchemes.has(parsedUrl.protocol)) {
|
|
216
|
+
allowed.push(urlString);
|
|
217
|
+
} else if (isUrlAllowed(parsedUrl, config.allowedUrls, config.allowSubdomains)) {
|
|
218
|
+
allowed.push(urlString);
|
|
219
|
+
} else {
|
|
220
|
+
blocked.push(urlString);
|
|
221
|
+
blockedReasons.push(`${urlString}: Not in allow list`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const tripwireTriggered = blocked.length > 0;
|
|
225
|
+
return {
|
|
226
|
+
guardrailName: "urls",
|
|
227
|
+
tripwireTriggered,
|
|
228
|
+
info: {
|
|
229
|
+
maskEntities: {
|
|
230
|
+
URL: blocked
|
|
231
|
+
},
|
|
232
|
+
detected: detectedUrls,
|
|
233
|
+
allowed,
|
|
234
|
+
blocked,
|
|
235
|
+
blockedReasons
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
const createUrlsCheckFn = (config) => (input) => urls(input, config);
|
|
240
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
241
|
+
0 && (module.exports = {
|
|
242
|
+
createUrlsCheckFn,
|
|
243
|
+
urls
|
|
244
|
+
});
|
|
245
|
+
//# sourceMappingURL=urls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/urls.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/urls.ts\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type UrlsConfig = {\n\tallowedUrls: string[];\n\tallowedSchemes: string[];\n\tblockUserinfo: boolean;\n\tallowSubdomains: boolean;\n};\n\n/**\n * Convert IPv4 address string to 32-bit integer for CIDR calculations.\n */\nfunction ipToInt(ip: string): number {\n\tconst parts = ip.split('.').map(Number);\n\tif (parts.length !== 4 || parts.some((part) => part < 0 || part > 255)) {\n\t\tthrow new Error(`Invalid IP address: ${ip}`);\n\t}\n\treturn (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3];\n}\n\n/**\n * Detect URLs in text using robust regex patterns.\n */\nfunction detectUrls(text: string): string[] {\n\t// Pattern for cleaning trailing punctuation (] must be escaped)\n\tconst PUNCTUATION_CLEANUP = /[.,;:!?)\\\\]]+$/;\n\n\tconst detectedUrls: string[] = [];\n\n\t// Pattern 1: URLs with schemes (highest priority)\n\tconst schemePatterns = [\n\t\t/https?:\\/\\/[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t\t/ftp:\\/\\/[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t\t/data:[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t\t/javascript:[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t\t/vbscript:[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t\t/mailto:[^\\s<>\"{}|\\\\^`\\[\\]]+/gi,\n\t];\n\n\tconst schemeUrls = new Set<string>();\n\tfor (const pattern of schemePatterns) {\n\t\tconst matches = text.match(pattern) || [];\n\t\tfor (let match of matches) {\n\t\t\t// Clean trailing punctuation\n\t\t\tmatch = match.replace(PUNCTUATION_CLEANUP, '');\n\t\t\tif (match) {\n\t\t\t\tdetectedUrls.push(match);\n\t\t\t\t// Track the domain part to avoid duplicates\n\t\t\t\tif (match.includes('://')) {\n\t\t\t\t\tconst domainPart = match.split('://', 2)[1].split('/')[0].split('?')[0].split('#')[0];\n\t\t\t\t\tschemeUrls.add(domainPart.toLowerCase());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Pattern 2: Domain-like patterns without schemes (exclude already found)\n\tconst domainPattern = /\\b(?:www\\.)?[a-zA-Z0-9][a-zA-Z0-9.-]*\\.[a-zA-Z]{2,}(?:\\/[^\\s]*)?/gi;\n\tconst domainMatches = text.match(domainPattern) || [];\n\n\tfor (let match of domainMatches) {\n\t\t// Clean trailing punctuation\n\t\tmatch = match.replace(PUNCTUATION_CLEANUP, '');\n\t\tif (match) {\n\t\t\t// Extract just the domain part for comparison\n\t\t\tconst domainPart = match.split('/')[0].split('?')[0].split('#')[0].toLowerCase();\n\t\t\t// Only add if we haven't already found this domain with a scheme\n\t\t\tif (!schemeUrls.has(domainPart)) {\n\t\t\t\tdetectedUrls.push(match);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Pattern 3: IP addresses (exclude already found)\n\tconst ipPattern = /\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(?::[0-9]+)?(?:\\/[^\\s]*)?/g;\n\tconst ipMatches = text.match(ipPattern) || [];\n\n\tfor (let match of ipMatches) {\n\t\t// Clean trailing punctuation\n\t\tmatch = match.replace(PUNCTUATION_CLEANUP, '');\n\t\tif (match) {\n\t\t\t// Extract IP part for comparison\n\t\t\tconst ipPart = match.split('/')[0].split('?')[0].split('#')[0].toLowerCase();\n\t\t\tif (!schemeUrls.has(ipPart)) {\n\t\t\t\tdetectedUrls.push(match);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Advanced deduplication: Remove domains that are already part of full URLs\n\tconst finalUrls: string[] = [];\n\tconst schemeUrlDomains = new Set<string>();\n\n\t// First pass: collect all domains from scheme-ful URLs\n\tfor (const url of detectedUrls) {\n\t\tif (url.includes('://')) {\n\t\t\ttry {\n\t\t\t\tconst parsed = new URL(url);\n\t\t\t\tif (parsed.hostname) {\n\t\t\t\t\tschemeUrlDomains.add(parsed.hostname.toLowerCase());\n\t\t\t\t\t// Also add www-stripped version\n\t\t\t\t\tconst bareDomain = parsed.hostname.toLowerCase().replace(/^www\\./, '');\n\t\t\t\t\tschemeUrlDomains.add(bareDomain);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Skip URLs with parsing errors (malformed URLs, encoding issues)\n\t\t\t\t// This is expected for edge cases and doesn't require logging\n\t\t\t}\n\t\t\tfinalUrls.push(url);\n\t\t}\n\t}\n\n\t// Second pass: only add scheme-less URLs if their domain isn't already covered\n\tfor (const url of detectedUrls) {\n\t\tif (!url.includes('://')) {\n\t\t\t// Check if this domain is already covered by a full URL\n\t\t\tconst urlLower = url.toLowerCase().replace(/^www\\./, '');\n\t\t\tif (!schemeUrlDomains.has(urlLower)) {\n\t\t\t\tfinalUrls.push(url);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove empty URLs and return unique list\n\treturn [...new Set(finalUrls.filter((url) => url))];\n}\n\n/**\n * Validate URL against security configuration.\n */\nfunction validateUrlSecurity(\n\turlString: string,\n\tconfig: UrlsConfig,\n): { parsedUrl: URL | null; reason: string } {\n\ttry {\n\t\tlet parsedUrl: URL;\n\t\tlet originalScheme: string;\n\n\t\t// Parse URL - preserve original scheme for validation\n\t\tif (urlString.includes('://')) {\n\t\t\t// Standard URL with double-slash scheme (http://, https://, ftp://, etc.)\n\t\t\tparsedUrl = new URL(urlString);\n\t\t\toriginalScheme = parsedUrl.protocol.replace(':', '');\n\t\t} else if (\n\t\t\turlString.includes(':') &&\n\t\t\turlString.split(':', 1)[0].match(/^(data|javascript|vbscript|mailto)$/)\n\t\t) {\n\t\t\t// Special single-colon schemes\n\t\t\tparsedUrl = new URL(urlString);\n\t\t\toriginalScheme = parsedUrl.protocol.replace(':', '');\n\t\t} else {\n\t\t\t// Add http scheme for parsing, but remember this is a default\n\t\t\tparsedUrl = new URL(`http://${urlString}`);\n\t\t\toriginalScheme = 'http'; // Default scheme for scheme-less URLs\n\t\t}\n\n\t\t// Basic validation: must have scheme and hostname (except for special schemes)\n\t\tif (!parsedUrl.protocol) {\n\t\t\treturn { parsedUrl: null, reason: 'Invalid URL format' };\n\t\t}\n\n\t\t// Special schemes like data: and javascript: don't need hostname\n\t\tconst specialSchemes = new Set(['data:', 'javascript:', 'vbscript:', 'mailto:']);\n\t\tif (!specialSchemes.has(parsedUrl.protocol) && !parsedUrl.hostname) {\n\t\t\treturn { parsedUrl: null, reason: 'Invalid URL format' };\n\t\t}\n\n\t\t// Security validations - use original scheme\n\t\tif (!config.allowedSchemes.includes(originalScheme)) {\n\t\t\treturn { parsedUrl: null, reason: `Blocked scheme: ${originalScheme}` };\n\t\t}\n\n\t\tif (config.blockUserinfo && (parsedUrl.username || parsedUrl.password)) {\n\t\t\treturn { parsedUrl: null, reason: 'Contains userinfo (potential credential injection)' };\n\t\t}\n\n\t\t// Everything else (IPs, localhost, private IPs) goes through allow list logic\n\t\treturn { parsedUrl, reason: '' };\n\t} catch (error) {\n\t\t// Provide specific error information for debugging\n\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\treturn { parsedUrl: null, reason: `Invalid URL format: ${errorMessage}` };\n\t}\n}\n\n/**\n * Check if URL is allowed based on the allow list configuration.\n */\nfunction isUrlAllowed(parsedUrl: URL, allowList: string[], allowSubdomains: boolean): boolean {\n\tif (allowList.length === 0) {\n\t\treturn false;\n\t}\n\n\tconst urlHost = parsedUrl.hostname?.toLowerCase();\n\tif (!urlHost) {\n\t\treturn false;\n\t}\n\n\tfor (const allowedEntry of allowList) {\n\t\tconst entry = allowedEntry.toLowerCase().trim();\n\n\t\t// Handle full URLs with specific paths\n\t\tif (entry.includes('://')) {\n\t\t\ttry {\n\t\t\t\tconst allowedUrl = new URL(entry);\n\t\t\t\tconst allowedHost = allowedUrl.hostname?.toLowerCase();\n\t\t\t\tconst allowedPath = allowedUrl.pathname;\n\n\t\t\t\tif (urlHost === allowedHost) {\n\t\t\t\t\t// Check if the URL path starts with the allowed path\n\t\t\t\t\tif (!allowedPath || allowedPath === '/' || parsedUrl.pathname.startsWith(allowedPath)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid URL in allow list: \"${entry}\" - ${error instanceof Error ? error.message : error}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle IP addresses and CIDR blocks\n\t\ttry {\n\t\t\t// Basic IP pattern check\n\t\t\tif (/^\\d+\\.\\d+\\.\\d+\\.\\d+/.test(entry.split('/')[0])) {\n\t\t\t\tif (entry === urlHost) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Proper CIDR validation\n\t\t\t\tif (entry.includes('/') && urlHost.match(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/)) {\n\t\t\t\t\tconst [network, prefixStr] = entry.split('/');\n\t\t\t\t\tconst prefix = parseInt(prefixStr);\n\n\t\t\t\t\tif (prefix >= 0 && prefix <= 32) {\n\t\t\t\t\t\t// Convert IPs to 32-bit integers for bitwise comparison\n\t\t\t\t\t\tconst networkInt = ipToInt(network);\n\t\t\t\t\t\tconst hostInt = ipToInt(urlHost);\n\n\t\t\t\t\t\t// Create subnet mask\n\t\t\t\t\t\tconst mask = (0xffffffff << (32 - prefix)) >>> 0;\n\n\t\t\t\t\t\t// Check if host is in the network\n\t\t\t\t\t\tif ((networkInt & mask) === (hostInt & mask)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Expected: entry is not an IP address/CIDR, continue to domain matching\n\t\t\t// Only log if it looks like it was intended to be an IP but failed parsing\n\t\t\tif (/^\\d+\\.\\d+/.test(entry)) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Warning: Malformed IP address in allow list: \"${entry}\" - ${error instanceof Error ? error.message : error}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Handle domain matching\n\t\tconst allowedDomain = entry.replace(/^www\\./, '');\n\t\tconst urlDomain = urlHost.replace(/^www\\./, '');\n\n\t\t// Exact match always allowed\n\t\tif (urlDomain === allowedDomain) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Subdomain matching if enabled\n\t\tif (allowSubdomains && urlDomain.endsWith(`.${allowedDomain}`)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Main URL filtering function.\n */\nexport const urls = (data: string, config: UrlsConfig): GuardrailResult => {\n\t// Detect URLs in the text\n\tconst detectedUrls = detectUrls(data);\n\n\tconst allowed: string[] = [];\n\tconst blocked: string[] = [];\n\tconst blockedReasons: string[] = [];\n\n\tfor (const urlString of detectedUrls) {\n\t\t// Validate URL with security checks\n\t\tconst { parsedUrl, reason } = validateUrlSecurity(urlString, config);\n\n\t\tif (parsedUrl === null) {\n\t\t\tblocked.push(urlString);\n\t\t\tblockedReasons.push(`${urlString}: ${reason}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check against allow list\n\t\t// Special schemes (data:, javascript:, mailto:) don't have meaningful hosts\n\t\t// so they only need scheme validation, not host-based allow list checking\n\t\tconst hostlessSchemes = new Set(['data:', 'javascript:', 'vbscript:', 'mailto:']);\n\t\tif (hostlessSchemes.has(parsedUrl.protocol)) {\n\t\t\t// For hostless schemes, only scheme permission matters (no allow list needed)\n\t\t\t// They were already validated for scheme permission in validateUrlSecurity\n\t\t\tallowed.push(urlString);\n\t\t} else if (isUrlAllowed(parsedUrl, config.allowedUrls, config.allowSubdomains)) {\n\t\t\tallowed.push(urlString);\n\t\t} else {\n\t\t\tblocked.push(urlString);\n\t\t\tblockedReasons.push(`${urlString}: Not in allow list`);\n\t\t}\n\t}\n\n\tconst tripwireTriggered = blocked.length > 0;\n\n\treturn {\n\t\tguardrailName: 'urls',\n\t\ttripwireTriggered,\n\t\tinfo: {\n\t\t\tmaskEntities: {\n\t\t\t\tURL: blocked,\n\t\t\t},\n\t\t\tdetected: detectedUrls,\n\t\t\tallowed,\n\t\t\tblocked,\n\t\t\tblockedReasons,\n\t\t},\n\t};\n};\n\nexport const createUrlsCheckFn: CreateCheckFn<UrlsConfig> = (config) => (input: string) =>\n\turls(input, config);\n"],"mappings":"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","names":[]}
|