/** * 配置文件里的 Patchbay 标记。 * * 每次落盘都在顶层写一个 `patchbay:` 键(内核对未知顶层键不报错:解析用的 * `yaml.Unmarshal` 没开严格模式,config/config.go:612)。上传配置文件时靠它 * 区分「Patchbay 管理过的配置」和随便一份 mihomo 配置——前者直接还原, * 后者提示走导入。 * * sig 是盐加版本号的哈希,回答的是「这个标记是不是 Patchbay 写的」,不是防伪 * ——在用户自己的机器上没有对手。刻意不对配置内容做哈希:这个项目只接管部分 * 段落,手改其余段落是正常用法(决策记录 0003),内容哈希会把合法的手改 * 判成无效。 */ import type { ConfigObject } from '../vendor/config-editor/index.ts' export const MARKER_KEY = 'patchbay' const VERSION = 1 const SALT = 'patchbay-config-salt' /** FNV-1a。只做标记指纹,不是安全用途。 */ function fnv(text: string): string { let h = 0x811c9dc5 for (let i = 0; i < text.length; i++) { h ^= text.charCodeAt(i) h = Math.imul(h, 0x01000193) } return (h >>> 0).toString(16).padStart(8, '0') } const sigOf = (version: number): string => fnv(`${SALT}:${String(version)}`) /** 给一份配置打上标记。已有的旧标记会被换成当前版本的。 */ export function withMarker(data: ConfigObject): ConfigObject { return { ...data, [MARKER_KEY]: { v: VERSION, sig: sigOf(VERSION) } } } /** 这份配置带不带有效的 Patchbay 标记。 */ export function hasValidMarker(data: ConfigObject): boolean { const marker = data[MARKER_KEY] if (typeof marker !== 'object' || marker === null || Array.isArray(marker)) return false const { v, sig } = marker as Record return typeof v === 'number' && sig === sigOf(v) }