import { z } from "zod"; import { createHash } from "node:crypto"; import type { JSONSchema7 } from "json-schema"; import type { ToolExecutor, ToolContext, ToolResult } from "../../registry"; import type { HashToolConfig } from "./config"; export const hashInputSchema = z.object({ operation: z .enum(["hash", "compare"]) .describe("操作类型: hash=计算哈希, compare=比较哈希值"), text: z .string() .min(1) .max(100000) .describe("要计算哈希的文本内容"), algorithm: z .enum(["md5", "sha1", "sha256", "sha512"]) .optional() .describe("哈希算法,不传则使用配置默认值"), expectedHash: z .string() .optional() .describe("compare 操作时,要对比的期望哈希值"), }); type HashInput = z.infer; function computeHash(text: string, algorithm: string, uppercase: boolean): string { const hash = createHash(algorithm).update(text, "utf8").digest("hex"); return uppercase ? hash.toUpperCase() : hash; } export const hashExecutor: ToolExecutor = { buildInputSchema(_config: HashToolConfig): JSONSchema7 { return { type: "object", properties: { operation: { type: "string", enum: ["hash", "compare"], description: "操作类型: hash=计算哈希, compare=比较哈希值", }, text: { type: "string", description: "要计算哈希的文本内容" }, algorithm: { type: "string", enum: ["md5", "sha1", "sha256", "sha512"], description: "哈希算法", }, expectedHash: { type: "string", description: "compare 操作的期望哈希值" }, }, required: ["operation", "text"], }; }, buildDescription(config: HashToolConfig): string { return `哈希计算工具。支持 md5、sha1、sha256、sha512 算法。可计算文本哈希值或对比哈希是否匹配。默认算法: ${config.defaultAlgorithm},输出${config.uppercase ? "大写" : "小写"}。`; }, async execute( input: unknown, config: HashToolConfig, _ctx: ToolContext, ): Promise { const start = Date.now(); const parsed = hashInputSchema.safeParse(input); if (!parsed.success) { return { success: false, data: null, error: `输入参数校验失败: ${parsed.error.message}`, metadata: { durationMs: Date.now() - start }, }; } const inp = parsed.data as HashInput; const algorithm = inp.algorithm ?? config.defaultAlgorithm; try { switch (inp.operation) { case "hash": { const hashValue = computeHash(inp.text, algorithm, config.uppercase); return { success: true, data: { algorithm, inputLength: inp.text.length, hash: hashValue, }, metadata: { durationMs: Date.now() - start }, }; } case "compare": { if (!inp.expectedHash) { throw new Error("compare 操作需要 expectedHash 参数"); } const actualHash = computeHash(inp.text, algorithm, config.uppercase); const expected = config.uppercase ? inp.expectedHash.toUpperCase() : inp.expectedHash.toLowerCase(); const matched = actualHash === expected; return { success: true, data: { algorithm, matched, actualHash, expectedHash: expected, }, metadata: { durationMs: Date.now() - start }, }; } default: throw new Error(`未知操作: ${inp.operation}`); } } catch (e) { return { success: false, data: null, error: e instanceof Error ? e.message : String(e), metadata: { durationMs: Date.now() - start }, }; } }, };