import { z } from "zod"; import { createHash, randomBytes } from "node:crypto"; import type { JSONSchema7 } from "json-schema"; import type { ToolExecutor, ToolContext, ToolResult } from "../../registry"; import type { Base64ToolConfig } from "./config"; export const base64InputSchema = z.object({ operation: z .enum([ "base64-encode", "base64-decode", "base64url-encode", "base64url-decode", "url-encode", "url-decode", "hash", ]) .describe("操作类型"), input: z.string().describe("输入内容"), algorithm: z .enum(["md5", "sha1", "sha256", "sha384", "sha512"]) .optional() .describe("哈希算法 (hash 操作使用)"), encoding: z .enum(["hex", "base64"]) .optional() .describe("哈希输出编码 (hash 操作使用)"), }); type Base64Input = z.infer; export const base64Executor: ToolExecutor = { buildInputSchema(_config: Base64ToolConfig): JSONSchema7 { return { type: "object", properties: { operation: { type: "string", enum: [ "base64-encode", "base64-decode", "base64url-encode", "base64url-decode", "url-encode", "url-decode", "hash", ], description: "操作类型", }, input: { type: "string", description: "输入内容" }, algorithm: { type: "string", enum: ["md5", "sha1", "sha256", "sha384", "sha512"], description: "哈希算法 (hash 操作)", }, encoding: { type: "string", enum: ["hex", "base64"], description: "哈希输出编码", }, }, required: ["operation", "input"], }; }, buildDescription(config: Base64ToolConfig): string { return `编解码工具。支持 Base64/Base64URL 编解码、URL 编解码、哈希计算(md5/sha1/sha256/sha384/sha512)。最大输入 ${config.maxInputLength} 字符。`; }, async execute( input: unknown, config: Base64ToolConfig, _ctx: ToolContext, ): Promise { const start = Date.now(); const parsed = base64InputSchema.safeParse(input); if (!parsed.success) { return { success: false, data: null, error: `输入参数校验失败: ${parsed.error.message}`, metadata: { durationMs: Date.now() - start }, }; } const inp = parsed.data as Base64Input; if (inp.input.length > config.maxInputLength) { return { success: false, data: null, error: `输入过长: ${inp.input.length} 字符 (限制 ${config.maxInputLength})`, metadata: { durationMs: Date.now() - start }, }; } try { let result: string; switch (inp.operation) { case "base64-encode": result = Buffer.from(inp.input, "utf-8").toString("base64"); break; case "base64-decode": result = Buffer.from(inp.input, "base64").toString("utf-8"); break; case "base64url-encode": result = Buffer.from(inp.input, "utf-8").toString("base64url"); break; case "base64url-decode": result = Buffer.from(inp.input, "base64url").toString("utf-8"); break; case "url-encode": result = encodeURIComponent(inp.input); break; case "url-decode": result = decodeURIComponent(inp.input); break; case "hash": { const algorithm = inp.algorithm ?? "sha256"; const encoding = inp.encoding ?? "hex"; const hash = createHash(algorithm).update(inp.input, "utf-8"); result = hash.digest(encoding); break; } default: throw new Error(`未知操作: ${inp.operation}`); } return { success: true, data: { operation: inp.operation, input: inp.input, output: result, inputLength: inp.input.length, outputLength: result.length, }, metadata: { durationMs: Date.now() - start }, }; } catch (e) { return { success: false, data: null, error: e instanceof Error ? e.message : String(e), metadata: { durationMs: Date.now() - start }, }; } }, };