'use strict' /** * 安全协议唯一使用的 canonical JSON。对象键按字典序排列,null/undefined 字段省略; * 非 JSON 协议值、数组空位和不确定的对象形态直接拒绝。 */ function canonicalJson(value) { if (value === null) return 'null' if (typeof value === 'string' || typeof value === 'boolean') return JSON.stringify(value) if (typeof value === 'number') { if (!Number.isFinite(value)) throw new TypeError('Canonical JSON requires finite numbers') return JSON.stringify(value) } if (Array.isArray(value)) { for (let index = 0; index < value.length; index += 1) { if (!Object.prototype.hasOwnProperty.call(value, index) || value[index] === undefined) { throw new TypeError('Canonical JSON arrays cannot contain holes or undefined') } } return `[${value.map(canonicalJson).join(',')}]` } if (value && typeof value === 'object') { const prototype = Object.getPrototypeOf(value) if (prototype !== Object.prototype && prototype !== null) { throw new TypeError('Canonical JSON only supports plain objects') } const keys = Reflect.ownKeys(value) if (keys.some(key => typeof key === 'symbol')) { throw new TypeError('Canonical JSON does not support symbol keys') } for (const key of keys) { const descriptor = Object.getOwnPropertyDescriptor(value, key) if (!descriptor?.enumerable || !('value' in descriptor)) { throw new TypeError('Canonical JSON only supports enumerable data properties') } } return `{${keys .filter(key => value[key] !== null && value[key] !== undefined) .sort() .map(key => `${JSON.stringify(key)}:${canonicalJson(value[key])}`) .join(',')}}` } throw new TypeError(`Canonical JSON does not support ${typeof value}`) } module.exports = { canonicalJson }