fix: support internal AgentBus attachments

This commit is contained in:
inman committed 2026-08-31 10:36:57 +08:00
1 parent cd45ce17d0
commit 161f90d09d
12 files changed
+96 -86

No files matched your search

+8 -45
View File
@@ -158,41 +158,6 @@ export function decodeInlineInputAttachment(
};
}
function ipv4Number(address: string): number | null {
const parts = address.split('.').map(Number);
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return null;
return (((parts[0] * 256 + parts[1]) * 256 + parts[2]) * 256 + parts[3]) >>> 0;
}
function ipv4InCidr(address: string, network: string, prefix: number): boolean {
const value = ipv4Number(address);
const base = ipv4Number(network);
if (value === null || base === null) return false;
const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
return (value & mask) === (base & mask);
}
export function isPrivateOrReservedIp(address: string): boolean {
const family = isIP(address);
if (family === 4) {
return [
['0.0.0.0', 8], ['10.0.0.0', 8], ['100.64.0.0', 10], ['127.0.0.0', 8],
['169.254.0.0', 16], ['172.16.0.0', 12], ['192.0.0.0', 24], ['192.0.2.0', 24],
['192.168.0.0', 16], ['198.18.0.0', 15], ['198.51.100.0', 24], ['203.0.113.0', 24],
['224.0.0.0', 4], ['240.0.0.0', 4]
].some(([network, prefix]) => ipv4InCidr(address, String(network), Number(prefix)));
}
if (family !== 6) return true;
const normalized = address.toLowerCase().split('%')[0];
if (normalized === '::' || normalized === '::1') return true;
const mapped = /^(?:::ffff:)?(\d+\.\d+\.\d+\.\d+)$/.exec(normalized);
if (mapped) return isPrivateOrReservedIp(mapped[1]);
return /^(?:fc|fd)/.test(normalized)
|| /^fe[89ab]/.test(normalized)
|| /^ff/.test(normalized)
|| normalized.startsWith('2001:db8:');
}
export function validateAgentBusAttachmentUrl(value: unknown): URL {
let url: URL;
try {
@@ -203,12 +168,8 @@ export function validateAgentBusAttachmentUrl(value: unknown): URL {
if (url.protocol !== 'https:' || url.username || url.password) {
throw new InputAttachmentError('roster_attachment_url_unsafe', '名单附件必须使用不含用户名密码的 HTTPS URL。');
}
const hostname = url.hostname.replace(/^\[|\]$/g, '');
if (!hostname || hostname.toLowerCase() === 'localhost') {
throw new InputAttachmentError('roster_attachment_url_unsafe', '名单附件 URL 指向了不允许的地址。');
}
if (isIP(hostname) && isPrivateOrReservedIp(hostname)) {
throw new InputAttachmentError('roster_attachment_url_unsafe', '名单附件 URL 指向了不允许的地址。');
if (!url.hostname.replace(/^\[|\]$/g, '')) {
throw new InputAttachmentError('roster_attachment_url_invalid', '名单附件 URL 无效。');
}
return url;
}
@@ -230,7 +191,9 @@ export function parseAgentBusInputAttachment(
};
}
async function publicAddresses(hostname: string): Promise<Array<{ address: string; family: number }>> {
export async function resolveAgentBusAttachmentAddresses(
hostname: string
): Promise<Array<{ address: string; family: number }>> {
if (isIP(hostname)) return [{ address: hostname, family: isIP(hostname) }];
let addresses: Array<{ address: string; family: number }>;
try {
@@ -238,8 +201,8 @@ async function publicAddresses(hostname: string): Promise<Array<{ address: strin
} catch {
throw new InputAttachmentError('roster_attachment_host_unresolved', '名单附件地址无法解析。');
}
if (!addresses.length || addresses.some((item) => isPrivateOrReservedIp(item.address))) {
throw new InputAttachmentError('roster_attachment_url_unsafe', '名单附件地址解析到了不允许的网络。');
if (!addresses.length) {
throw new InputAttachmentError('roster_attachment_host_unresolved', '名单附件地址无法解析。');
}
return addresses;
}
@@ -319,7 +282,7 @@ export async function downloadAgentBusInputAttachment(
redirectCount = redirects;
const dnsStartedAt = process.hrtime.bigint();
emitAttachmentDiagnostic(diagnostic, 'dns_started', { redirect_count: redirects });
const addresses = await publicAddresses(url.hostname.replace(/^\[|\]$/g, ''));
const addresses = await resolveAgentBusAttachmentAddresses(url.hostname.replace(/^\[|\]$/g, ''));
emitAttachmentDiagnostic(diagnostic, 'dns_validated', {
redirect_count: redirects,
address_count: addresses.length,