diff --git a/apps/server/src/server/api/contracts/config.contract.ts b/apps/server/src/server/api/contracts/config.contract.ts index b305580..30a8927 100644 --- a/apps/server/src/server/api/contracts/config.contract.ts +++ b/apps/server/src/server/api/contracts/config.contract.ts @@ -1,10 +1,23 @@ import { oc } from '@orpc/contract' import { z } from 'zod' -const configOutput = z.object({ - licence: z.string().nullable().describe('当前本地 licence,未设置时为 null'), - fingerprint: z.string().describe('UX 本机计算得到的 fingerprint'), -}) +const configOutput = z + .object({ + licence: z.string().nullable().describe('当前本地 licence,未设置时为 null'), + fingerprint: z.string().describe('UX 本机计算得到的设备特征码(SHA-256)'), + }) + .meta({ + examples: [ + { + licence: 'LIC-8F2A-XXXX', + fingerprint: '9a3b7c1d2e4f5a6b8c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b', + }, + { + licence: null, + fingerprint: '9a3b7c1d2e4f5a6b8c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b', + }, + ], + }) export const get = oc .route({ @@ -30,8 +43,12 @@ export const setLicence = oc tags: ['Config'], }) .input( - z.object({ - licence: z.string().min(1).describe('本地持久化的 licence'), - }), + z + .object({ + licence: z.string().min(1).describe('本地持久化的 licence'), + }) + .meta({ + examples: [{ licence: 'LIC-8F2A-XXXX' }], + }), ) .output(configOutput) diff --git a/apps/server/src/server/api/contracts/crypto.contract.ts b/apps/server/src/server/api/contracts/crypto.contract.ts index 5e61b13..4f5ae14 100644 --- a/apps/server/src/server/api/contracts/crypto.contract.ts +++ b/apps/server/src/server/api/contracts/crypto.contract.ts @@ -12,14 +12,31 @@ export const encryptDeviceInfo = oc tags: ['Crypto'], }) .input( - z.object({ - platformPublicKey: z.string().min(1).describe('平台公钥(Base64,SPKI DER)'), - }), + z + .object({ + platformPublicKey: z.string().min(1).describe('平台公钥(Base64,SPKI DER)'), + }) + .meta({ + examples: [ + { + platformPublicKey: + 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzDlZvMDVaL+fjl05Hi182JOAUAaN4gh9rOF+1NhKfO4J6e0HLy8lBuylp3A4xoTiyUejNm22h0dqAgDSPnY/xZR76POFTD1soHr2LaFCN8JAbQ96P8gE7wC9qpoTssVvIVRH7QbVd260J6eD0Szwcx9cg591RSN69pMpe5IVRi8T99Hhql6/wnZHORPr18eESLOY93jRskLzc0q18r68RRoTJiQf+9YC8ub5iKp7rCjVnPi1UbIYmXmL08tk5mksYA0NqWQAa1ofKxx/9tQtB9uTjhTxuTu94XU9jlGU87qaHZs+kpqa8CAbYYJFbSP1xHwoZzpU2jpw2aF22HBYxwIDAQAB', + }, + ], + }), ) .output( - z.object({ - encrypted: z.string().describe('Base64 密文(用于设备授权二维码)'), - }), + z + .object({ + encrypted: z.string().describe('Base64 密文(用于设备授权二维码)'), + }) + .meta({ + examples: [ + { + encrypted: 'dGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIFJTQS1PQUVQIGVuY3J5cHRlZCBkZXZpY2UgaW5mby4uLg==', + }, + ], + }), ) export const decryptTask = oc @@ -33,14 +50,31 @@ export const decryptTask = oc tags: ['Crypto'], }) .input( - z.object({ - encryptedData: z.string().min(1).describe('Base64 密文'), - }), + z + .object({ + encryptedData: z.string().min(1).describe('Base64 编码的 AES-256-GCM 密文(来自任务二维码扫描结果)'), + }) + .meta({ + examples: [ + { + encryptedData: 'uWUcAmp6UQd0w3G3crdsd4613QCxGLoEgslgXJ4G2hQhpQdjtghtQjCBUZwB/JO+NRgH1vSTr8dqBJRq7Qh4nug==', + }, + ], + }), ) .output( - z.object({ - decrypted: z.string().describe('解密后的 UTF-8 明文字符串'), - }), + z + .object({ + decrypted: z.string().describe('解密后的任务信息 JSON 字符串'), + }) + .meta({ + examples: [ + { + decrypted: + '{"taskId":"TASK-20260115-4875","enterpriseId":"1173040813421105152","orgName":"超艺科技有限公司","inspectionId":"702286470691215417","inspectionPerson":"警务通","issuedAt":1734571234567}', + }, + ], + }), ) export const encryptSummary = oc @@ -54,15 +88,33 @@ export const encryptSummary = oc tags: ['Crypto'], }) .input( - z.object({ - salt: z.string().min(1).describe('HKDF salt(例如 taskId)'), - plaintext: z.string().min(1).describe('待加密明文'), - }), + z + .object({ + salt: z.string().min(1).describe('HKDF salt(即 taskId,从任务二维码中获取)'), + plaintext: z.string().min(1).describe('待加密的摘要信息 JSON 明文'), + }) + .meta({ + examples: [ + { + salt: 'TASK-20260115-4875', + plaintext: + '{"enterpriseId":"1173040813421105152","inspectionId":"702286470691215417","summary":"检查摘要信息:发现3个高危漏洞,5个中危漏洞","timestamp":1734571234567}', + }, + ], + }), ) .output( - z.object({ - encrypted: z.string().describe('Base64 密文'), - }), + z + .object({ + encrypted: z.string().describe('Base64 密文(用于摘要信息二维码)'), + }) + .meta({ + examples: [ + { + encrypted: 'uWUcAmp6UQd0w3G3crdsd4613QCxGLoEgslgXJ4G2hQhpQdjtghtQjCBUZwB/JO+NRgH1vSTr8dqBJRq7Qh4nug==', + }, + ], + }), ) export const signAndPackReport = oc @@ -77,14 +129,45 @@ export const signAndPackReport = oc }) .input( z.object({ - pgpPrivateKey: z.string().min(1).describe('OpenPGP 私钥(ASCII armored)'), - signingContext: z.string().min(1).describe('签名上下文字符串(由调用方定义)'), - summaryJson: z.string().min(1).describe('summary.json 的完整 JSON 文本'), - outputFileName: z.string().min(1).optional().describe('返回 ZIP 文件名(可选)'), + pgpPrivateKey: z + .string() + .min(1) + .describe('OpenPGP 私钥(ASCII armored)') + .meta({ + examples: ['-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxcMGBGd...\n-----END PGP PRIVATE KEY BLOCK-----'], + }), + signingContext: z + .string() + .min(1) + .describe('签名上下文字符串(通常为 taskId + inspectionId 拼接)') + .meta({ + examples: ['TASK-20260115-4875702286470691215417'], + }), + summaryJson: z + .string() + .min(1) + .describe('summary.json 的完整 JSON 文本(包含 orgId、checkId、taskId 等业务字段)') + .meta({ + examples: [ + '{"orgId":1173040813421105152,"checkId":702286470691215417,"taskId":"TASK-20260115-4875","summary":"检查摘要信息"}', + ], + }), + outputFileName: z + .string() + .min(1) + .optional() + .describe('返回 ZIP 文件名(可选,默认 signed-report.zip)') + .meta({ examples: ['signed-report.zip'] }), rawZip: z .file() .mime(['application/zip', 'application/x-zip-compressed']) - .describe('原始报告 ZIP 文件(multipart/form-data 字段)'), + .describe( + '原始报告 ZIP 文件(multipart/form-data 字段,应包含 assets.json、vulnerabilities.json、weakPasswords.json、漏洞评估报告.html)', + ), }), ) - .output(z.file().describe('签名后报告 ZIP 文件(二进制响应)')) + .output( + z + .file() + .describe('签名后报告 ZIP 文件(二进制响应,包含 summary.json、META-INF/manifest.json、META-INF/signature.asc)'), + )