Files
weixin-plugin-test/weixin-plugin/weixin/util/redact.ts
zyh 77019ec050 feat: 初始化微信插件独立测试环境
添加完整的微信插件测试框架,包含:
- 微信插件源码(weixin-plugin/)
- TypeScript 类型定义(types.ts)
- 插件编译脚本(scripts/build-weixin-plugin.sh)
- 简化测试脚本(scripts/test-weixin-simple.js)
- 完整测试脚本(scripts/test-weixin-plugin.js)
- 项目配置和依赖管理(package.json)
- 使用说明文档(README.md)

主要功能:
- 支持二维码登录认证
- HTTP 长轮询消息接收
- 文本、图片、视频、文件消息收发
- 自动回复测试
- 运行状态统计

Generated with [Claude Code](https://claude.com/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-30 07:14:00 +00:00

55 lines
1.8 KiB
TypeScript

const DEFAULT_BODY_MAX_LEN = 200;
const DEFAULT_TOKEN_PREFIX_LEN = 6;
/**
* Truncate a string, appending a length indicator when trimmed.
* Returns `""` for empty/undefined input.
*/
export function truncate(s: string | undefined, max: number): string {
if (!s) return "";
if (s.length <= max) return s;
return `${s.slice(0, max)}…(len=${s.length})`;
}
/**
* Redact a token/secret: show only the first few chars + total length.
* Returns `"(none)"` when absent.
*/
export function redactToken(token: string | undefined, prefixLen = DEFAULT_TOKEN_PREFIX_LEN): string {
if (!token) return "(none)";
if (token.length <= prefixLen) return `****(len=${token.length})`;
return `${token.slice(0, prefixLen)}…(len=${token.length})`;
}
/** Field names whose values should be masked in logged JSON bodies. */
const SENSITIVE_FIELDS = /\b(context_token|bot_token|token|authorization|Authorization)\b/;
/**
* Truncate a JSON body string to `maxLen` chars for safe logging.
* Redacts known sensitive fields before truncating.
*/
export function redactBody(body: string | undefined, maxLen = DEFAULT_BODY_MAX_LEN): string {
if (!body) return "(empty)";
// Mask values of known sensitive JSON keys: "key":"value" → "key":"<redacted>"
const redacted = body.replace(
/"(context_token|bot_token|token|authorization|Authorization)"\s*:\s*"[^"]*"/g,
'"$1":"<redacted>"',
);
if (redacted.length <= maxLen) return redacted;
return `${redacted.slice(0, maxLen)}…(truncated, totalLen=${redacted.length})`;
}
/**
* Strip query string (which often contains signatures/tokens) from a URL,
* keeping only origin + pathname.
*/
export function redactUrl(rawUrl: string): string {
try {
const u = new URL(rawUrl);
const base = `${u.origin}${u.pathname}`;
return u.search ? `${base}?<redacted>` : base;
} catch {
return truncate(rawUrl, 80);
}
}