link_chang/src/Util/node/Vless.ts

153 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Base64 } from 'js-base64';
class VLESSQuery {
constructor(
public security: string,
public alpn: string[],
public sni: string,
public fp: string,
public sid: string,
public pbk: string,
public flow: string,
public encryption: string,
public type: string,
public headerType: string,
public path: string,
public host: string
) { }
}
class VLESS {
constructor(
public name: string,
public uuid: string,
public server: string,
public port: number,
public query: VLESSQuery
) { }
// Base64 解码函数
// private static base64Decode(str: string): string {
// return Buffer.from(str, 'base64').toString('utf-8');
// }
// 编码 VLESS URL
encodeURL(): string {
const url = new URL(`vless://${this.uuid}@${this.server}:${this.port}`);
// 设置 Query 参数
const query = url.searchParams;
query.set('security', this.query.security);
query.set('sni', this.query.sni);
query.set('fp', this.query.fp);
query.set('sid', this.query.sid);
query.set('pbk', this.query.pbk);
query.set('flow', this.query.flow);
query.set('encryption', this.query.encryption);
query.set('type', this.query.type);
query.set('headerType', this.query.headerType);
query.set('path', this.query.path);
query.set('host', this.query.host);
// 移除空值参数
for (const [key, value] of query) {
if (value === '') {
query.delete(key);
}
}
// 如果有 name设置为 Fragment
if (this.name) {
url.hash = this.name;
} else {
url.hash = `${this.server}:${this.port}`;
}
return url.toString();
}
// 解码 VLESS URL
static decodeURL(urlStr: string): VLESS {
if (!urlStr.startsWith('vless://')) {
throw new Error(`Invalid vless URL: ${urlStr}`);
}
const decodedUrl = urlStr.split('@');
const url = new URL(`http://${decodedUrl[1]}`);
const regex = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/;
const match = urlStr.match(regex);
const uuid = match[0];
const hostname = url.hostname;
const port = parseInt(url.port, 10);
const query = url.searchParams;
const encryption = query.get('encryption') || '';
const security = query.get('security') || '';
const type = query.get('type') || '';
const flow = query.get('flow') || '';
const headerType = query.get('headerType') || '';
const pbk = query.get('pbk') || '';
const sid = query.get('sid') || '';
const fp = query.get('fp') || '';
const alpns = query.get('alpn') || '';
const alpn = alpns ? alpns.split(',') : [];
const sni = query.get('sni') || '';
const path = query.get('path') || '';
const host = query.get('host') || '';
// 获取 name若为空则使用 `hostname:port`
const name = url.hash ? decodeURIComponent(url.hash.slice(1)) : `${hostname}:${port}`;
const queryObj = new VLESSQuery(
security,
alpn,
sni,
fp,
sid,
pbk,
flow,
encryption,
type,
headerType,
path,
host
);
return new VLESS(name, uuid, hostname, port, queryObj);
}
}
// // 示例用法
// function callVLESS() {
// const vless = new VLESS(
// 'Sharon-香港',
// '6adb4f43-9813-45f4-abf8-772be7db08sd',
// 'ss.com',
// 443,
// new VLESSQuery(
// 'reality',
// ['http/1.1'],
// 'ss.com',
// 'chrome',
// '',
// 'g-oxbqigzCaXqARxuyD2_vbTYeMD9zn8wnTo02S69QM',
// 'xtls-rprx-vision',
// 'none',
// 'tcp',
// 'none',
// '',
// ''
// )
// );
// const encoded = vless.encodeURL();
// console.log('Encoded VLESS URL:', encoded);
// const decoded = VLESS.decodeURL(encoded);
// console.log('Decoded VLESS:', decoded);
// }
// callVLESS();
export { VLESS }