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 }