Files
2026-10-22 17:07:08 +08:00

87 lines
3.9 KiB
TypeScript
Executable File

import minecraftProtocol from "@wp2508/minecraft-protocol";
import type { ProxyOptions } from '@wp2508/mineflayer';
import {
validate_code_map,
type validate_username_code,
type validate_host_code,
type validate_port_code,
type validate_version_code,
type validate_proxy_code,
} from './validate_code_map';
const supportedVersions = minecraftProtocol.supportedVersions;
const username_code = validate_code_map.username;
const host_code = validate_code_map.host;
const port_code = validate_code_map.port;
const version_code = validate_code_map.version;
const proxy_code = validate_code_map.proxy;
// 检查 username 是否符合 Minecraft 用户名规则,返回错误码;0 表示通过
export function validate_username(username: string): validate_username_code {
if (typeof username !== 'string') return username_code.invalid_type;
if (username.length === 0) return username_code.empty;
if (username.length < 3) return username_code.too_short;
if (username.length > 16) return username_code.over_length;
if (!/^[A-Za-z0-9_]+$/.test(username)) return username_code.invalid_char;
return username_code.ok;
}
const IPV4_REGEX = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
const DOMAIN_REGEX = /^(?=.{1,253}$)([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$/;
function is_valid_ipv6(host: string): boolean {
const value = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
if (!value.includes(':')) return false;
try {
const url = new URL(`http://[${value}]`);
return url.hostname.length > 0;
} catch {
return false;
}
}
// 检查是否为 ip 地址或者域名,返回错误码;0 表示通过
export function validate_host(host: string): validate_host_code {
if (typeof host !== 'string') return host_code.invalid_type;
if (host.length === 0) return host_code.empty;
if (host.length > 253) return host_code.over_length;
if (IPV4_REGEX.test(host)) return host_code.ok;
if (is_valid_ipv6(host)) return host_code.ok;
if (DOMAIN_REGEX.test(host)) return host_code.ok;
return host_code.invalid_format;
}
// 检查端口是否在 0-65535 之间,返回错误码;0 表示通过
export function validate_port(port: number): validate_port_code {
if (typeof port !== 'number') return port_code.invalid_type;
if (Number.isNaN(port)) return port_code.not_number;
if (!Number.isInteger(port)) return port_code.not_integer;
if (port < 0 || port > 65535) return port_code.out_of_range;
return port_code.ok;
}
// 检查版本是否在版本列表中,返回错误码;0 表示通过
export function validate_version(version: string): validate_version_code {
if (typeof version !== 'string') return version_code.invalid_type;
if (version.length === 0) return version_code.empty;
if (!supportedVersions.includes(version)) return version_code.unsupported;
return version_code.ok;
}
const PROXY_TYPES = ['socks5', 'sock5', 'http', 'https'] as const;
// 检查代理配置是否合理,返回错误码;0 表示通过
export function validate_proxy(proxy: ProxyOptions): validate_proxy_code {
if (typeof proxy !== 'object' || proxy === null) return proxy_code.invalid_type;
if (!proxy.type) return proxy_code.missing_type;
if (!PROXY_TYPES.includes(proxy.type)) return proxy_code.invalid_type_value;
if (!proxy.host) return proxy_code.missing_host;
if (validate_host(proxy.host) !== host_code.ok) return proxy_code.invalid_host;
if (proxy.port === undefined || proxy.port === null) return proxy_code.missing_port;
if (validate_port(proxy.port) !== port_code.ok) return proxy_code.invalid_port;
if (proxy.username != null && typeof proxy.username !== 'string') return proxy_code.invalid_username;
if (proxy.password != null && typeof proxy.password !== 'string') return proxy_code.invalid_password;
return proxy_code.ok;
}