fix: hysteria2 带 pinSHA256 时跳过证书校验
带 pinSHA256 的 hysteria2 节点用自签/SNI 伪装证书(如 sni=www.bing.com), 靠指纹固定校验而非标准 CA 链。Surge 的 server-cert-fingerprint-sha256 实测 不可靠(仍按 SNI 主机名校验并拒绝),故改为输出 skip-cert-verify=true, 与 Shadowrocket 等客户端的实际行为一致。 新增 regen-surge-lines.ts 一次性脚本:从 uri 重新生成所有静态节点的 surge_line(保留自定义名字),修正解析器改动前已存的节点。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -18,11 +18,17 @@ export function parseHysteria2(uri: string): ParsedNode {
|
|||||||
const sni = params.get('sni') || '';
|
const sni = params.get('sni') || '';
|
||||||
const obfs = params.get('obfs') || '';
|
const obfs = params.get('obfs') || '';
|
||||||
const obfsPassword = params.get('obfs-password') || params.get('obfs_password') || '';
|
const obfsPassword = params.get('obfs-password') || params.get('obfs_password') || '';
|
||||||
|
// pinSHA256 means the node uses a self-signed / SNI-masqueraded cert verified by
|
||||||
|
// fingerprint rather than the standard CA chain. Surge's server-cert-fingerprint-sha256
|
||||||
|
// proved unreliable here (it still validates against the SNI hostname and rejects the
|
||||||
|
// cert), so in that case we skip standard verification — matching the effective behavior
|
||||||
|
// of clients like Shadowrocket that connect fine via pinSHA256.
|
||||||
|
const hasPin = !!(params.get('pinSHA256') || params.get('pinsha256'));
|
||||||
|
|
||||||
let line = `${name} = hysteria2, ${server}, ${port}, password=${auth}`;
|
let line = `${name} = hysteria2, ${server}, ${port}, password=${auth}`;
|
||||||
if (sni) line += `, sni=${sni}`;
|
if (sni) line += `, sni=${sni}`;
|
||||||
if (obfs === 'salamander' && obfsPassword) line += `, salamander-password=${obfsPassword}`;
|
if (obfs === 'salamander' && obfsPassword) line += `, salamander-password=${obfsPassword}`;
|
||||||
line += `, skip-cert-verify=${readInsecure(params)}`;
|
line += `, skip-cert-verify=${readInsecure(params) || hasPin}`;
|
||||||
|
|
||||||
return { name, type: 'hysteria2', server, port, surgeLine: line };
|
return { name, type: 'hysteria2', server, port, surgeLine: line };
|
||||||
}
|
}
|
||||||
|
|||||||
43
server/src/scripts/regen-surge-lines.ts
Normal file
43
server/src/scripts/regen-surge-lines.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// One-off migration: regenerate static_nodes.surge_line from their stored uri
|
||||||
|
// using the current parsers. Static nodes cache surge_line at add-time, so a
|
||||||
|
// parser fix (e.g. hysteria2 skip-cert-verify) does not reach already-stored
|
||||||
|
// nodes until they are re-parsed. The custom node name is preserved.
|
||||||
|
//
|
||||||
|
// Run inside the container: pnpm exec tsx src/scripts/regen-surge-lines.ts
|
||||||
|
import db from '../db.js';
|
||||||
|
import { parseNodeUri } from '../parsers/index.js';
|
||||||
|
|
||||||
|
function renameSurgeLine(surgeLine: string, oldName: string, newName: string): string {
|
||||||
|
if (surgeLine.startsWith(oldName + ' = ')) {
|
||||||
|
return newName + surgeLine.slice(oldName.length);
|
||||||
|
}
|
||||||
|
return surgeLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = db.prepare('SELECT id, name, uri, surge_line FROM static_nodes').all() as Array<{
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
uri: string;
|
||||||
|
surge_line: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const update = db.prepare('UPDATE static_nodes SET surge_line = ?, type = ? WHERE id = ?');
|
||||||
|
let changed = 0;
|
||||||
|
|
||||||
|
for (const row of rows) {
|
||||||
|
const node = parseNodeUri(row.uri);
|
||||||
|
if (!node) {
|
||||||
|
console.warn(`[skip] id=${row.id} "${row.name}" — unparseable uri`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const newLine = renameSurgeLine(node.surgeLine, node.name, row.name);
|
||||||
|
if (newLine !== row.surge_line) {
|
||||||
|
update.run(newLine, node.type, row.id);
|
||||||
|
changed++;
|
||||||
|
console.log(`[updated] id=${row.id} "${row.name}"`);
|
||||||
|
console.log(` old: ${row.surge_line}`);
|
||||||
|
console.log(` new: ${newLine}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDone. ${changed}/${rows.length} static node(s) regenerated.`);
|
||||||
Reference in New Issue
Block a user