You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

158 lines
4.3 KiB

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<typeof base64InputSchema>;
export const base64Executor: ToolExecutor<Base64ToolConfig> = {
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<ToolResult> {
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 },
};
}
},
};