refactor(crypto): use Zod safeParse for summary.json validation instead of manual checks

This commit is contained in:
2026-03-06 16:39:38 +08:00
parent 4d64cfb93d
commit 3d27f8ccfa

View File

@@ -11,6 +11,7 @@ import {
import { ORPCError } from '@orpc/server'
import type { JSZipObject } from 'jszip'
import JSZip from 'jszip'
import { z } from 'zod'
import { getUxConfig } from '@/server/ux-config'
import { db } from '../middlewares'
import { os } from '../server'
@@ -20,6 +21,14 @@ interface ZipFileItem {
bytes: Uint8Array
}
const summaryPayloadSchema = z
.object({
taskId: z.string().min(1, 'summary.json must contain a non-empty taskId'),
checkId: z.string().optional(),
inspectionId: z.string().optional(),
})
.passthrough()
const MAX_RAW_ZIP_BYTES = 50 * 1024 * 1024
const MAX_SINGLE_FILE_BYTES = 20 * 1024 * 1024
const MAX_TOTAL_UNCOMPRESSED_BYTES = 60 * 1024 * 1024
@@ -165,7 +174,7 @@ export const signAndPackReport = os.crypto.signAndPackReport.use(db).handler(asy
const zipFiles = await listSafeZipFiles(rawZip)
// Extract and parse summary.json from the ZIP
// Extract and validate summary.json from the ZIP
const summaryFile = zipFiles.find((f) => f.name === 'summary.json')
if (!summaryFile) {
throw new ORPCError('BAD_REQUEST', {
@@ -173,24 +182,25 @@ export const signAndPackReport = os.crypto.signAndPackReport.use(db).handler(asy
})
}
let summaryPayload: Record<string, unknown>
let rawJson: unknown
try {
summaryPayload = JSON.parse(Buffer.from(summaryFile.bytes).toString('utf-8'))
rawJson = JSON.parse(Buffer.from(summaryFile.bytes).toString('utf-8'))
} catch {
throw new ORPCError('BAD_REQUEST', {
message: 'summary.json in the ZIP is not valid JSON',
})
}
// Derive signingContext from summary.json fields
const taskId = String(summaryPayload.taskId ?? '')
const checkId = String(summaryPayload.checkId ?? summaryPayload.inspectionId ?? '')
if (!taskId) {
const parsed = summaryPayloadSchema.safeParse(rawJson)
if (!parsed.success) {
throw new ORPCError('BAD_REQUEST', {
message: 'summary.json must contain a taskId field',
message: `Invalid summary.json: ${z.prettifyError(parsed.error)}`,
})
}
const signingContext = `${taskId}${checkId}`
const summaryPayload = parsed.data
const checkId = summaryPayload.checkId ?? summaryPayload.inspectionId ?? ''
const signingContext = `${summaryPayload.taskId}${checkId}`
// Compute device signature
const ikm = config.licence + config.fingerprint