Files
podkop/fe-app-podkop/src/validators/validateHysteriaUrl.ts
2025-12-01 16:38:26 +02:00

118 lines
3.0 KiB
TypeScript

import { ValidationResult } from './types';
import { parseQueryString } from '../helpers/parseQueryString';
export function validateHysteria2Url(url: string): ValidationResult {
try {
const isHY2 = url.startsWith('hysteria2://');
const isHY2Short = url.startsWith('hy2://');
if (!isHY2 && !isHY2Short) {
return {
valid: false,
message: _('Invalid HY2 URL: must start with hysteria2:// or hy2://'),
};
}
if (/\s/.test(url)) {
return {
valid: false,
message: _('Invalid HY2 URL: must not contain spaces'),
};
}
const prefix = isHY2 ? 'hysteria2://' : 'hy2://';
const body = url.slice(prefix.length);
const [mainPart] = body.split('#');
const [authHostPort, queryString] = mainPart.split('?');
if (!authHostPort)
return {
valid: false,
message: _('Invalid HY2 URL: missing credentials/server'),
};
const [passwordPart, hostPortPart] = authHostPort.split('@');
if (!passwordPart)
return { valid: false, message: _('Invalid HY2 URL: missing password') };
if (!hostPortPart)
return {
valid: false,
message: _('Invalid HY2 URL: missing host & port'),
};
const [host, port] = hostPortPart.split(':');
if (!host) {
return { valid: false, message: _('Invalid HY2 URL: missing host') };
}
if (!port) {
return { valid: false, message: _('Invalid HY2 URL: missing port') };
}
const cleanedPort = port.replace('/', '');
const portNum = Number(cleanedPort);
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
return {
valid: false,
message: _('Invalid HY2 URL: invalid port number'),
};
}
if (queryString) {
const params = parseQueryString(queryString);
const paramsKeys = Object.keys(params);
if (
paramsKeys.includes('insecure') &&
!['0', '1'].includes(params.insecure)
) {
return {
valid: false,
message: _('Invalid HY2 URL: insecure must be 0 or 1'),
};
}
const validObfsTypes = ['none', 'salamander'];
if (
paramsKeys.includes('obfs') &&
!validObfsTypes.includes(params.obfs)
) {
return {
valid: false,
message: _('Invalid HY2 URL: unsupported obfs type'),
};
}
if (
paramsKeys.includes('obfs') &&
params.obfs !== 'none' &&
!params['obfs-password']
) {
return {
valid: false,
message: _(
'Invalid HY2 URL: obfs-password required when obfs is set',
),
};
}
if (paramsKeys.includes('sni') && !params.sni) {
return {
valid: false,
message: _('Invalid HY2 URL: sni cannot be empty'),
};
}
}
return { valid: true, message: _('Valid') };
} catch (_e) {
return { valid: false, message: _('Invalid HY2 URL: parsing failed') };
}
}