fix(server): 使用 lossless-json 无损处理 summary.json Long 精度
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
"@tanstack/react-start": "catalog:",
|
||||
"drizzle-orm": "catalog:",
|
||||
"jszip": "catalog:",
|
||||
"lossless-json": "catalog:",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"systeminformation": "catalog:",
|
||||
|
||||
@@ -10,12 +10,28 @@ import {
|
||||
} from '@furtherverse/crypto'
|
||||
import { ORPCError } from '@orpc/server'
|
||||
import JSZip from 'jszip'
|
||||
import {
|
||||
isInteger,
|
||||
isSafeNumber,
|
||||
LosslessNumber,
|
||||
parse as losslessParse,
|
||||
stringify as losslessStringify,
|
||||
} from 'lossless-json'
|
||||
import { z } from 'zod'
|
||||
import { extractSafeZipFiles, ZipValidationError } from '@/server/safe-zip'
|
||||
import { getUxConfig } from '@/server/ux-config'
|
||||
import { db } from '../middlewares'
|
||||
import { os } from '../server'
|
||||
|
||||
const safeNumberParser = (value: string): number | string => {
|
||||
if (isSafeNumber(value)) return Number(value)
|
||||
if (isInteger(value)) return value
|
||||
return Number(value)
|
||||
}
|
||||
|
||||
const toLosslessNumber = (value: string): LosslessNumber | string =>
|
||||
value !== '' && /^-?\d+$/.test(value) ? new LosslessNumber(value) : value
|
||||
|
||||
const summaryPayloadSchema = z
|
||||
.object({
|
||||
taskId: z.string().min(1, 'summary.json must contain a non-empty taskId'),
|
||||
@@ -94,7 +110,7 @@ export const signAndPackReport = os.crypto.signAndPackReport.use(db).handler(asy
|
||||
|
||||
let rawJson: unknown
|
||||
try {
|
||||
rawJson = JSON.parse(Buffer.from(summaryFile.bytes).toString('utf-8'))
|
||||
rawJson = losslessParse(Buffer.from(summaryFile.bytes).toString('utf-8'), undefined, safeNumberParser)
|
||||
} catch {
|
||||
throw new ORPCError('BAD_REQUEST', {
|
||||
message: 'summary.json in the ZIP is not valid JSON',
|
||||
@@ -138,15 +154,21 @@ export const signAndPackReport = os.crypto.signAndPackReport.use(db).handler(asy
|
||||
|
||||
// Build final summary.json with flat structure (matching Kotlin reference)
|
||||
const finalSummary = {
|
||||
orgId,
|
||||
checkId,
|
||||
orgId: toLosslessNumber(String(orgId)),
|
||||
checkId: toLosslessNumber(checkId),
|
||||
taskId: summaryPayload.taskId,
|
||||
licence: config.licence,
|
||||
fingerprint: config.fingerprint,
|
||||
deviceSignature,
|
||||
summary: summaryPayload.summary ?? '',
|
||||
}
|
||||
const summaryBytes = Buffer.from(JSON.stringify(finalSummary), 'utf-8')
|
||||
const summaryJson = losslessStringify(finalSummary)
|
||||
if (!summaryJson) {
|
||||
throw new ORPCError('INTERNAL_SERVER_ERROR', {
|
||||
message: 'Failed to serialize summary.json',
|
||||
})
|
||||
}
|
||||
const summaryBytes = Buffer.from(summaryJson, 'utf-8')
|
||||
|
||||
// Build manifest.json (fixed file list, matching Kotlin reference)
|
||||
const manifestFiles: Record<string, string> = {
|
||||
|
||||
3
bun.lock
3
bun.lock
@@ -49,6 +49,7 @@
|
||||
"@tanstack/react-start": "catalog:",
|
||||
"drizzle-orm": "catalog:",
|
||||
"jszip": "catalog:",
|
||||
"lossless-json": "^4.3.0",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"systeminformation": "catalog:",
|
||||
@@ -1078,6 +1079,8 @@
|
||||
|
||||
"log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="],
|
||||
|
||||
"lossless-json": ["lossless-json@4.3.0", "", {}, "sha512-ToxOC+SsduRmdSuoLZLYAr5zy1Qu7l5XhmPWM3zefCZ5IcrzW/h108qbJUKfOlDlhvhjUK84+8PSVX0kxnit0g=="],
|
||||
|
||||
"lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"electron-builder": "^26.8.1",
|
||||
"electron-vite": "^5.0.0",
|
||||
"jszip": "^3.10.1",
|
||||
"lossless-json": "^4.3.0",
|
||||
"motion": "^12.35.0",
|
||||
"nitro": "npm:nitro-nightly@3.0.1-20260227-181935-bfbb207c",
|
||||
"openpgp": "^6.0.1",
|
||||
|
||||
Reference in New Issue
Block a user