@n8n/utils
Advanced tools
| //#region src/scrub-secrets.ts | ||
| /** | ||
| * Replace common credential patterns in free-form text with `[REDACTED]`. | ||
| * | ||
| * Used before persisting or transmitting user-supplied text (telemetry | ||
| * excerpts, eval report HTML, free-form feedback) where keys/tokens | ||
| * accidentally pasted into prompts or command lines could otherwise leak | ||
| * downstream. | ||
| * | ||
| * Conservative by design: matches well-known prefixed tokens, explicit | ||
| * `key=value` pairs, and quoted JSON/JS-object fields with sensitive | ||
| * names. We don't attempt to redact arbitrary long opaque strings — false | ||
| * positives on file paths, IDs, or base64 payloads would make the output | ||
| * unreadable. | ||
| */ | ||
| const SECRET_KEYS = "password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token"; | ||
| const SECRET_VALUE_PATTERNS = [ | ||
| /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g, | ||
| /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, | ||
| /\b(?:Bearer|Basic|Token)\s+[A-Za-z0-9._~+/=-]{12,}/gi, | ||
| /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g, | ||
| /\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, | ||
| /\bAIza[0-9A-Za-z_-]{35}\b/g, | ||
| /\bxox[abprso]-[A-Za-z0-9-]{10,}/g, | ||
| /\bgh[psoru]_[A-Za-z0-9]{20,}/g, | ||
| /\bgithub_pat_[A-Za-z0-9_]{22,}/g, | ||
| /\bAKIA[0-9A-Z]{16}\b/g, | ||
| /(?<=:\/\/)[^\s:/@]+:[^\s:/@]+(?=@)/g, | ||
| new RegExp(`"(?:${SECRET_KEYS})"\\s*:\\s*"(?!\\[(?:redacted|REDACTED)\\]")(?:[^"\\\\\\r\\n]|\\\\.)*"`, "gi"), | ||
| new RegExp(`'(?:${SECRET_KEYS})'\\s*:\\s*'(?!\\[(?:redacted|REDACTED)\\]')(?:[^'\\\\\\r\\n]|\\\\.)*'`, "gi"), | ||
| new RegExp(`\\b(?:${SECRET_KEYS})\\s*[:=]\\s*\\S+`, "gi") | ||
| ]; | ||
| function scrubSecretsInText(input) { | ||
| let out = input; | ||
| for (const pattern of SECRET_VALUE_PATTERNS) out = out.replace(pattern, "[REDACTED]"); | ||
| return out; | ||
| } | ||
| //#endregion | ||
| exports.SECRET_KEYS = SECRET_KEYS; | ||
| exports.SECRET_VALUE_PATTERNS = SECRET_VALUE_PATTERNS; | ||
| exports.scrubSecretsInText = scrubSecretsInText; | ||
| //# sourceMappingURL=scrub-secrets.cjs.map |
| {"version":3,"file":"scrub-secrets.cjs","names":["SECRET_VALUE_PATTERNS: readonly RegExp[]"],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` placeholder so this\n\t// stays idempotent when chained behind upstream object-walking redaction\n\t// (e.g. langsmith trace payloads).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments\n\tnew RegExp(`\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*\\\\S+`, 'gi'),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAaA,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAeA,IAAI,OACH,OAAO,YAAY,yEACnB,KACA;CAED,IAAI,OACH,OAAO,YAAY,yEACnB,KACA;CAED,IAAI,OAAO,SAAS,YAAY,oBAAoB,KAAK;CACzD;AAED,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;AACV,MAAK,MAAM,WAAW,sBACrB,OAAM,IAAI,QAAQ,SAAS,aAAa;AAEzC,QAAO"} |
| //#region src/scrub-secrets.d.ts | ||
| declare const SECRET_KEYS = "password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token"; | ||
| declare const SECRET_VALUE_PATTERNS: readonly RegExp[]; | ||
| declare function scrubSecretsInText(input: string): string; | ||
| //#endregion | ||
| export { SECRET_KEYS, SECRET_VALUE_PATTERNS, scrubSecretsInText }; | ||
| //# sourceMappingURL=scrub-secrets.d.cts.map |
| //#region src/scrub-secrets.d.ts | ||
| declare const SECRET_KEYS = "password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token"; | ||
| declare const SECRET_VALUE_PATTERNS: readonly RegExp[]; | ||
| declare function scrubSecretsInText(input: string): string; | ||
| //#endregion | ||
| export { SECRET_KEYS, SECRET_VALUE_PATTERNS, scrubSecretsInText }; | ||
| //# sourceMappingURL=scrub-secrets.d.mts.map |
| //#region src/scrub-secrets.ts | ||
| /** | ||
| * Replace common credential patterns in free-form text with `[REDACTED]`. | ||
| * | ||
| * Used before persisting or transmitting user-supplied text (telemetry | ||
| * excerpts, eval report HTML, free-form feedback) where keys/tokens | ||
| * accidentally pasted into prompts or command lines could otherwise leak | ||
| * downstream. | ||
| * | ||
| * Conservative by design: matches well-known prefixed tokens, explicit | ||
| * `key=value` pairs, and quoted JSON/JS-object fields with sensitive | ||
| * names. We don't attempt to redact arbitrary long opaque strings — false | ||
| * positives on file paths, IDs, or base64 payloads would make the output | ||
| * unreadable. | ||
| */ | ||
| const SECRET_KEYS = "password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token"; | ||
| const SECRET_VALUE_PATTERNS = [ | ||
| /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g, | ||
| /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, | ||
| /\b(?:Bearer|Basic|Token)\s+[A-Za-z0-9._~+/=-]{12,}/gi, | ||
| /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g, | ||
| /\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, | ||
| /\bAIza[0-9A-Za-z_-]{35}\b/g, | ||
| /\bxox[abprso]-[A-Za-z0-9-]{10,}/g, | ||
| /\bgh[psoru]_[A-Za-z0-9]{20,}/g, | ||
| /\bgithub_pat_[A-Za-z0-9_]{22,}/g, | ||
| /\bAKIA[0-9A-Z]{16}\b/g, | ||
| /(?<=:\/\/)[^\s:/@]+:[^\s:/@]+(?=@)/g, | ||
| new RegExp(`"(?:${SECRET_KEYS})"\\s*:\\s*"(?!\\[(?:redacted|REDACTED)\\]")(?:[^"\\\\\\r\\n]|\\\\.)*"`, "gi"), | ||
| new RegExp(`'(?:${SECRET_KEYS})'\\s*:\\s*'(?!\\[(?:redacted|REDACTED)\\]')(?:[^'\\\\\\r\\n]|\\\\.)*'`, "gi"), | ||
| new RegExp(`\\b(?:${SECRET_KEYS})\\s*[:=]\\s*\\S+`, "gi") | ||
| ]; | ||
| function scrubSecretsInText(input) { | ||
| let out = input; | ||
| for (const pattern of SECRET_VALUE_PATTERNS) out = out.replace(pattern, "[REDACTED]"); | ||
| return out; | ||
| } | ||
| //#endregion | ||
| export { SECRET_KEYS, SECRET_VALUE_PATTERNS, scrubSecretsInText }; | ||
| //# sourceMappingURL=scrub-secrets.mjs.map |
| {"version":3,"file":"scrub-secrets.mjs","names":["SECRET_VALUE_PATTERNS: readonly RegExp[]"],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` placeholder so this\n\t// stays idempotent when chained behind upstream object-walking redaction\n\t// (e.g. langsmith trace payloads).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments\n\tnew RegExp(`\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*\\\\S+`, 'gi'),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAaA,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAeA,IAAI,OACH,OAAO,YAAY,yEACnB,KACA;CAED,IAAI,OACH,OAAO,YAAY,yEACnB,KACA;CAED,IAAI,OAAO,SAAS,YAAY,oBAAoB,KAAK;CACzD;AAED,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;AACV,MAAK,MAAM,WAAW,sBACrB,OAAM,IAAI,QAAQ,SAAS,aAAa;AAEzC,QAAO"} |
+4
-4
| { | ||
| "name": "@n8n/utils", | ||
| "type": "module", | ||
| "version": "1.20.0", | ||
| "version": "1.20.1", | ||
| "files": [ | ||
@@ -35,7 +35,7 @@ "dist", | ||
| "typescript": "5.9.2", | ||
| "vite": "npm:rolldown-vite@latest", | ||
| "vite": "npm:rolldown-vite@7.1.16", | ||
| "vitest": "^3.1.3", | ||
| "@n8n/typescript-config": "1.3.0", | ||
| "@n8n/eslint-config": "0.0.1", | ||
| "@n8n/vitest-config": "1.5.0" | ||
| "@n8n/vitest-config": "1.5.1", | ||
| "@n8n/typescript-config": "1.3.1" | ||
| }, | ||
@@ -42,0 +42,0 @@ "license": "SEE LICENSE IN LICENSE.md", |
119161
13.01%114
5.56%1025
8.47%