fix(adapters,security): S-4 rss/browser redaction use the shared contracts key table
- contracts: isSensitiveQueryParam (whole-name match on SENSITIVE_QUERY_PARAMS or isSensitiveKey), the single source for query credential names - rss/redact: drop local SENSITIVE_QUERY_KEYS; param checks go through isSensitiveQueryParam (+ caller extras); REDACTED re-exported from contracts - browser/redact: CREDENTIAL_PARAM built from SENSITIVE_QUERY_PARAMS, JSON keys also checked with isSensitiveKey; keeps only its own rules (path passkey, cookie names, a11y password fields); remove stray regex statement - redact-consistency.test: 24 credential spellings (pass_key, c_secure_pass, refresh_token, password, uid_key, auth, ...) masked by contracts, rss and browser alike; plain params untouched; rss extract/unredact round-trip Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b48d8592d5
commit
47bd04aec0
5 files changed
+95
-28
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import { isSensitiveQueryParam, redactUrl as redactUrlShared } from "@umt/contracts";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { redactBrowserUrl, urlHasCredential } from "./browser/redact.ts";
|
||||
import { extractSecretParams, redactUrl as redactRssUrl, redactText, unredactUrl } from "./rss/redact.ts";
|
||||
|
||||
// 验收 07 S-4:脱敏键表只有一份(@umt/contracts redact.ts)。contracts(logger + 模型上下文)、rss、browser
|
||||
// 三处对同一组凭证参数给出一致结论;任何一处漏遮都会让 passkey 进日志或模型。
|
||||
|
||||
const SECRET = "s3cr3tVALUE42";
|
||||
const CREDENTIAL_PARAMS = [
|
||||
"passkey",
|
||||
"pass_key",
|
||||
"pass-key",
|
||||
"PassKey",
|
||||
"authkey",
|
||||
"auth_key",
|
||||
"torrent_pass",
|
||||
"rsskey",
|
||||
"rss_key",
|
||||
"c_secure_pass",
|
||||
"downhash",
|
||||
"apikey",
|
||||
"api_key",
|
||||
"access_token",
|
||||
"refresh_token",
|
||||
"token",
|
||||
"auth",
|
||||
"sign",
|
||||
"signature",
|
||||
"credential",
|
||||
"secret",
|
||||
"password",
|
||||
"uid_key",
|
||||
"key",
|
||||
];
|
||||
const PLAIN_PARAMS = ["id", "cat", "page", "q", "tokens", "limit", "type"];
|
||||
|
||||
describe("脱敏键表三处一致", () => {
|
||||
it.each(CREDENTIAL_PARAMS)("凭证参数 %s:contracts / rss / browser 都遮蔽", (p) => {
|
||||
const url = `https://pt.example.org/rss.php?id=7&${p}=${SECRET}&cat=401`;
|
||||
expect(isSensitiveQueryParam(p)).toBe(true);
|
||||
for (const out of [
|
||||
redactUrlShared(url),
|
||||
redactRssUrl(url),
|
||||
redactText(`GET ${url} failed`),
|
||||
redactBrowserUrl(url),
|
||||
]) {
|
||||
expect(out, out).not.toContain(SECRET);
|
||||
expect(out).toContain("id=7");
|
||||
}
|
||||
expect(urlHasCredential(url)).toBe(true);
|
||||
// rss 的去重键可还原:取出的 secret 正好填回被遮的参数
|
||||
const secrets = extractSecretParams(url);
|
||||
expect(Object.values(secrets)).toContain(SECRET);
|
||||
expect(unredactUrl(redactRssUrl(url), secrets)).toContain(`${p}=${SECRET}`);
|
||||
});
|
||||
|
||||
it.each(PLAIN_PARAMS)("普通参数 %s:三处都不遮", (p) => {
|
||||
const url = `https://pt.example.org/torrents.php?${p}=abc123`;
|
||||
expect(isSensitiveQueryParam(p)).toBe(false);
|
||||
expect(redactUrlShared(url)).toBe(url);
|
||||
expect(redactRssUrl(url)).toBe(url);
|
||||
expect(redactBrowserUrl(url)).toBe(url);
|
||||
});
|
||||
|
||||
it("URL userinfo 三处都抹掉", () => {
|
||||
const url = `https://user:${SECRET}@pt.example.org/x`;
|
||||
for (const out of [redactUrlShared(url), redactRssUrl(url), redactBrowserUrl(url)])
|
||||
expect(out).not.toContain(SECRET);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user