Various bug fixes for URI format parsing

This commit is contained in:
Peng-YM 2022-06-20 17:00:57 +08:00
parent 4dde556daf
commit e401a31b6c
7 changed files with 68 additions and 74 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "sub-store", "name": "sub-store",
"version": "2.0.7", "version": "2.0.8",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js", "main": "src/main.js",
"scripts": { "scripts": {

View File

@ -1,3 +1,4 @@
import { getIfNotBlank, isPresent, isNotBlank, getIfPresent } from '@/utils';
import getSurgeParser from './peggy/surge'; import getSurgeParser from './peggy/surge';
import getLoonParser from './peggy/loon'; import getLoonParser from './peggy/loon';
import getQXParser from './peggy/qx'; import getQXParser from './peggy/qx';
@ -11,14 +12,12 @@ function URI_SS() {
return /^ss:\/\//.test(line); return /^ss:\/\//.test(line);
}; };
const parse = (line) => { const parse = (line) => {
const supported = {};
// parse url // parse url
let content = line.split('ss://')[1]; let content = line.split('ss://')[1];
const proxy = { const proxy = {
name: decodeURIComponent(line.split('#')[1]), name: decodeURIComponent(line.split('#')[1]),
type: 'ss', type: 'ss',
supported,
}; };
content = content.split('#')[0]; // strip proxy name content = content.split('#')[0]; // strip proxy name
// handle IPV4 and IPV6 // handle IPV4 and IPV6
@ -49,21 +48,16 @@ function URI_SS() {
proxy.plugin = 'obfs'; proxy.plugin = 'obfs';
proxy['plugin-opts'] = { proxy['plugin-opts'] = {
mode: params.obfs, mode: params.obfs,
host: params['obfs-host'], host: getIfNotBlank(params['obfs-host']),
}; };
break; break;
case 'v2ray-plugin': case 'v2ray-plugin':
proxy.supported = {
...supported,
Loon: false,
Surge: false,
};
proxy.obfs = 'v2ray-plugin'; proxy.obfs = 'v2ray-plugin';
proxy['plugin-opts'] = { proxy['plugin-opts'] = {
mode: 'websocket', mode: 'websocket',
host: params['obfs-host'], host: getIfNotBlank(params['obfs-host']),
path: params.path || '', path: getIfNotBlank(params.path),
tls: params.tls || false, tls: getIfPresent(params.tls),
}; };
break; break;
default: default:
@ -83,10 +77,6 @@ function URI_SSR() {
const test = (line) => { const test = (line) => {
return /^ssr:\/\//.test(line); return /^ssr:\/\//.test(line);
}; };
const supported = {
Surge: false,
};
const parse = (line) => { const parse = (line) => {
line = Base64.decode(line.split('ssr://')[1]); line = Base64.decode(line.split('ssr://')[1]);
@ -116,7 +106,6 @@ function URI_SSR() {
cipher: params[1], cipher: params[1],
obfs: params[2], obfs: params[2],
password: Base64.decode(params[3]), password: Base64.decode(params[3]),
supported,
}; };
// get other params // get other params
const other_params = {}; const other_params = {};
@ -132,12 +121,11 @@ function URI_SSR() {
name: other_params.remarks name: other_params.remarks
? Base64.decode(other_params.remarks) ? Base64.decode(other_params.remarks)
: proxy.server, : proxy.server,
'protocol-param': Base64.decode( 'protocol-param': getIfNotBlank(
other_params.protoparam || '', Base64.decode(other_params.protoparam || '').replace(/\s/g, ''),
).replace(/\s/g, ''), ),
'obfs-param': Base64.decode(other_params.obfsparam || '').replace( 'obfs-param': getIfNotBlank(
/\s/g, Base64.decode(other_params.obfsparam || '').replace(/\s/g, ''),
'',
), ),
}; };
return proxy; return proxy;
@ -156,7 +144,6 @@ function URI_VMess() {
return /^vmess:\/\//.test(line); return /^vmess:\/\//.test(line);
}; };
const parse = (line) => { const parse = (line) => {
const supported = {};
line = line.split('vmess://')[1]; line = line.split('vmess://')[1];
const content = Base64.decode(line); const content = Base64.decode(line);
if (/=\s*vmess/.test(content)) { if (/=\s*vmess/.test(content)) {
@ -176,41 +163,38 @@ function URI_VMess() {
type: 'vmess', type: 'vmess',
server: partitions[1], server: partitions[1],
port: partitions[2], port: partitions[2],
cipher: partitions[3], cipher: getIfNotBlank(partitions[3], 'auto'),
uuid: partitions[4].match(/^"(.*)"$/)[1], uuid: partitions[4].match(/^"(.*)"$/)[1],
tls: params.obfs === 'over-tls' || params.obfs === 'wss', tls: params.obfs === 'wss',
udp: getIfPresent(params['udp-relay']),
tfo: getIfPresent(params['fast-open']),
'skip-cert-verify': isPresent(params['tls-verification'])
? !params['tls-verification']
: undefined,
}; };
if (typeof params['udp-relay'] !== 'undefined')
proxy.udp = JSON.parse(params['udp-relay']);
if (typeof params['fast-open'] !== 'undefined')
proxy.udp = JSON.parse(params['fast-open']);
// handle ws headers // handle ws headers
if (isPresent(params.obfs)) {
if (params.obfs === 'ws' || params.obfs === 'wss') { if (params.obfs === 'ws' || params.obfs === 'wss') {
proxy.network = 'ws'; proxy.network = 'ws';
proxy['ws-opts'].path = (params['obfs-path'] || '"/"').match( proxy['ws-opts'].path = (
/^"(.*)"$/, getIfNotBlank(params['obfs-path']) || '"/"'
)[1]; ).match(/^"(.*)"$/)[1];
let obfs_host = params['obfs-header']; let obfs_host = params['obfs-header'];
if (obfs_host && obfs_host.indexOf('Host') !== -1) { if (obfs_host && obfs_host.indexOf('Host') !== -1) {
obfs_host = obfs_host.match(/Host:\s*([a-zA-Z0-9-.]*)/)[1]; obfs_host = obfs_host.match(
/Host:\s*([a-zA-Z0-9-.]*)/,
)[1];
} }
if (isNotBlank(obfs_host)) {
proxy['ws-opts'].headers = { proxy['ws-opts'].headers = {
Host: obfs_host || proxy.server, // if no host provided, use the same as server Host: obfs_host,
}; };
} }
} else {
// handle scert throw new Error(`Unsupported obfs: ${params.obfs}`);
if (proxy.tls && params['"tls-verification"'] === 'false') {
proxy['skip-cert-verify'] = true;
} }
// handle sni
if (proxy.tls && params['obfs-host']) {
proxy.sni = params['obfs-host'];
} }
return proxy; return proxy;
} else { } else {
// V2rayN URI format // V2rayN URI format
@ -222,25 +206,23 @@ function URI_VMess() {
port: params.port, port: params.port,
cipher: 'auto', // V2rayN has no default cipher! use aes-128-gcm as default. cipher: 'auto', // V2rayN has no default cipher! use aes-128-gcm as default.
uuid: params.id, uuid: params.id,
alterId: params.aid || 0, alterId: getIfPresent(params.aid, 0),
tls: params.tls === 'tls' || params.tls === true, tls: params.tls === 'tls' || params.tls === true,
supported, 'skip-cert-verify': isPresent(params.verify_cert)
? !params.verify_cert
: undefined,
}; };
// handle obfs // handle obfs
if (params.net === 'ws') { if (params.net === 'ws') {
proxy.network = 'ws'; proxy.network = 'ws';
proxy['ws-opts'] = { proxy['ws-opts'] = {
path: params.path, path: getIfNotBlank(params.path),
headers: { Host: params.host || params.add }, headers: { Host: getIfNotBlank(params.host) },
}; };
if (proxy.tls && params.host) { if (proxy.tls && params.host) {
proxy.sni = params.host; proxy.sni = params.host;
} }
} }
// handle scert
if (params.verify_cert === false) {
proxy['skip-cert-verify'] = true;
}
return proxy; return proxy;
} }
}; };
@ -255,7 +237,6 @@ function URI_Trojan() {
}; };
const parse = (line) => { const parse = (line) => {
const supported = {};
line = line.split('trojan://')[1]; line = line.split('trojan://')[1];
const [server, port] = line.split('@')[1].split('?')[0].split(':'); const [server, port] = line.split('@')[1].split('?')[0].split(':');
const name = decodeURIComponent(line.split('#')[1].trim()); const name = decodeURIComponent(line.split('#')[1].trim());
@ -278,7 +259,6 @@ function URI_Trojan() {
port, port,
password: line.split('@')[0], password: line.split('@')[0],
sni, sni,
supported,
}; };
}; };
return { name, test, parse }; return { name, test, parse };

View File

@ -144,9 +144,6 @@ function trojan(proxy) {
} }
} }
// tls
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint // tls fingerprint
appendIfPresent( appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, `,tls-cert-sha256=${proxy['tls-fingerprint']}`,

View File

@ -25,5 +25,6 @@ export class Result {
} }
export function isPresent(obj, attr) { export function isPresent(obj, attr) {
return typeof _.get(obj, attr) !== 'undefined'; const data = _.get(obj, attr);
return typeof data !== 'undefined' && data !== null;
} }

View File

@ -13,4 +13,20 @@ function isIPv6(ip) {
return IPV6_REGEX.test(ip); return IPV6_REGEX.test(ip);
} }
export { isIPv4, isIPv6 }; function isNotBlank(str) {
return typeof str === 'string' && str.trim().length > 0;
}
function getIfNotBlank(str, defaultValue) {
return isNotBlank(str) ? str : defaultValue;
}
function isPresent(obj) {
return typeof obj !== 'undefined' && obj !== null;
}
function getIfPresent(obj, defaultValue) {
return isPresent(obj) ? obj : defaultValue;
}
export { isIPv4, isIPv6, isNotBlank, getIfNotBlank, isPresent, getIfPresent };

File diff suppressed because one or more lines are too long