mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
739100c873 | ||
|
|
a4384f4f13 | ||
|
|
468d136f0e | ||
|
|
b0c1157fe1 | ||
|
|
56626dabc7 | ||
|
|
2a87f7b3c3 | ||
|
|
81adfbc461 | ||
|
|
e04217c50d | ||
|
|
391a5aa2e4 | ||
|
|
2f3b42f552 | ||
|
|
76302f9d53 | ||
|
|
1924e9735c | ||
|
|
6a8cee3cd5 | ||
|
|
9b2209cc8b | ||
|
|
c585785c50 | ||
|
|
c3e5da7ee4 | ||
|
|
2ecad8bbb8 | ||
|
|
a642213928 | ||
|
|
f85e360ea8 | ||
|
|
1b948cdf52 | ||
|
|
556d5f393c | ||
|
|
a8c05207c0 | ||
|
|
e97fb1e6d9 | ||
|
|
e40b9a77c4 | ||
|
|
df0ac8a218 | ||
|
|
36377f3c20 | ||
|
|
47f26bdac8 | ||
|
|
a8a89ee2a2 | ||
|
|
199c5fb337 | ||
|
|
df505616ec | ||
|
|
c5b11f8b36 | ||
|
|
b19b49d2fa | ||
|
|
395c6e4e4a | ||
|
|
ae1c738f70 | ||
|
|
02d54208b0 |
11
.github/workflows/main.yml
vendored
11
.github/workflows/main.yml
vendored
@@ -59,6 +59,17 @@ jobs:
|
|||||||
./backend/dist/sub-store-parser.loon.min.js
|
./backend/dist/sub-store-parser.loon.min.js
|
||||||
./backend/dist/cron-sync-artifacts.min.js
|
./backend/dist/cron-sync-artifacts.min.js
|
||||||
./backend/dist/sub-store.bundle.js
|
./backend/dist/sub-store.bundle.js
|
||||||
|
- name: Git push assets to "release" branch
|
||||||
|
run: |
|
||||||
|
cd backend/dist || exit 1
|
||||||
|
git init
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git checkout -b release
|
||||||
|
git add .
|
||||||
|
git commit -m "release: ${{ steps.tag.outputs.release_tag }}"
|
||||||
|
git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}"
|
||||||
|
git push -f -u origin release
|
||||||
- name: Sync to GitLab
|
- name: Sync to GitLab
|
||||||
env:
|
env:
|
||||||
GITLAB_PIPELINE_TOKEN: ${{ secrets.GITLAB_PIPELINE_TOKEN }}
|
GITLAB_PIPELINE_TOKEN: ${{ secrets.GITLAB_PIPELINE_TOKEN }}
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "web"]
|
|
||||||
path = web
|
|
||||||
url = https://github.com/sub-store-org/Sub-Store-Front-End.git
|
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -26,15 +26,13 @@ Core functionalities:
|
|||||||
|
|
||||||
### Supported Input Formats
|
### Supported Input Formats
|
||||||
|
|
||||||
- [x] SS URI
|
- [x] URI(SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5)
|
||||||
- [x] SSR URI
|
- [x] Clash Proxies YAML
|
||||||
- [x] SSD URI
|
- [x] Clash Proxy JSON(single line)
|
||||||
- [x] V2RayN URI
|
|
||||||
- [x] Hysteria 2 URI
|
|
||||||
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS)
|
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS)
|
||||||
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, SOCKS5, WireGuard, VLESS, Hysteria 2)
|
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, SOCKS5, WireGuard, VLESS, Hysteria 2)
|
||||||
- [x] Surge (SS, VMess, Trojan, HTTP, SOCKS5, TUIC, Snell, Hysteria 2, SSR(external, only for macOS), External Proxy Program(only for macOS), WireGuard(Surge to Surge))
|
- [x] Surge (SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, TUIC, Snell, Hysteria 2, SSH(Password authentication only), SSR(external, only for macOS), External Proxy Program(only for macOS), WireGuard(Surge to Surge))
|
||||||
- [x] Surfboard (SS, VMess, Trojan, HTTP, SOCKS5, WireGuard(Surfboard to Surfboard))
|
- [x] Surfboard (SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, WireGuard(Surfboard to Surfboard))
|
||||||
- [x] Shadowrocket (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC)
|
- [x] Shadowrocket (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC)
|
||||||
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC)
|
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC)
|
||||||
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC)
|
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC)
|
||||||
@@ -84,15 +82,25 @@ Install `pnpm`
|
|||||||
Go to `backend` directories, install node dependencies:
|
Go to `backend` directories, install node dependencies:
|
||||||
|
|
||||||
```
|
```
|
||||||
pnpm install
|
pnpm i
|
||||||
```
|
```
|
||||||
|
|
||||||
1. In `backend`, run the backend server on http://localhost:3000
|
1. In `backend`, run the backend server on http://localhost:3000
|
||||||
|
|
||||||
|
babel(old school)
|
||||||
|
|
||||||
```
|
```
|
||||||
pnpm start
|
pnpm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
esbuild(experimental)
|
||||||
|
|
||||||
|
```
|
||||||
|
pnpm run --parallel "/^dev:.*/"
|
||||||
|
```
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
This project is under the GPL V3 LICENSE.
|
This project is under the GPL V3 LICENSE.
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ const path = require('path');
|
|||||||
const { build } = require('esbuild');
|
const { build } = require('esbuild');
|
||||||
|
|
||||||
!(async () => {
|
!(async () => {
|
||||||
|
const version = JSON.parse(
|
||||||
|
fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'),
|
||||||
|
).version.trim();
|
||||||
|
|
||||||
const artifacts = [
|
const artifacts = [
|
||||||
{ src: 'src/main.js', dest: 'sub-store.min.js' },
|
{ src: 'src/main.js', dest: 'sub-store.min.js' },
|
||||||
{
|
{
|
||||||
@@ -54,6 +58,16 @@ const { build } = require('esbuild');
|
|||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
outfile: 'dist/sub-store.bundle.js',
|
outfile: 'dist/sub-store.bundle.js',
|
||||||
});
|
});
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(__dirname, 'dist/sub-store.bundle.js'),
|
||||||
|
`// SUB_STORE_BACKEND_VERSION: ${version}
|
||||||
|
${fs.readFileSync(path.join(__dirname, 'dist/sub-store.bundle.js'), {
|
||||||
|
encoding: 'utf8',
|
||||||
|
})}`,
|
||||||
|
{
|
||||||
|
encoding: 'utf8',
|
||||||
|
},
|
||||||
|
);
|
||||||
})()
|
})()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
|||||||
@@ -3,23 +3,49 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { build } = require('esbuild');
|
const { build } = require('esbuild');
|
||||||
|
|
||||||
let content = fs.readFileSync(path.join(__dirname, 'sub-store.min.js'), {
|
!(async () => {
|
||||||
encoding: 'utf8',
|
const version = JSON.parse(
|
||||||
});
|
fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'),
|
||||||
content = content.replace(
|
).version.trim();
|
||||||
/eval\(('|")(require\(('|").*?('|")\))('|")\)/g,
|
|
||||||
'$2',
|
|
||||||
);
|
|
||||||
fs.writeFileSync(path.join(__dirname, 'dist/sub-store.no-bundle.js'), content, {
|
|
||||||
encoding: 'utf8',
|
|
||||||
});
|
|
||||||
|
|
||||||
build({
|
let content = fs.readFileSync(path.join(__dirname, 'sub-store.min.js'), {
|
||||||
entryPoints: ['dist/sub-store.no-bundle.js'],
|
encoding: 'utf8',
|
||||||
bundle: true,
|
});
|
||||||
minify: true,
|
content = content.replace(
|
||||||
sourcemap: true,
|
/eval\(('|")(require\(('|").*?('|")\))('|")\)/g,
|
||||||
platform: 'node',
|
'$2',
|
||||||
format: 'cjs',
|
);
|
||||||
outfile: 'dist/sub-store.bundle.js',
|
fs.writeFileSync(
|
||||||
});
|
path.join(__dirname, 'dist/sub-store.no-bundle.js'),
|
||||||
|
content,
|
||||||
|
{
|
||||||
|
encoding: 'utf8',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await build({
|
||||||
|
entryPoints: ['dist/sub-store.no-bundle.js'],
|
||||||
|
bundle: true,
|
||||||
|
minify: true,
|
||||||
|
sourcemap: true,
|
||||||
|
platform: 'node',
|
||||||
|
format: 'cjs',
|
||||||
|
outfile: 'dist/sub-store.bundle.js',
|
||||||
|
});
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(__dirname, 'dist/sub-store.bundle.js'),
|
||||||
|
`// SUB_STORE_BACKEND_VERSION: ${version}
|
||||||
|
${fs.readFileSync(path.join(__dirname, 'dist/sub-store.bundle.js'), {
|
||||||
|
encoding: 'utf8',
|
||||||
|
})}`,
|
||||||
|
{
|
||||||
|
encoding: 'utf8',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
console.log('done');
|
||||||
|
});
|
||||||
|
|||||||
24
backend/dev-esbuild.js
Normal file
24
backend/dev-esbuild.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const { build } = require('esbuild');
|
||||||
|
|
||||||
|
!(async () => {
|
||||||
|
const artifacts = [{ src: 'src/main.js', dest: 'sub-store.min.js' }];
|
||||||
|
|
||||||
|
for await (const artifact of artifacts) {
|
||||||
|
await build({
|
||||||
|
entryPoints: [artifact.src],
|
||||||
|
bundle: true,
|
||||||
|
minify: false,
|
||||||
|
sourcemap: false,
|
||||||
|
platform: 'node',
|
||||||
|
format: 'cjs',
|
||||||
|
outfile: artifact.dest,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
console.log('done');
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.203",
|
"version": "2.14.236",
|
||||||
"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": {
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
"test": "gulp peggy && npx cross-env BABEL_ENV=test mocha src/test/**/*.spec.js --require @babel/register --recursive",
|
"test": "gulp peggy && npx cross-env BABEL_ENV=test mocha src/test/**/*.spec.js --require @babel/register --recursive",
|
||||||
"serve": "node sub-store.min.js",
|
"serve": "node sub-store.min.js",
|
||||||
"start": "nodemon -w src -w package.json --exec babel-node src/main.js",
|
"start": "nodemon -w src -w package.json --exec babel-node src/main.js",
|
||||||
|
"dev:esbuild": "nodemon -w src -w package.json dev-esbuild.js",
|
||||||
|
"dev:run": "nodemon -w sub-store.min.js sub-store.min.js",
|
||||||
"build": "gulp",
|
"build": "gulp",
|
||||||
"bundle": "node bundle.js"
|
"bundle": "node bundle.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import YAML from '@/utils/yaml';
|
import YAML from '@/utils/yaml';
|
||||||
import download from '@/utils/download';
|
import download from '@/utils/download';
|
||||||
import { isIPv4, isIPv6, isValidPortNumber } from '@/utils';
|
import {
|
||||||
|
isIPv4,
|
||||||
|
isIPv6,
|
||||||
|
isValidPortNumber,
|
||||||
|
isNotBlank,
|
||||||
|
utf8ArrayToStr,
|
||||||
|
} from '@/utils';
|
||||||
import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
|
import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
|
||||||
import PROXY_PREPROCESSORS from './preprocessors';
|
import PROXY_PREPROCESSORS from './preprocessors';
|
||||||
import PROXY_PRODUCERS from './producers';
|
import PROXY_PRODUCERS from './producers';
|
||||||
import PROXY_PARSERS from './parsers';
|
import PROXY_PARSERS from './parsers';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
|
import { FILES_KEY, MODULES_KEY } from '@/constants';
|
||||||
|
import { findByName } from '@/utils/database';
|
||||||
|
import { produceArtifact } from '@/restful/sync';
|
||||||
|
|
||||||
function preprocess(raw) {
|
function preprocess(raw) {
|
||||||
for (const processor of PROXY_PREPROCESSORS) {
|
for (const processor of PROXY_PREPROCESSORS) {
|
||||||
@@ -63,7 +72,7 @@ function parse(raw) {
|
|||||||
return proxies;
|
return proxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function process(proxies, operators = [], targetPlatform, source) {
|
async function processFn(proxies, operators = [], targetPlatform, source) {
|
||||||
for (const item of operators) {
|
for (const item of operators) {
|
||||||
// process script
|
// process script
|
||||||
let script;
|
let script;
|
||||||
@@ -95,18 +104,50 @@ async function process(proxies, operators = [], targetPlatform, source) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
url = `${url.split('#')[0]}${noCache ? '#noCache' : ''}`;
|
||||||
|
const downloadUrlMatch = url.match(
|
||||||
|
/^\/api\/(file|module)\/(.+)/,
|
||||||
|
);
|
||||||
|
if (downloadUrlMatch) {
|
||||||
|
let type = '';
|
||||||
|
try {
|
||||||
|
type = downloadUrlMatch?.[1];
|
||||||
|
let name = downloadUrlMatch?.[2];
|
||||||
|
if (name == null) {
|
||||||
|
throw new Error(`本地 ${type} URL 无效: ${url}`);
|
||||||
|
}
|
||||||
|
name = decodeURIComponent(name);
|
||||||
|
const key = type === 'module' ? MODULES_KEY : FILES_KEY;
|
||||||
|
const item = findByName($.read(key), name);
|
||||||
|
if (!item) {
|
||||||
|
throw new Error(`找不到 ${type}: ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
// if this is a remote script, download it
|
if (type === 'module') {
|
||||||
try {
|
script = item.content;
|
||||||
script = await download(
|
} else {
|
||||||
`${url.split('#')[0]}${noCache ? '#noCache' : ''}`,
|
script = await produceArtifact({
|
||||||
);
|
type: 'file',
|
||||||
// $.info(`Script loaded: >>>\n ${script}`);
|
name,
|
||||||
} catch (err) {
|
});
|
||||||
$.error(
|
}
|
||||||
`Error when downloading remote script: ${item.args.content}.\n Reason: ${err}`,
|
} catch (err) {
|
||||||
);
|
$.error(
|
||||||
throw new Error(`无法下载脚本: ${url}`);
|
`Error when loading ${type}: ${item.args.content}.\n Reason: ${err}`,
|
||||||
|
);
|
||||||
|
throw new Error(`无法加载 ${type}: ${url}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if this is a remote script, download it
|
||||||
|
try {
|
||||||
|
script = await download(url);
|
||||||
|
// $.info(`Script loaded: >>>\n ${script}`);
|
||||||
|
} catch (err) {
|
||||||
|
$.error(
|
||||||
|
`Error when downloading remote script: ${item.args.content}.\n Reason: ${err}`,
|
||||||
|
);
|
||||||
|
throw new Error(`无法下载脚本: ${url}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
script = content;
|
script = content;
|
||||||
@@ -151,6 +192,13 @@ function produce(proxies, targetPlatform, type, opts = {}) {
|
|||||||
!(proxy.supported && proxy.supported[targetPlatform] === false),
|
!(proxy.supported && proxy.supported[targetPlatform] === false),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
proxies = proxies.map((proxy) => {
|
||||||
|
if (!isNotBlank(proxy.name)) {
|
||||||
|
proxy.name = `${proxy.type} ${proxy.server}:${proxy.port}`;
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
});
|
||||||
|
|
||||||
$.info(`Producing proxies for target: ${targetPlatform}`);
|
$.info(`Producing proxies for target: ${targetPlatform}`);
|
||||||
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
|
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
|
||||||
let localPort = 10000;
|
let localPort = 10000;
|
||||||
@@ -188,7 +236,7 @@ function produce(proxies, targetPlatform, type, opts = {}) {
|
|||||||
|
|
||||||
export const ProxyUtils = {
|
export const ProxyUtils = {
|
||||||
parse,
|
parse,
|
||||||
process,
|
process: processFn,
|
||||||
produce,
|
produce,
|
||||||
isIPv4,
|
isIPv4,
|
||||||
isIPv6,
|
isIPv6,
|
||||||
@@ -215,6 +263,10 @@ function safeMatch(parser, line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function lastParse(proxy) {
|
function lastParse(proxy) {
|
||||||
|
if (proxy.interface) {
|
||||||
|
proxy['interface-name'] = proxy.interface;
|
||||||
|
delete proxy.interface;
|
||||||
|
}
|
||||||
if (isValidPortNumber(proxy.port)) {
|
if (isValidPortNumber(proxy.port)) {
|
||||||
proxy.port = parseInt(proxy.port, 10);
|
proxy.port = parseInt(proxy.port, 10);
|
||||||
}
|
}
|
||||||
@@ -328,6 +380,18 @@ function lastParse(proxy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (typeof proxy.name !== 'string') {
|
||||||
|
try {
|
||||||
|
if (proxy.name?.data) {
|
||||||
|
proxy.name = Buffer.from(proxy.name.data).toString('utf8');
|
||||||
|
} else {
|
||||||
|
proxy.name = utf8ArrayToStr(proxy.name);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$.error(`proxy.name decode failed\nReason: ${e}`);
|
||||||
|
proxy.name = `${proxy.type} ${proxy.server}:${proxy.port}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,11 +273,17 @@ function URI_VMess() {
|
|||||||
params.port = port;
|
params.port = port;
|
||||||
params.add = server;
|
params.add = server;
|
||||||
}
|
}
|
||||||
|
const server = params.add;
|
||||||
|
const port = parseInt(getIfPresent(params.port), 10);
|
||||||
const proxy = {
|
const proxy = {
|
||||||
name: params.ps ?? params.remarks,
|
name:
|
||||||
|
params.ps ??
|
||||||
|
params.remarks ??
|
||||||
|
params.remark ??
|
||||||
|
`VMess ${server}:${port}`,
|
||||||
type: 'vmess',
|
type: 'vmess',
|
||||||
server: params.add,
|
server,
|
||||||
port: parseInt(getIfPresent(params.port), 10),
|
port,
|
||||||
cipher: getIfPresent(params.scy, 'auto'),
|
cipher: getIfPresent(params.scy, 'auto'),
|
||||||
uuid: params.id,
|
uuid: params.id,
|
||||||
alterId: parseInt(
|
alterId: parseInt(
|
||||||
@@ -399,14 +405,18 @@ function URI_VLESS() {
|
|||||||
params[key] = value;
|
params[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy.name = name ?? params.remarks ?? `VLESS ${server}:${port}`;
|
proxy.name =
|
||||||
|
name ??
|
||||||
|
params.remarks ??
|
||||||
|
params.remark ??
|
||||||
|
`VLESS ${server}:${port}`;
|
||||||
|
|
||||||
proxy.tls = params.security && params.security !== 'none';
|
proxy.tls = params.security && params.security !== 'none';
|
||||||
if (isShadowrocket && /TRUE|1/i.test(params.tls)) {
|
if (isShadowrocket && /TRUE|1/i.test(params.tls)) {
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
params.security = params.security ?? 'reality';
|
params.security = params.security ?? 'reality';
|
||||||
}
|
}
|
||||||
proxy.sni = params.sni ?? params.peer;
|
proxy.sni = params.sni || params.peer;
|
||||||
proxy.flow = params.flow;
|
proxy.flow = params.flow;
|
||||||
if (!proxy.flow && isShadowrocket && params.xtls) {
|
if (!proxy.flow && isShadowrocket && params.xtls) {
|
||||||
// "none" is undefined
|
// "none" is undefined
|
||||||
@@ -545,6 +555,75 @@ function URI_Hysteria2() {
|
|||||||
};
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
function URI_Hysteria() {
|
||||||
|
const name = 'URI Hysteria Parser';
|
||||||
|
const test = (line) => {
|
||||||
|
return /^(hysteria|hy):\/\//.test(line);
|
||||||
|
};
|
||||||
|
const parse = (line) => {
|
||||||
|
line = line.split(/(hysteria|hy):\/\//)[2];
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let [__, server, ___, port, ____, addons = '', name] =
|
||||||
|
/^(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line);
|
||||||
|
port = parseInt(`${port}`, 10);
|
||||||
|
if (isNaN(port)) {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
if (name != null) {
|
||||||
|
name = decodeURIComponent(name);
|
||||||
|
}
|
||||||
|
name = name ?? `Hysteria ${server}:${port}`;
|
||||||
|
|
||||||
|
const proxy = {
|
||||||
|
type: 'hysteria',
|
||||||
|
name,
|
||||||
|
server,
|
||||||
|
port,
|
||||||
|
};
|
||||||
|
const params = {};
|
||||||
|
for (const addon of addons.split('&')) {
|
||||||
|
let [key, value] = addon.split('=');
|
||||||
|
key = key.replace(/_/, '-');
|
||||||
|
value = decodeURIComponent(value);
|
||||||
|
if (['alpn'].includes(key)) {
|
||||||
|
proxy[key] = value ? value.split(',') : undefined;
|
||||||
|
} else if (['insecure'].includes(key)) {
|
||||||
|
proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value);
|
||||||
|
} else if (['auth'].includes(key)) {
|
||||||
|
proxy['auth-str'] = value;
|
||||||
|
} else if (['mport'].includes(key)) {
|
||||||
|
proxy['ports'] = value;
|
||||||
|
} else if (['obfsParam'].includes(key)) {
|
||||||
|
proxy['obfs'] = value;
|
||||||
|
} else if (['upmbps'].includes(key)) {
|
||||||
|
proxy['up'] = value;
|
||||||
|
} else if (['downmbps'].includes(key)) {
|
||||||
|
proxy['down'] = value;
|
||||||
|
} else if (['obfs'].includes(key)) {
|
||||||
|
// obfs: Obfuscation mode (optional, empty or "xplus")
|
||||||
|
proxy['_obfs'] = value || '';
|
||||||
|
} else if (['fast-open', 'peer'].includes(key)) {
|
||||||
|
params[key] = value;
|
||||||
|
} else {
|
||||||
|
proxy[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proxy.sni && params.peer) {
|
||||||
|
proxy.sni = params.peer;
|
||||||
|
}
|
||||||
|
if (!proxy['fast-open'] && params.fastopen) {
|
||||||
|
proxy['fast-open'] = true;
|
||||||
|
}
|
||||||
|
if (!proxy.protocol) {
|
||||||
|
// protocol: protocol to use ("udp", "wechat-video", "faketcp") (optional, default: "udp")
|
||||||
|
proxy.protocol = 'udp';
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
|
return { name, test, parse };
|
||||||
|
}
|
||||||
function URI_TUIC() {
|
function URI_TUIC() {
|
||||||
const name = 'URI TUIC Parser';
|
const name = 'URI TUIC Parser';
|
||||||
const test = (line) => {
|
const test = (line) => {
|
||||||
@@ -552,7 +631,6 @@ function URI_TUIC() {
|
|||||||
};
|
};
|
||||||
const parse = (line) => {
|
const parse = (line) => {
|
||||||
line = line.split(/tuic:\/\//)[1];
|
line = line.split(/tuic:\/\//)[1];
|
||||||
console.log(line);
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [__, uuid, password, server, ___, port, ____, addons = '', name] =
|
let [__, uuid, password, server, ___, port, ____, addons = '', name] =
|
||||||
/^(.*?):(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line);
|
/^(.*?):(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line);
|
||||||
@@ -674,6 +752,9 @@ function Clash_All() {
|
|||||||
if (proxy['benchmark-url']) {
|
if (proxy['benchmark-url']) {
|
||||||
proxy['test-url'] = proxy['benchmark-url'];
|
proxy['test-url'] = proxy['benchmark-url'];
|
||||||
}
|
}
|
||||||
|
if (proxy['benchmark-timeout']) {
|
||||||
|
proxy['test-timeout'] = proxy['benchmark-timeout'];
|
||||||
|
}
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
@@ -935,6 +1016,14 @@ function Loon_WireGuard() {
|
|||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Surge_SSH() {
|
||||||
|
const name = 'Surge SSH Parser';
|
||||||
|
const test = (line) => {
|
||||||
|
return /^.*=\s*ssh/.test(line.split(',')[0]);
|
||||||
|
};
|
||||||
|
const parse = (line) => getSurgeParser().parse(line);
|
||||||
|
return { name, test, parse };
|
||||||
|
}
|
||||||
function Surge_SS() {
|
function Surge_SS() {
|
||||||
const name = 'Surge SS Parser';
|
const name = 'Surge SS Parser';
|
||||||
const test = (line) => {
|
const test = (line) => {
|
||||||
@@ -1101,9 +1190,11 @@ export default [
|
|||||||
URI_VMess(),
|
URI_VMess(),
|
||||||
URI_VLESS(),
|
URI_VLESS(),
|
||||||
URI_TUIC(),
|
URI_TUIC(),
|
||||||
|
URI_Hysteria(),
|
||||||
URI_Hysteria2(),
|
URI_Hysteria2(),
|
||||||
URI_Trojan(),
|
URI_Trojan(),
|
||||||
Clash_All(),
|
Clash_All(),
|
||||||
|
Surge_SSH(),
|
||||||
Surge_SS(),
|
Surge_SS(),
|
||||||
Surge_VMess(),
|
Surge_VMess(),
|
||||||
Surge_Trojan(),
|
Surge_Trojan(),
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ const grammars = String.raw`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2) {
|
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2/ssh) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "ss";
|
proxy.type = "ss";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -52,7 +52,7 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -63,21 +63,25 @@ vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/
|
|||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
ssh = tag equals "ssh" address (username password)? (usernamek passwordk)? (server_fingerprint/idle_timeout/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
|
proxy.type = "ssh";
|
||||||
|
handleShadowTLS();
|
||||||
|
}
|
||||||
|
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "snell";
|
proxy.type = "snell";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -87,28 +91,28 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/no_error_alert/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/no_error_alert/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/test_url/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "hysteria2";
|
proxy.type = "hysteria2";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
@@ -218,6 +222,14 @@ no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-ale
|
|||||||
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
||||||
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
||||||
|
test_udp = comma "test-udp" equals match:[^,]+ { proxy["test-udp"] = match.join(""); }
|
||||||
|
test_timeout = comma "test-timeout" equals match:$[0-9]+ { proxy["test-timeout"] = parseInt(match.trim()); }
|
||||||
|
tos = comma "tos" equals match:$[0-9]+ { proxy.tos = parseInt(match.trim()); }
|
||||||
|
interface = comma "interface" equals match:[^,]+ { proxy.interface = match.join(""); }
|
||||||
|
allow_other_interface = comma "allow-other-interface" equals flag:bool { proxy["allow-other-interface"] = flag; }
|
||||||
|
hybrid = comma "hybrid" equals flag:bool { proxy.hybrid = flag; }
|
||||||
|
idle_timeout = comma "idle-timeout" equals match:$[0-9]+ { proxy["idle-timeout"] = parseInt(match.trim()); }
|
||||||
|
server_fingerprint = comma "server-fingerprint" equals match:[^,]+ { proxy["server-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); }
|
||||||
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
||||||
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
||||||
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
||||||
|
|||||||
@@ -35,11 +35,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2) {
|
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2/ssh) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "ss";
|
proxy.type = "ss";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -50,7 +50,7 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -61,21 +61,25 @@ vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/
|
|||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
http = tag equals "http" address (username password)? (usernamek passwordk)? (ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/no_error_alert/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
ssh = tag equals "ssh" address (username password)? (usernamek passwordk)? (server_fingerprint/idle_timeout/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
|
proxy.type = "ssh";
|
||||||
|
handleShadowTLS();
|
||||||
|
}
|
||||||
|
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "snell";
|
proxy.type = "snell";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -85,28 +89,28 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/no_error_alert/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/no_error_alert/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/test_url/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "hysteria2";
|
proxy.type = "hysteria2";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
@@ -216,6 +220,14 @@ no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-ale
|
|||||||
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
||||||
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
||||||
|
test_udp = comma "test-udp" equals match:[^,]+ { proxy["test-udp"] = match.join(""); }
|
||||||
|
test_timeout = comma "test-timeout" equals match:$[0-9]+ { proxy["test-timeout"] = parseInt(match.trim()); }
|
||||||
|
tos = comma "tos" equals match:$[0-9]+ { proxy.tos = parseInt(match.trim()); }
|
||||||
|
interface = comma "interface" equals match:[^,]+ { proxy.interface = match.join(""); }
|
||||||
|
allow_other_interface = comma "allow-other-interface" equals flag:bool { proxy["allow-other-interface"] = flag; }
|
||||||
|
hybrid = comma "hybrid" equals flag:bool { proxy.hybrid = flag; }
|
||||||
|
idle_timeout = comma "idle-timeout" equals match:$[0-9]+ { proxy["idle-timeout"] = parseInt(match.trim()); }
|
||||||
|
server_fingerprint = comma "server-fingerprint" equals match:[^,]+ { proxy["server-fingerprint"] = match.join("").replace(/^"(.*)"$/, '$1'); }
|
||||||
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
||||||
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
||||||
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ start = (trojan) {
|
|||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
trojan = "trojan://" password:password "@" server:server ":" port:port params? name:name?{
|
trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
proxy.password = password;
|
proxy.password = password;
|
||||||
proxy.server = server;
|
proxy.server = server;
|
||||||
@@ -79,7 +79,7 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params = "/"? "?" head:param tail:("&"@param)* {
|
params = "?" head:param tail:("&"@param)* {
|
||||||
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
||||||
proxy.sni = params["sni"] || params["peer"];
|
proxy.sni = params["sni"] || params["peer"];
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ start = (trojan) {
|
|||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
trojan = "trojan://" password:password "@" server:server ":" port:port params? name:name?{
|
trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
proxy.password = password;
|
proxy.password = password;
|
||||||
proxy.server = server;
|
proxy.server = server;
|
||||||
@@ -77,7 +77,7 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params = "/"? "?" head:param tail:("&"@param)* {
|
params = "?" head:param tail:("&"@param)* {
|
||||||
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
||||||
proxy.sni = params["sni"] || params["peer"];
|
proxy.sni = params["sni"] || params["peer"];
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ function QuickSettingOperator(args) {
|
|||||||
if (get(args.useless)) {
|
if (get(args.useless)) {
|
||||||
const filter = UselessFilter();
|
const filter = UselessFilter();
|
||||||
const selected = filter.func(proxies);
|
const selected = filter.func(proxies);
|
||||||
proxies.filter((_, i) => selected[i]);
|
proxies = proxies.filter(
|
||||||
|
(p, i) => selected[i] && p.port > 0 && p.port <= 65535,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return proxies.map((proxy) => {
|
return proxies.map((proxy) => {
|
||||||
@@ -119,7 +121,7 @@ function QuickSettingOperator(args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add or remove flag for proxies
|
// add or remove flag for proxies
|
||||||
function FlagOperator({ mode }) {
|
function FlagOperator({ mode, tw }) {
|
||||||
return {
|
return {
|
||||||
name: 'Flag Operator',
|
name: 'Flag Operator',
|
||||||
func: (proxies) => {
|
func: (proxies) => {
|
||||||
@@ -133,7 +135,13 @@ function FlagOperator({ mode }) {
|
|||||||
// remove old flag
|
// remove old flag
|
||||||
proxy.name = removeFlag(proxy.name);
|
proxy.name = removeFlag(proxy.name);
|
||||||
proxy.name = newFlag + ' ' + proxy.name;
|
proxy.name = newFlag + ' ' + proxy.name;
|
||||||
proxy.name = proxy.name.replace(/🇹🇼/g, '🇨🇳');
|
if (tw == 'ws') {
|
||||||
|
proxy.name = proxy.name.replace(/🇹🇼/g, '🇼🇸');
|
||||||
|
} else if (tw == 'tw') {
|
||||||
|
// 不变
|
||||||
|
} else {
|
||||||
|
proxy.name = proxy.name.replace(/🇹🇼/g, '🇨🇳');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
});
|
});
|
||||||
@@ -511,7 +519,7 @@ function ResolveDomainOperator({ provider, type, filter }) {
|
|||||||
|
|
||||||
return proxies.filter((p) => {
|
return proxies.filter((p) => {
|
||||||
if (filter === 'removeFailed') {
|
if (filter === 'removeFailed') {
|
||||||
return p['no-resolve'] || p.resolved;
|
return isIP(p.server) || p['no-resolve'] || p.resolved;
|
||||||
} else if (filter === 'IPOnly') {
|
} else if (filter === 'IPOnly') {
|
||||||
return isIP(p.server);
|
return isIP(p.server);
|
||||||
} else if (filter === 'IPv4Only') {
|
} else if (filter === 'IPv4Only') {
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ function shadowsocks(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
@@ -109,7 +111,9 @@ function shadowsocksr(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
@@ -152,7 +156,9 @@ function trojan(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
@@ -219,7 +225,9 @@ function vmess(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +289,9 @@ function vless(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,8 +314,6 @@ function http(proxy) {
|
|||||||
// tfo
|
// tfo
|
||||||
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
|
||||||
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +344,11 @@ function wireguard(proxy) {
|
|||||||
if (proxy.dns) {
|
if (proxy.dns) {
|
||||||
if (Array.isArray(proxy.dns)) {
|
if (Array.isArray(proxy.dns)) {
|
||||||
proxy.dnsv6 = proxy.dns.find((i) => isIPv6(i));
|
proxy.dnsv6 = proxy.dns.find((i) => isIPv6(i));
|
||||||
proxy.dns = proxy.dns.find((i) => isIPv4(i));
|
let dns = proxy.dns.find((i) => isIPv4(i));
|
||||||
|
if (!dns) {
|
||||||
|
dns = proxy.dns.find((i) => !isIPv4(i) && !isIPv6(i));
|
||||||
|
}
|
||||||
|
proxy.dns = dns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.appendIfPresent(`,dns=${proxy.dns}`, 'dns');
|
result.appendIfPresent(`,dns=${proxy.dns}`, 'dns');
|
||||||
@@ -390,7 +402,9 @@ function hysteria2(proxy) {
|
|||||||
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
result.appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
// udp
|
// udp
|
||||||
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
if (proxy.udp) {
|
||||||
|
result.append(`,udp=true`);
|
||||||
|
}
|
||||||
|
|
||||||
// download-bandwidth
|
// download-bandwidth
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
|
|||||||
@@ -178,8 +178,8 @@ const grpcParser = (proxy, parsedProxy) => {
|
|||||||
const transport = { type: 'grpc' };
|
const transport = { type: 'grpc' };
|
||||||
if (proxy['grpc-opts']) {
|
if (proxy['grpc-opts']) {
|
||||||
const serviceName = proxy['grpc-opts']['grpc-service-name'];
|
const serviceName = proxy['grpc-opts']['grpc-service-name'];
|
||||||
if (serviceName && serviceName !== '')
|
if (serviceName != null && serviceName !== '')
|
||||||
transport.service_name = serviceName;
|
transport.service_name = `${serviceName}`;
|
||||||
}
|
}
|
||||||
parsedProxy.transport = transport;
|
parsedProxy.transport = transport;
|
||||||
};
|
};
|
||||||
@@ -217,6 +217,31 @@ const tlsParser = (proxy, parsedProxy) => {
|
|||||||
if (!parsedProxy.tls.enabled) delete parsedProxy.tls;
|
if (!parsedProxy.tls.enabled) delete parsedProxy.tls;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sshParser = (proxy = {}) => {
|
||||||
|
const parsedProxy = {
|
||||||
|
tag: proxy.name,
|
||||||
|
type: 'ssh',
|
||||||
|
server: proxy.server,
|
||||||
|
server_port: parseInt(`${proxy.port}`, 10),
|
||||||
|
};
|
||||||
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
|
throw 'invalid port';
|
||||||
|
if (proxy.username) parsedProxy.user = proxy.username;
|
||||||
|
if (proxy.password) parsedProxy.password = proxy.password;
|
||||||
|
if (proxy['server-fingerprint']) {
|
||||||
|
parsedProxy.host_key = [proxy['server-fingerprint']];
|
||||||
|
// https://manual.nssurge.com/policy/ssh.html
|
||||||
|
// Surge only supports curve25519-sha256 as the kex algorithm and aes128-gcm as the encryption algorithm. It means that the SSH server must use OpenSSH v7.3 or above. (It should not be a problem since OpenSSH 7.3 was released on 2016-08-01.)
|
||||||
|
// TODO: ?
|
||||||
|
parsedProxy.host_key_algorithms = [
|
||||||
|
proxy['server-fingerprint'].split(' ')[0],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
|
tfoParser(proxy, parsedProxy);
|
||||||
|
return parsedProxy;
|
||||||
|
};
|
||||||
|
|
||||||
const httpParser = (proxy = {}) => {
|
const httpParser = (proxy = {}) => {
|
||||||
const parsedProxy = {
|
const parsedProxy = {
|
||||||
tag: proxy.name,
|
tag: proxy.name,
|
||||||
@@ -225,7 +250,7 @@ const httpParser = (proxy = {}) => {
|
|||||||
server_port: parseInt(`${proxy.port}`, 10),
|
server_port: parseInt(`${proxy.port}`, 10),
|
||||||
tls: { enabled: false, server_name: proxy.server, insecure: false },
|
tls: { enabled: false, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.username) parsedProxy.username = proxy.username;
|
if (proxy.username) parsedProxy.username = proxy.username;
|
||||||
if (proxy.password) parsedProxy.password = proxy.password;
|
if (proxy.password) parsedProxy.password = proxy.password;
|
||||||
@@ -252,7 +277,7 @@ const socks5Parser = (proxy = {}) => {
|
|||||||
password: proxy.password,
|
password: proxy.password,
|
||||||
version: '5',
|
version: '5',
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.username) parsedProxy.username = proxy.username;
|
if (proxy.username) parsedProxy.username = proxy.username;
|
||||||
if (proxy.password) parsedProxy.password = proxy.password;
|
if (proxy.password) parsedProxy.password = proxy.password;
|
||||||
@@ -287,7 +312,7 @@ const shadowTLSParser = (proxy = {}) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (stPart.server_port < 1 || stPart.server_port > 65535)
|
if (stPart.server_port < 0 || stPart.server_port > 65535)
|
||||||
throw '端口值非法';
|
throw '端口值非法';
|
||||||
if (proxy['fast-open'] === true) stPart.udp_fragment = true;
|
if (proxy['fast-open'] === true) stPart.udp_fragment = true;
|
||||||
tfoParser(proxy, stPart);
|
tfoParser(proxy, stPart);
|
||||||
@@ -303,7 +328,7 @@ const ssParser = (proxy = {}) => {
|
|||||||
method: proxy.cipher,
|
method: proxy.cipher,
|
||||||
password: proxy.password,
|
password: proxy.password,
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.uot) parsedProxy.udp_over_tcp = true;
|
if (proxy.uot) parsedProxy.udp_over_tcp = true;
|
||||||
if (proxy['udp-over-tcp']) parsedProxy.udp_over_tcp = true;
|
if (proxy['udp-over-tcp']) parsedProxy.udp_over_tcp = true;
|
||||||
@@ -379,7 +404,7 @@ const ssrParser = (proxy = {}) => {
|
|||||||
obfs: proxy.obfs,
|
obfs: proxy.obfs,
|
||||||
protocol: proxy.protocol,
|
protocol: proxy.protocol,
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy['obfs-param']) parsedProxy.obfs_param = proxy['obfs-param'];
|
if (proxy['obfs-param']) parsedProxy.obfs_param = proxy['obfs-param'];
|
||||||
if (proxy['protocol-param'] && proxy['protocol-param'] !== '')
|
if (proxy['protocol-param'] && proxy['protocol-param'] !== '')
|
||||||
@@ -412,7 +437,7 @@ const vmessParser = (proxy = {}) => {
|
|||||||
].indexOf(parsedProxy.security) === -1
|
].indexOf(parsedProxy.security) === -1
|
||||||
)
|
)
|
||||||
parsedProxy.security = 'auto';
|
parsedProxy.security = 'auto';
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.xudp) parsedProxy.packet_encoding = 'xudp';
|
if (proxy.xudp) parsedProxy.packet_encoding = 'xudp';
|
||||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
@@ -436,7 +461,7 @@ const vlessParser = (proxy = {}) => {
|
|||||||
uuid: proxy.uuid,
|
uuid: proxy.uuid,
|
||||||
tls: { enabled: false, server_name: proxy.server, insecure: false },
|
tls: { enabled: false, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
if (proxy.flow === 'xtls-rprx-vision') parsedProxy.flow = proxy.flow;
|
if (proxy.flow === 'xtls-rprx-vision') parsedProxy.flow = proxy.flow;
|
||||||
@@ -457,7 +482,7 @@ const trojanParser = (proxy = {}) => {
|
|||||||
password: proxy.password,
|
password: proxy.password,
|
||||||
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy);
|
if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy);
|
||||||
@@ -477,7 +502,7 @@ const hysteriaParser = (proxy = {}) => {
|
|||||||
disable_mtu_discovery: false,
|
disable_mtu_discovery: false,
|
||||||
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.auth_str) parsedProxy.auth_str = `${proxy.auth_str}`;
|
if (proxy.auth_str) parsedProxy.auth_str = `${proxy.auth_str}`;
|
||||||
if (proxy['auth-str']) parsedProxy.auth_str = `${proxy['auth-str']}`;
|
if (proxy['auth-str']) parsedProxy.auth_str = `${proxy['auth-str']}`;
|
||||||
@@ -524,7 +549,7 @@ const hysteria2Parser = (proxy = {}) => {
|
|||||||
obfs: {},
|
obfs: {},
|
||||||
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy.up) parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10);
|
if (proxy.up) parsedProxy.up_mbps = parseInt(`${proxy.up}`, 10);
|
||||||
if (proxy.down) parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10);
|
if (proxy.down) parsedProxy.down_mbps = parseInt(`${proxy.down}`, 10);
|
||||||
@@ -547,7 +572,7 @@ const tuic5Parser = (proxy = {}) => {
|
|||||||
password: proxy.password,
|
password: proxy.password,
|
||||||
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
tls: { enabled: true, server_name: proxy.server, insecure: false },
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
if (
|
if (
|
||||||
@@ -583,13 +608,15 @@ const wireguardParser = (proxy = {}) => {
|
|||||||
pre_shared_key: proxy['pre-shared-key'],
|
pre_shared_key: proxy['pre-shared-key'],
|
||||||
reserved: [],
|
reserved: [],
|
||||||
};
|
};
|
||||||
if (parsedProxy.server_port < 1 || parsedProxy.server_port > 65535)
|
if (parsedProxy.server_port < 0 || parsedProxy.server_port > 65535)
|
||||||
throw 'invalid port';
|
throw 'invalid port';
|
||||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||||
if (typeof proxy.reserved === 'string') {
|
if (typeof proxy.reserved === 'string') {
|
||||||
parsedProxy.reserved.push(proxy.reserved);
|
parsedProxy.reserved.push(proxy.reserved);
|
||||||
} else {
|
} else if (Array.isArray(proxy.reserved)) {
|
||||||
for (const r of proxy.reserved) parsedProxy.reserved.push(r);
|
for (const r of proxy.reserved) parsedProxy.reserved.push(r);
|
||||||
|
} else {
|
||||||
|
delete parsedProxy.reserved;
|
||||||
}
|
}
|
||||||
if (proxy.peers && proxy.peers.length > 0) {
|
if (proxy.peers && proxy.peers.length > 0) {
|
||||||
parsedProxy.peers = [];
|
parsedProxy.peers = [];
|
||||||
@@ -603,8 +630,10 @@ const wireguardParser = (proxy = {}) => {
|
|||||||
};
|
};
|
||||||
if (typeof p.reserved === 'string') {
|
if (typeof p.reserved === 'string') {
|
||||||
peer.reserved.push(p.reserved);
|
peer.reserved.push(p.reserved);
|
||||||
} else {
|
} else if (Array.isArray(p.reserved)) {
|
||||||
for (const r of p.reserved) peer.reserved.push(r);
|
for (const r of p.reserved) peer.reserved.push(r);
|
||||||
|
} else {
|
||||||
|
delete peer.reserved;
|
||||||
}
|
}
|
||||||
if (p['pre-shared-key']) peer.pre_shared_key = p['pre-shared-key'];
|
if (p['pre-shared-key']) peer.pre_shared_key = p['pre-shared-key'];
|
||||||
parsedProxy.peers.push(peer);
|
parsedProxy.peers.push(peer);
|
||||||
@@ -624,6 +653,9 @@ export default function singbox_Producer() {
|
|||||||
.map((proxy) => {
|
.map((proxy) => {
|
||||||
try {
|
try {
|
||||||
switch (proxy.type) {
|
switch (proxy.type) {
|
||||||
|
case 'ssh':
|
||||||
|
list.push(sshParser(proxy));
|
||||||
|
break;
|
||||||
case 'http':
|
case 'http':
|
||||||
list.push(httpParser(proxy));
|
list.push(httpParser(proxy));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -250,6 +250,10 @@ export default function Stash_Producer() {
|
|||||||
proxy['benchmark-url'] = proxy['test-url'];
|
proxy['benchmark-url'] = proxy['test-url'];
|
||||||
delete proxy['test-url'];
|
delete proxy['test-url'];
|
||||||
}
|
}
|
||||||
|
if (proxy['test-timeout']) {
|
||||||
|
proxy['benchmark-timeout'] = proxy['test-timeout'];
|
||||||
|
delete proxy['test-timeout'];
|
||||||
|
}
|
||||||
|
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Result, isPresent } from './utils';
|
import { Result, isPresent } from './utils';
|
||||||
import { isNotBlank } from '@/utils';
|
import { isNotBlank, getIfNotBlank } from '@/utils';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
|
|
||||||
const targetPlatform = 'Surge';
|
const targetPlatform = 'Surge';
|
||||||
@@ -13,7 +13,7 @@ const ipVersions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function Surge_Producer() {
|
export default function Surge_Producer() {
|
||||||
const produce = (proxy) => {
|
const produce = (proxy, type, opts = {}) => {
|
||||||
switch (proxy.type) {
|
switch (proxy.type) {
|
||||||
case 'ss':
|
case 'ss':
|
||||||
return shadowsocks(proxy);
|
return shadowsocks(proxy);
|
||||||
@@ -30,9 +30,15 @@ export default function Surge_Producer() {
|
|||||||
case 'tuic':
|
case 'tuic':
|
||||||
return tuic(proxy);
|
return tuic(proxy);
|
||||||
case 'wireguard-surge':
|
case 'wireguard-surge':
|
||||||
return wireguard(proxy);
|
return wireguard_surge(proxy);
|
||||||
case 'hysteria2':
|
case 'hysteria2':
|
||||||
return hysteria2(proxy);
|
return hysteria2(proxy);
|
||||||
|
case 'ssh':
|
||||||
|
return ssh(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts['include-unsupported-proxy'] && proxy.type === 'wireguard') {
|
||||||
|
return wireguard(proxy);
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
||||||
@@ -82,10 +88,8 @@ function shadowsocks(proxy) {
|
|||||||
result.append(`,encrypt-method=${proxy.cipher}`);
|
result.append(`,encrypt-method=${proxy.cipher}`);
|
||||||
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -117,6 +121,21 @@ function shadowsocks(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -167,10 +186,8 @@ function trojan(proxy) {
|
|||||||
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
||||||
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -204,6 +221,21 @@ function trojan(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -236,10 +268,8 @@ function vmess(proxy) {
|
|||||||
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
||||||
result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid');
|
result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -280,6 +310,21 @@ function vmess(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -307,6 +352,64 @@ function vmess(proxy) {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ssh(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=ssh,${proxy.server},${proxy.port}`);
|
||||||
|
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||||
|
result.appendIfPresent(`,${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,idle-timeout=${proxy['idle-timeout']}`,
|
||||||
|
'idle-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server-fingerprint="${proxy['server-fingerprint']}"`,
|
||||||
|
'server-fingerprint',
|
||||||
|
);
|
||||||
|
|
||||||
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
|
'no-error-alert',
|
||||||
|
);
|
||||||
|
|
||||||
|
// tfo
|
||||||
|
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// test-url
|
||||||
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
|
// underlying-proxy
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
|
'underlying-proxy',
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
function http(proxy) {
|
function http(proxy) {
|
||||||
const result = new Result(proxy);
|
const result = new Result(proxy);
|
||||||
const type = proxy.tls ? 'https' : 'http';
|
const type = proxy.tls ? 'https' : 'http';
|
||||||
@@ -314,10 +417,8 @@ function http(proxy) {
|
|||||||
result.appendIfPresent(`,${proxy.username}`, 'username');
|
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||||
result.appendIfPresent(`,${proxy.password}`, 'password');
|
result.appendIfPresent(`,${proxy.password}`, 'password');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -345,6 +446,21 @@ function http(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -379,10 +495,8 @@ function socks5(proxy) {
|
|||||||
result.appendIfPresent(`,${proxy.username}`, 'username');
|
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||||
result.appendIfPresent(`,${proxy.password}`, 'password');
|
result.appendIfPresent(`,${proxy.password}`, 'password');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -412,6 +526,21 @@ function socks5(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -445,10 +574,8 @@ function snell(proxy) {
|
|||||||
result.appendIfPresent(`,version=${proxy.version}`, 'version');
|
result.appendIfPresent(`,version=${proxy.version}`, 'version');
|
||||||
result.appendIfPresent(`,psk=${proxy.psk}`, 'psk');
|
result.appendIfPresent(`,psk=${proxy.psk}`, 'psk');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -477,6 +604,21 @@ function snell(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -525,10 +667,8 @@ function tuic(proxy) {
|
|||||||
'alpn',
|
'alpn',
|
||||||
);
|
);
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -557,6 +697,21 @@ function tuic(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -587,6 +742,122 @@ function tuic(proxy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function wireguard(proxy) {
|
function wireguard(proxy) {
|
||||||
|
if (Array.isArray(proxy.peers) && proxy.peers.length > 0) {
|
||||||
|
proxy.server = proxy.peers[0].server;
|
||||||
|
proxy.port = proxy.peers[0].port;
|
||||||
|
proxy.ip = proxy.peers[0].ip;
|
||||||
|
proxy.ipv6 = proxy.peers[0].ipv6;
|
||||||
|
proxy['public-key'] = proxy.peers[0]['public-key'];
|
||||||
|
proxy['preshared-key'] = proxy.peers[0]['pre-shared-key'];
|
||||||
|
// https://github.com/MetaCubeX/mihomo/blob/0404e35be8736b695eae018a08debb175c1f96e6/docs/config.yaml#L717
|
||||||
|
proxy['allowed-ips'] = proxy.peers[0]['allowed-ips'];
|
||||||
|
proxy.reserved = proxy.peers[0].reserved;
|
||||||
|
}
|
||||||
|
const result = new Result(proxy);
|
||||||
|
|
||||||
|
result.append(`# WireGuard Proxy ${proxy.name}
|
||||||
|
${proxy.name}=wireguard`);
|
||||||
|
|
||||||
|
proxy['section-name'] = getIfNotBlank(proxy['section-name'], proxy.name);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,section-name=${proxy['section-name']}`,
|
||||||
|
'section-name',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
|
'no-error-alert',
|
||||||
|
);
|
||||||
|
|
||||||
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
|
// test-url
|
||||||
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
|
// underlying-proxy
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
|
'underlying-proxy',
|
||||||
|
);
|
||||||
|
|
||||||
|
result.append(`
|
||||||
|
# WireGuard Section ${proxy.name}
|
||||||
|
[WireGuard ${proxy['section-name']}]
|
||||||
|
private-key = ${proxy['private-key']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(`\nself-ip = ${proxy.ip}`, 'ip');
|
||||||
|
result.appendIfPresent(`\nself-ip-v6 = ${proxy.ipv6}`, 'ipv6');
|
||||||
|
if (proxy.dns) {
|
||||||
|
if (Array.isArray(proxy.dns)) {
|
||||||
|
proxy.dns = proxy.dns.join(', ');
|
||||||
|
}
|
||||||
|
result.append(`\ndns-server = ${proxy.dns}`);
|
||||||
|
}
|
||||||
|
result.appendIfPresent(`\nmtu = ${proxy.mtu}`, 'mtu');
|
||||||
|
|
||||||
|
if (ip_version === 'prefer-v6') {
|
||||||
|
result.append(`\nprefer-ipv6 = true`);
|
||||||
|
}
|
||||||
|
const allowedIps = Array.isArray(proxy['allowed-ips'])
|
||||||
|
? proxy['allowed-ips'].join(',')
|
||||||
|
: proxy['allowed-ips'];
|
||||||
|
let reserved = Array.isArray(proxy.reserved)
|
||||||
|
? proxy.reserved.join('/')
|
||||||
|
: proxy.reserved;
|
||||||
|
let presharedKey = proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
|
if (presharedKey) {
|
||||||
|
presharedKey = `,preshared-key="${presharedKey}"`;
|
||||||
|
}
|
||||||
|
const peer = {
|
||||||
|
'public-key': proxy['public-key'],
|
||||||
|
'allowed-ips': allowedIps,
|
||||||
|
endpoint: `${proxy.server}:${proxy.port}`,
|
||||||
|
keepalive: proxy['persistent-keepalive'] || proxy.keepalive,
|
||||||
|
'client-id': reserved,
|
||||||
|
'preshared-key': presharedKey,
|
||||||
|
};
|
||||||
|
result.append(
|
||||||
|
`\npeer = (${Object.keys(peer)
|
||||||
|
.filter((k) => peer[k] != null)
|
||||||
|
.map((k) => `${k} = ${peer[k]}`)
|
||||||
|
.join(', ')})`,
|
||||||
|
);
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
function wireguard_surge(proxy) {
|
||||||
const result = new Result(proxy);
|
const result = new Result(proxy);
|
||||||
|
|
||||||
result.append(`${proxy.name}=wireguard`);
|
result.append(`${proxy.name}=wireguard`);
|
||||||
@@ -600,13 +871,26 @@ function wireguard(proxy) {
|
|||||||
'no-error-alert',
|
'no-error-alert',
|
||||||
);
|
);
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
@@ -643,10 +927,8 @@ function hysteria2(proxy) {
|
|||||||
|
|
||||||
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
result.appendIfPresent(
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
'ip-version',
|
|
||||||
);
|
|
||||||
|
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,no-error-alert=${proxy['no-error-alert']}`,
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
@@ -673,6 +955,21 @@ function hysteria2(proxy) {
|
|||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,test-timeout=${proxy['test-timeout']}`,
|
||||||
|
'test-timeout',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(`,test-udp=${proxy['test-udp']}`, 'test-udp');
|
||||||
|
result.appendIfPresent(`,hybrid=${proxy['hybrid']}`, 'hybrid');
|
||||||
|
result.appendIfPresent(`,tos=${proxy['tos']}`, 'tos');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||||
|
'allow-other-interface',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,interface=${proxy['interface-name']}`,
|
||||||
|
'interface-name',
|
||||||
|
);
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ export default function URI_Producer() {
|
|||||||
const type = 'SINGLE';
|
const type = 'SINGLE';
|
||||||
const produce = (proxy) => {
|
const produce = (proxy) => {
|
||||||
let result = '';
|
let result = '';
|
||||||
|
delete proxy.subName;
|
||||||
|
delete proxy.collectionName;
|
||||||
|
if (['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(proxy.type)) {
|
||||||
|
delete proxy.tls;
|
||||||
|
}
|
||||||
if (proxy.server && isIPv6(proxy.server)) {
|
if (proxy.server && isIPv6(proxy.server)) {
|
||||||
proxy.server = `[${proxy.server}]`;
|
proxy.server = `[${proxy.server}]`;
|
||||||
}
|
}
|
||||||
@@ -197,9 +202,9 @@ export default function URI_Producer() {
|
|||||||
|
|
||||||
result = `vless://${proxy.uuid}@${proxy.server}:${
|
result = `vless://${proxy.uuid}@${proxy.server}:${
|
||||||
proxy.port
|
proxy.port
|
||||||
}?${vlessTransport}&security=${encodeURIComponent(
|
}?security=${encodeURIComponent(
|
||||||
security,
|
security,
|
||||||
)}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${pbk}#${encodeURIComponent(
|
)}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${pbk}#${encodeURIComponent(
|
||||||
proxy.name,
|
proxy.name,
|
||||||
)}`;
|
)}`;
|
||||||
break;
|
break;
|
||||||
@@ -285,6 +290,61 @@ export default function URI_Producer() {
|
|||||||
'&',
|
'&',
|
||||||
)}#${encodeURIComponent(proxy.name)}`;
|
)}#${encodeURIComponent(proxy.name)}`;
|
||||||
break;
|
break;
|
||||||
|
case 'hysteria':
|
||||||
|
let hysteriaParams = [];
|
||||||
|
Object.keys(proxy).forEach((key) => {
|
||||||
|
if (!['name', 'type', 'server', 'port'].includes(key)) {
|
||||||
|
const i = key.replace(/-/, '_');
|
||||||
|
if (['alpn'].includes(key)) {
|
||||||
|
if (proxy[key]) {
|
||||||
|
hysteriaParams.push(
|
||||||
|
`${i}=${encodeURIComponent(
|
||||||
|
Array.isArray(proxy[key])
|
||||||
|
? proxy[key][0]
|
||||||
|
: proxy[key],
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (['skip-cert-verify'].includes(key)) {
|
||||||
|
if (proxy[key]) {
|
||||||
|
hysteriaParams.push(`insecure=1`);
|
||||||
|
}
|
||||||
|
} else if (['tfo', 'fast-open'].includes(key)) {
|
||||||
|
if (
|
||||||
|
proxy[key] &&
|
||||||
|
!hysteriaParams.includes('fastopen=1')
|
||||||
|
) {
|
||||||
|
hysteriaParams.push(`fastopen=1`);
|
||||||
|
}
|
||||||
|
} else if (['ports'].includes(key)) {
|
||||||
|
hysteriaParams.push(`mport=${proxy[key]}`);
|
||||||
|
} else if (['auth-str'].includes(key)) {
|
||||||
|
hysteriaParams.push(`auth=${proxy[key]}`);
|
||||||
|
} else if (['up'].includes(key)) {
|
||||||
|
hysteriaParams.push(`upmbps=${proxy[key]}`);
|
||||||
|
} else if (['down'].includes(key)) {
|
||||||
|
hysteriaParams.push(`downmbps=${proxy[key]}`);
|
||||||
|
} else if (['_obfs'].includes(key)) {
|
||||||
|
hysteriaParams.push(`obfs=${proxy[key]}`);
|
||||||
|
} else if (['obfs'].includes(key)) {
|
||||||
|
hysteriaParams.push(`obfsParam=${proxy[key]}`);
|
||||||
|
} else if (['sni'].includes(key)) {
|
||||||
|
hysteriaParams.push(`peer=${proxy[key]}`);
|
||||||
|
} else if (proxy[key]) {
|
||||||
|
hysteriaParams.push(
|
||||||
|
`${i}=${encodeURIComponent(proxy[key])}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
result = `hysteria://${proxy.server}:${
|
||||||
|
proxy.port
|
||||||
|
}?${hysteriaParams.join('&')}#${encodeURIComponent(
|
||||||
|
proxy.name,
|
||||||
|
)}`;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'tuic':
|
case 'tuic':
|
||||||
if (!proxy.token || proxy.token.length === 0) {
|
if (!proxy.token || proxy.token.length === 0) {
|
||||||
let tuicParams = [];
|
let tuicParams = [];
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const RULE_TYPES_MAPPING = [
|
|||||||
[/^(IN|SRC)-PORT$/, 'IN-PORT'],
|
[/^(IN|SRC)-PORT$/, 'IN-PORT'],
|
||||||
[/^PROTOCOL$/, 'PROTOCOL'],
|
[/^PROTOCOL$/, 'PROTOCOL'],
|
||||||
[/^IP-CIDR$/i, 'IP-CIDR'],
|
[/^IP-CIDR$/i, 'IP-CIDR'],
|
||||||
[/^(IP-CIDR6|ip6-cidr|IP6-CIDR)$/],
|
[/^(IP-CIDR6|ip6-cidr|IP6-CIDR)$/, 'IP-CIDR6'],
|
||||||
];
|
];
|
||||||
|
|
||||||
function AllRuleParser() {
|
function AllRuleParser() {
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ function SurgeRuleSet() {
|
|||||||
const type = 'SINGLE';
|
const type = 'SINGLE';
|
||||||
const func = (rule) => {
|
const func = (rule) => {
|
||||||
let output = `${rule.type},${rule.content}`;
|
let output = `${rule.type},${rule.content}`;
|
||||||
if (rule.type === 'IP-CIDR' || rule.type === 'IP-CIDR6') {
|
if (['IP-CIDR', 'IP-CIDR6'].includes(rule.type)) {
|
||||||
output += rule.options ? `,${rule.options[0]}` : '';
|
output +=
|
||||||
|
rule.options?.length > 0 ? `,${rule.options.join(',')}` : '';
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
@@ -44,6 +45,12 @@ function LoonRules() {
|
|||||||
// skip unsupported rules
|
// skip unsupported rules
|
||||||
const UNSUPPORTED = ['DEST-PORT', 'SRC-IP', 'IN-PORT', 'PROTOCOL'];
|
const UNSUPPORTED = ['DEST-PORT', 'SRC-IP', 'IN-PORT', 'PROTOCOL'];
|
||||||
if (UNSUPPORTED.indexOf(rule.type) !== -1) return null;
|
if (UNSUPPORTED.indexOf(rule.type) !== -1) return null;
|
||||||
|
if (['IP-CIDR', 'IP-CIDR6'].includes(rule.type) && rule.options) {
|
||||||
|
// Loon only supports the no-resolve option
|
||||||
|
rule.options = rule.options.filter((option) =>
|
||||||
|
['no-resolve'].includes(option),
|
||||||
|
);
|
||||||
|
}
|
||||||
return SurgeRuleSet().func(rule);
|
return SurgeRuleSet().func(rule);
|
||||||
};
|
};
|
||||||
return { type, func };
|
return { type, func };
|
||||||
@@ -62,8 +69,17 @@ function ClashRuleProvider() {
|
|||||||
let output = `${TRANSFORM[rule.type] || rule.type},${
|
let output = `${TRANSFORM[rule.type] || rule.type},${
|
||||||
rule.content
|
rule.content
|
||||||
}`;
|
}`;
|
||||||
if (rule.type === 'IP-CIDR' || rule.type === 'IP-CIDR6') {
|
if (['IP-CIDR', 'IP-CIDR6'].includes(rule.type)) {
|
||||||
output += rule.options ? `,${rule.options[0]}` : '';
|
if (rule.options) {
|
||||||
|
// Clash only supports the no-resolve option
|
||||||
|
rule.options = rule.options.filter((option) =>
|
||||||
|
['no-resolve'].includes(option),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
output +=
|
||||||
|
rule.options?.length > 0
|
||||||
|
? `,${rule.options.join(',')}`
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { version } from '../../package.json';
|
import { version } from '../../package.json';
|
||||||
import { SETTINGS_KEY, ARTIFACTS_KEY } from '@/constants';
|
import {
|
||||||
|
SETTINGS_KEY,
|
||||||
|
ARTIFACTS_KEY,
|
||||||
|
SUBS_KEY,
|
||||||
|
COLLECTIONS_KEY,
|
||||||
|
} from '@/constants';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
import { produceArtifact } from '@/restful/sync';
|
import { produceArtifact } from '@/restful/sync';
|
||||||
import { syncToGist } from '@/restful/artifacts';
|
import { syncToGist } from '@/restful/artifacts';
|
||||||
|
import { findByName } from '@/utils/database';
|
||||||
|
|
||||||
!(async function () {
|
!(async function () {
|
||||||
const settings = $.read(SETTINGS_KEY);
|
const settings = $.read(SETTINGS_KEY);
|
||||||
@@ -30,23 +36,83 @@ async function doSync() {
|
|||||||
const files = {};
|
const files = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const invalid = [];
|
||||||
|
const allSubs = $.read(SUBS_KEY);
|
||||||
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
|
const subNames = [];
|
||||||
|
allArtifacts.map((artifact) => {
|
||||||
|
if (artifact.sync && artifact.source) {
|
||||||
|
if (artifact.type === 'subscription') {
|
||||||
|
const subName = artifact.source;
|
||||||
|
const sub = findByName(allSubs, subName);
|
||||||
|
if (sub && sub.url && !subNames.includes(subName)) {
|
||||||
|
subNames.push(subName);
|
||||||
|
}
|
||||||
|
} else if (artifact.type === 'collection') {
|
||||||
|
const collection = findByName(allCols, artifact.source);
|
||||||
|
if (collection && Array.isArray(collection.subscriptions)) {
|
||||||
|
collection.subscriptions.map((subName) => {
|
||||||
|
const sub = findByName(allSubs, subName);
|
||||||
|
if (sub && sub.url && !subNames.includes(subName)) {
|
||||||
|
subNames.push(subName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (subNames.length > 0) {
|
||||||
|
await Promise.all(
|
||||||
|
subNames.map(async (subName) => {
|
||||||
|
try {
|
||||||
|
await produceArtifact({
|
||||||
|
type: 'subscription',
|
||||||
|
name: subName,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// $.error(`${e.message ?? e}`);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
allArtifacts.map(async (artifact) => {
|
allArtifacts.map(async (artifact) => {
|
||||||
if (artifact.sync) {
|
try {
|
||||||
$.info(`正在同步云配置:${artifact.name}...`);
|
if (artifact.sync && artifact.source) {
|
||||||
const output = await produceArtifact({
|
$.info(`正在同步云配置:${artifact.name}...`);
|
||||||
type: artifact.type,
|
const output = await produceArtifact({
|
||||||
name: artifact.source,
|
type: artifact.type,
|
||||||
platform: artifact.platform,
|
name: artifact.source,
|
||||||
});
|
platform: artifact.platform,
|
||||||
|
produceOpts: {
|
||||||
|
'include-unsupported-proxy':
|
||||||
|
artifact.includeUnsupportedProxy,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
files[encodeURIComponent(artifact.name)] = {
|
// if (!output || output.length === 0)
|
||||||
content: output,
|
// throw new Error('该配置的结果为空 不进行上传');
|
||||||
};
|
|
||||||
|
files[encodeURIComponent(artifact.name)] = {
|
||||||
|
content: output,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`同步配置 ${artifact.name} 发生错误: ${e.message ?? e}`,
|
||||||
|
);
|
||||||
|
invalid.push(artifact.name);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (invalid.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`同步配置 ${invalid.join(', ')} 发生错误 详情请查看日志`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const resp = await syncToGist(files);
|
const resp = await syncToGist(files);
|
||||||
const body = JSON.parse(resp.body);
|
const body = JSON.parse(resp.body);
|
||||||
|
|
||||||
@@ -71,8 +137,8 @@ async function doSync() {
|
|||||||
|
|
||||||
$.write(allArtifacts, ARTIFACTS_KEY);
|
$.write(allArtifacts, ARTIFACTS_KEY);
|
||||||
$.notify('🌍 Sub-Store', '全部订阅同步成功!');
|
$.notify('🌍 Sub-Store', '全部订阅同步成功!');
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
$.notify('🌍 Sub-Store', '同步订阅失败', `原因:${err}`);
|
$.notify('🌍 Sub-Store', '同步订阅失败', `原因:${e.message ?? e}`);
|
||||||
$.error(`无法同步订阅配置到 Gist,原因:${err}`);
|
$.error(`无法同步订阅配置到 Gist,原因:${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,28 +2,79 @@
|
|||||||
import { ProxyUtils } from '@/core/proxy-utils';
|
import { ProxyUtils } from '@/core/proxy-utils';
|
||||||
import { RuleUtils } from '@/core/rule-utils';
|
import { RuleUtils } from '@/core/rule-utils';
|
||||||
import { version } from '../../package.json';
|
import { version } from '../../package.json';
|
||||||
|
import download from '@/utils/download';
|
||||||
|
|
||||||
console.log(
|
let result = '';
|
||||||
`
|
let resource = typeof $resource !== 'undefined' ? $resource : '';
|
||||||
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
|
let resourceType = typeof $resourceType !== 'undefined' ? $resourceType : '';
|
||||||
Sub-Store -- v${version}
|
let resourceUrl = typeof $resourceUrl !== 'undefined' ? $resourceUrl : '';
|
||||||
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const RESOURCE_TYPE = {
|
!(async () => {
|
||||||
PROXY: 1,
|
console.log(
|
||||||
RULE: 2,
|
`
|
||||||
};
|
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
|
||||||
|
Sub-Store -- v${version}
|
||||||
|
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
let result = $resource;
|
let arg;
|
||||||
|
if (typeof $argument != 'undefined') {
|
||||||
|
arg = Object.fromEntries(
|
||||||
|
$argument.split('&').map((item) => item.split('=')),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
arg = {};
|
||||||
|
}
|
||||||
|
|
||||||
if ($resourceType === RESOURCE_TYPE.PROXY) {
|
const RESOURCE_TYPE = {
|
||||||
const proxies = ProxyUtils.parse($resource);
|
PROXY: 1,
|
||||||
result = ProxyUtils.produce(proxies, 'Loon');
|
RULE: 2,
|
||||||
} else if ($resourceType === RESOURCE_TYPE.RULE) {
|
};
|
||||||
const rules = RuleUtils.parse($resource);
|
|
||||||
result = RuleUtils.produce(rules, 'Loon');
|
|
||||||
}
|
|
||||||
|
|
||||||
$done(result);
|
result = resource;
|
||||||
|
|
||||||
|
if (resourceType === RESOURCE_TYPE.PROXY) {
|
||||||
|
try {
|
||||||
|
let proxies = ProxyUtils.parse(resource);
|
||||||
|
result = ProxyUtils.produce(proxies, 'Loon');
|
||||||
|
} catch (e) {
|
||||||
|
console.log('解析器: 使用 resource 出现错误');
|
||||||
|
console.log(e.message ?? e);
|
||||||
|
}
|
||||||
|
if ((!result || /^\s*$/.test(result)) && resourceUrl) {
|
||||||
|
console.log(`解析器: 尝试从 ${resourceUrl} 获取订阅`);
|
||||||
|
try {
|
||||||
|
let raw = await download(resourceUrl, arg?.ua, arg?.timeout);
|
||||||
|
let proxies = ProxyUtils.parse(raw);
|
||||||
|
result = ProxyUtils.produce(proxies, 'Loon');
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message ?? e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (resourceType === RESOURCE_TYPE.RULE) {
|
||||||
|
try {
|
||||||
|
const rules = RuleUtils.parse(resource);
|
||||||
|
result = RuleUtils.produce(rules, 'Loon');
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message ?? e);
|
||||||
|
}
|
||||||
|
if ((!result || /^\s*$/.test(result)) && resourceUrl) {
|
||||||
|
console.log(`解析器: 尝试从 ${resourceUrl} 获取规则`);
|
||||||
|
try {
|
||||||
|
let raw = await download(resourceUrl, arg?.ua, arg?.timeout);
|
||||||
|
let rules = RuleUtils.parse(raw);
|
||||||
|
result = RuleUtils.produce(rules, 'Loon');
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message ?? e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
.catch(async (e) => {
|
||||||
|
console.log('解析器: 出现错误');
|
||||||
|
console.log(e.message ?? e);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
$done(result || '');
|
||||||
|
});
|
||||||
|
|||||||
@@ -448,6 +448,46 @@ async function syncArtifacts() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const invalid = [];
|
const invalid = [];
|
||||||
|
const allSubs = $.read(SUBS_KEY);
|
||||||
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
|
const subNames = [];
|
||||||
|
allArtifacts.map((artifact) => {
|
||||||
|
if (artifact.sync && artifact.source) {
|
||||||
|
if (artifact.type === 'subscription') {
|
||||||
|
const subName = artifact.source;
|
||||||
|
const sub = findByName(allSubs, subName);
|
||||||
|
if (sub && sub.url && !subNames.includes(subName)) {
|
||||||
|
subNames.push(subName);
|
||||||
|
}
|
||||||
|
} else if (artifact.type === 'collection') {
|
||||||
|
const collection = findByName(allCols, artifact.source);
|
||||||
|
if (collection && Array.isArray(collection.subscriptions)) {
|
||||||
|
collection.subscriptions.map((subName) => {
|
||||||
|
const sub = findByName(allSubs, subName);
|
||||||
|
if (sub && sub.url && !subNames.includes(subName)) {
|
||||||
|
subNames.push(subName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (subNames.length > 0) {
|
||||||
|
await Promise.all(
|
||||||
|
subNames.map(async (subName) => {
|
||||||
|
try {
|
||||||
|
await produceArtifact({
|
||||||
|
type: 'subscription',
|
||||||
|
name: subName,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// $.error(`${e.message ?? e}`);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
allArtifacts.map(async (artifact) => {
|
allArtifacts.map(async (artifact) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { FILES_KEY, MODULES_KEY, SETTINGS_KEY } from '@/constants';
|
import { SETTINGS_KEY } from '@/constants';
|
||||||
import { findByName } from '@/utils/database';
|
|
||||||
import { HTTP, ENV } from '@/vendor/open-api';
|
import { HTTP, ENV } from '@/vendor/open-api';
|
||||||
import { hex_md5 } from '@/vendor/md5';
|
import { hex_md5 } from '@/vendor/md5';
|
||||||
import resourceCache from '@/utils/resource-cache';
|
import resourceCache from '@/utils/resource-cache';
|
||||||
@@ -36,22 +35,22 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/);
|
// const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/);
|
||||||
if (downloadUrlMatch) {
|
// if (downloadUrlMatch) {
|
||||||
let type = downloadUrlMatch?.[1];
|
// let type = downloadUrlMatch?.[1];
|
||||||
let name = downloadUrlMatch?.[2];
|
// let name = downloadUrlMatch?.[2];
|
||||||
if (name == null) {
|
// if (name == null) {
|
||||||
throw new Error(`本地 ${type} URL 无效: ${url}`);
|
// throw new Error(`本地 ${type} URL 无效: ${url}`);
|
||||||
}
|
// }
|
||||||
name = decodeURIComponent(name);
|
// name = decodeURIComponent(name);
|
||||||
const key = type === 'module' ? MODULES_KEY : FILES_KEY;
|
// const key = type === 'module' ? MODULES_KEY : FILES_KEY;
|
||||||
const item = findByName($.read(key), name);
|
// const item = findByName($.read(key), name);
|
||||||
if (!item) {
|
// if (!item) {
|
||||||
throw new Error(`找不到本地 ${type}: ${name}`);
|
// throw new Error(`找不到本地 ${type}: ${name}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return item.content;
|
// return item.content;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const { isNode } = ENV();
|
const { isNode } = ENV();
|
||||||
const { defaultUserAgent, defaultTimeout } = $.read(SETTINGS_KEY);
|
const { defaultUserAgent, defaultTimeout } = $.read(SETTINGS_KEY);
|
||||||
@@ -74,6 +73,7 @@ export default async function download(rawUrl, ua, timeout) {
|
|||||||
// try to find in app cache
|
// try to find in app cache
|
||||||
const cached = resourceCache.get(id);
|
const cached = resourceCache.get(id);
|
||||||
if (!$arguments?.noCache && cached) {
|
if (!$arguments?.noCache && cached) {
|
||||||
|
$.info(`使用缓存: ${url}`);
|
||||||
result = cached;
|
result = cached;
|
||||||
} else {
|
} else {
|
||||||
$.info(
|
$.info(
|
||||||
|
|||||||
@@ -213,11 +213,16 @@ export function getFlag(name) {
|
|||||||
'🇹🇼': [
|
'🇹🇼': [
|
||||||
'Taiwan',
|
'Taiwan',
|
||||||
'台湾',
|
'台湾',
|
||||||
|
'臺灣',
|
||||||
|
'台灣',
|
||||||
|
'中華民國',
|
||||||
|
'中华民国',
|
||||||
'台北',
|
'台北',
|
||||||
'台中',
|
'台中',
|
||||||
'新北',
|
'新北',
|
||||||
'彰化',
|
'彰化',
|
||||||
'台',
|
'台',
|
||||||
|
'臺',
|
||||||
'Taipei',
|
'Taipei',
|
||||||
],
|
],
|
||||||
'🇺🇦': ['Ukraine', '乌克兰', '烏克蘭'],
|
'🇺🇦': ['Ukraine', '乌克兰', '烏克蘭'],
|
||||||
@@ -371,7 +376,7 @@ export function getFlag(name) {
|
|||||||
'🇹🇭': ['TH', 'THA'],
|
'🇹🇭': ['TH', 'THA'],
|
||||||
'🇹🇳': ['TN', 'TUN'],
|
'🇹🇳': ['TN', 'TUN'],
|
||||||
'🇹🇷': ['TR', 'TUR'],
|
'🇹🇷': ['TR', 'TUR'],
|
||||||
'🇹🇼': ['TW', 'TWN', 'CHT', 'HINET'],
|
'🇹🇼': ['TW', 'TWN', 'CHT', 'HINET', 'ROC'],
|
||||||
'🇺🇦': ['UA', 'UKR'],
|
'🇺🇦': ['UA', 'UKR'],
|
||||||
'🇺🇸': ['US', 'USA', 'LAX', 'SFO'],
|
'🇺🇸': ['US', 'USA', 'LAX', 'SFO'],
|
||||||
'🇺🇾': ['UY', 'URY'],
|
'🇺🇾': ['UY', 'URY'],
|
||||||
|
|||||||
@@ -10,7 +10,17 @@ class ResourceCache {
|
|||||||
if (!$.read(HEADERS_RESOURCE_CACHE_KEY)) {
|
if (!$.read(HEADERS_RESOURCE_CACHE_KEY)) {
|
||||||
$.write('{}', HEADERS_RESOURCE_CACHE_KEY);
|
$.write('{}', HEADERS_RESOURCE_CACHE_KEY);
|
||||||
}
|
}
|
||||||
this.resourceCache = JSON.parse($.read(HEADERS_RESOURCE_CACHE_KEY));
|
try {
|
||||||
|
this.resourceCache = JSON.parse($.read(HEADERS_RESOURCE_CACHE_KEY));
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`解析持久化缓存中的 ${HEADERS_RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${
|
||||||
|
e?.message ?? e
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
this.resourceCache = {};
|
||||||
|
$.write('{}', HEADERS_RESOURCE_CACHE_KEY);
|
||||||
|
}
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,53 @@ function getIfPresent(obj, defaultValue) {
|
|||||||
return isPresent(obj) ? obj : defaultValue;
|
return isPresent(obj) ? obj : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const utf8ArrayToStr =
|
||||||
|
typeof TextDecoder !== 'undefined'
|
||||||
|
? (v) => new TextDecoder().decode(new Uint8Array(v))
|
||||||
|
: (function () {
|
||||||
|
var charCache = new Array(128); // Preallocate the cache for the common single byte chars
|
||||||
|
var charFromCodePt = String.fromCodePoint || String.fromCharCode;
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
return function (array) {
|
||||||
|
var codePt, byte1;
|
||||||
|
var buffLen = array.length;
|
||||||
|
|
||||||
|
result.length = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < buffLen; ) {
|
||||||
|
byte1 = array[i++];
|
||||||
|
|
||||||
|
if (byte1 <= 0x7f) {
|
||||||
|
codePt = byte1;
|
||||||
|
} else if (byte1 <= 0xdf) {
|
||||||
|
codePt = ((byte1 & 0x1f) << 6) | (array[i++] & 0x3f);
|
||||||
|
} else if (byte1 <= 0xef) {
|
||||||
|
codePt =
|
||||||
|
((byte1 & 0x0f) << 12) |
|
||||||
|
((array[i++] & 0x3f) << 6) |
|
||||||
|
(array[i++] & 0x3f);
|
||||||
|
} else if (String.fromCodePoint) {
|
||||||
|
codePt =
|
||||||
|
((byte1 & 0x07) << 18) |
|
||||||
|
((array[i++] & 0x3f) << 12) |
|
||||||
|
((array[i++] & 0x3f) << 6) |
|
||||||
|
(array[i++] & 0x3f);
|
||||||
|
} else {
|
||||||
|
codePt = 63; // Cannot convert four byte code points, so use "?" instead
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(
|
||||||
|
charCache[codePt] ||
|
||||||
|
(charCache[codePt] = charFromCodePt(codePt)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join('');
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isIPv4,
|
isIPv4,
|
||||||
isIPv6,
|
isIPv6,
|
||||||
@@ -43,4 +90,5 @@ export {
|
|||||||
getIfNotBlank,
|
getIfNotBlank,
|
||||||
isPresent,
|
isPresent,
|
||||||
getIfPresent,
|
getIfPresent,
|
||||||
|
utf8ArrayToStr,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ class ResourceCache {
|
|||||||
if (!$.read(RESOURCE_CACHE_KEY)) {
|
if (!$.read(RESOURCE_CACHE_KEY)) {
|
||||||
$.write('{}', RESOURCE_CACHE_KEY);
|
$.write('{}', RESOURCE_CACHE_KEY);
|
||||||
}
|
}
|
||||||
this.resourceCache = JSON.parse($.read(RESOURCE_CACHE_KEY));
|
try {
|
||||||
|
this.resourceCache = JSON.parse($.read(RESOURCE_CACHE_KEY));
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`解析持久化缓存中的 ${RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${
|
||||||
|
e?.message ?? e
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
this.resourceCache = {};
|
||||||
|
$.write('{}', RESOURCE_CACHE_KEY);
|
||||||
|
}
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,17 @@ class ResourceCache {
|
|||||||
if (!$.read(SCRIPT_RESOURCE_CACHE_KEY)) {
|
if (!$.read(SCRIPT_RESOURCE_CACHE_KEY)) {
|
||||||
$.write('{}', SCRIPT_RESOURCE_CACHE_KEY);
|
$.write('{}', SCRIPT_RESOURCE_CACHE_KEY);
|
||||||
}
|
}
|
||||||
this.resourceCache = JSON.parse($.read(SCRIPT_RESOURCE_CACHE_KEY));
|
try {
|
||||||
|
this.resourceCache = JSON.parse($.read(SCRIPT_RESOURCE_CACHE_KEY));
|
||||||
|
} catch (e) {
|
||||||
|
$.error(
|
||||||
|
`解析持久化缓存中的 ${SCRIPT_RESOURCE_CACHE_KEY} 失败, 重置为 {}, 错误: ${
|
||||||
|
e?.message ?? e
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
this.resourceCache = {};
|
||||||
|
$.write('{}', SCRIPT_RESOURCE_CACHE_KEY);
|
||||||
|
}
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
backend/src/vendor/open-api.js
vendored
2
backend/src/vendor/open-api.js
vendored
@@ -312,7 +312,7 @@ export function HTTP(defaultOptions = { baseURL: '' }) {
|
|||||||
? eval("require('request')")
|
? eval("require('request')")
|
||||||
: $httpClient;
|
: $httpClient;
|
||||||
request[method.toLowerCase()](
|
request[method.toLowerCase()](
|
||||||
options,
|
JSON.parse(JSON.stringify(options)),
|
||||||
(err, response, body) => {
|
(err, response, body) => {
|
||||||
// if (err) {
|
// if (err) {
|
||||||
// console.log(err);
|
// console.log(err);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!name=Sub-Store
|
#!name=Sub-Store
|
||||||
#!desc=高级订阅管理工具. 定时任务默认为每天 0 点
|
#!desc=高级订阅管理工具. 定时任务默认为每天 23 点 55 分
|
||||||
#!openUrl=https://sub.store
|
#!openUrl=https://sub.store
|
||||||
#!author=Peng-YM
|
#!author=Peng-YM
|
||||||
#!homepage=https://github.com/sub-store-org/Sub-Store
|
#!homepage=https://github.com/sub-store-org/Sub-Store
|
||||||
@@ -17,4 +17,4 @@ hostname=sub.store
|
|||||||
http-request ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js, requires-body=true, timeout=120, tag=Sub-Store Core
|
http-request ^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))) script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js, requires-body=true, timeout=120, tag=Sub-Store Core
|
||||||
http-request ^https?:\/\/sub\.store script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js, requires-body=true, timeout=120, tag=Sub-Store Simple
|
http-request ^https?:\/\/sub\.store script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js, requires-body=true, timeout=120, tag=Sub-Store Simple
|
||||||
|
|
||||||
cron "0 0 * * *" script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js, tag=Sub-Store Sync
|
cron "55 23 * * *" script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js, tag=Sub-Store Sync
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Sub-Store",
|
"name": "Sub-Store",
|
||||||
"description": "定时任务默认为每天 0 点",
|
"description": "定时任务默认为每天 23 点 55 分",
|
||||||
"task": [
|
"task": [
|
||||||
"0 0 * * * https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js, tag=Sub-Store Sync, img-url=https://raw.githubusercontent.com/58xinian/icon/master/Sub-Store1.png"
|
"55 23 * * * https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js, tag=Sub-Store Sync, img-url=https://raw.githubusercontent.com/58xinian/icon/master/Sub-Store1.png"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,9 @@ Telegram 频道: [`https://t.me/cool_scripts` ](https://t.me/cool_scripts)
|
|||||||
|
|
||||||
1. 官方默认版模块(目前不带 ability 参数, 不保证以后不会改动): [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule)
|
1. 官方默认版模块(目前不带 ability 参数, 不保证以后不会改动): [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge.sgmodule)
|
||||||
|
|
||||||
2. 固定带 ability 参数版本,可能会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 请使用此带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule)
|
2. 固定带 ability 参数版本,可能会爆内存, 如果需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 请使用此带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-ability.sgmodule)
|
||||||
|
|
||||||
|
> 最新 Surge iOS TestFlight 版本应该没有内存问题了 可以大胆尝试带 ability 参数版本
|
||||||
|
|
||||||
3. 固定不带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule)
|
3. 固定不带 ability 参数版本: [`https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule`](https://raw.githubusercontent.com/sub-store-org/Sub-Store/master/config/Surge-Noability.sgmodule)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
name: Sub-Store
|
name: Sub-Store
|
||||||
desc: 高级订阅管理工具 @Peng-YM. 定时任务默认为每天 0 点
|
desc: 高级订阅管理工具 @Peng-YM. 定时任务默认为每天 23 点 55 分
|
||||||
|
icon: https://raw.githubusercontent.com/cc63/ICON/main/Sub-Store.png
|
||||||
|
|
||||||
http:
|
http:
|
||||||
mitm:
|
mitm:
|
||||||
@@ -19,7 +20,7 @@ http:
|
|||||||
cron:
|
cron:
|
||||||
script:
|
script:
|
||||||
- name: cron-sync-artifacts
|
- name: cron-sync-artifacts
|
||||||
cron: "0 0 * * *"
|
cron: "55 23 * * *"
|
||||||
timeout: 120
|
timeout: 120
|
||||||
|
|
||||||
script-providers:
|
script-providers:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!name=Sub-Store(β)
|
#!name=Sub-Store(β)
|
||||||
#!desc=支持最新 Surge iOS TestFlight 版本的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 0 0 * * *
|
#!desc=支持最新 Surge iOS TestFlight 版本的参数设置功能. 测落地功能 ability: http-client-policy, 同步配置的定时 cronexp: 55 23 * * *
|
||||||
#!category=订阅管理
|
#!category=订阅管理
|
||||||
#!arguments=ability:http-client-policy,cronexp:0 0 * * *,sync:"Sub-Store Sync"
|
#!arguments=ability:http-client-policy,cronexp:55 23 * * *,sync:"Sub-Store Sync"
|
||||||
#!arguments-desc="\n1️⃣ ability\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n⚠️ Surge 上时候可能会爆内存\n不需要使用的时候应该关闭\n填写任意其他值关闭\n\n2️⃣ cronexp\n同步配置定时任务\n默认为每天 0 点\n\n3️⃣ sync\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务"
|
#!arguments-desc="\n1️⃣ ability\n默认已开启测落地能力\n需要配合脚本操作\n如 https://raw.githubusercontent.com/Keywos/rule/main/cname.js\n⚠️ Surge 上时候可能会爆内存\n不需要使用的时候应该关闭\n填写任意其他值关闭\n\n2️⃣ cronexp\n同步配置定时任务\n默认为每天 23 点 55 分\n\n3️⃣ sync\n自定义定时任务名\n便于在脚本编辑器中选择\n若设为 # 可取消定时任务"
|
||||||
|
|
||||||
[MITM]
|
[MITM]
|
||||||
hostname = %APPEND% sub.store
|
hostname = %APPEND% sub.store
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#!name=Sub-Store
|
#!name=Sub-Store
|
||||||
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用带 ability 参数. 定时任务默认为每天 0 点
|
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 可以用带 ability 参数. 定时任务默认为每天 23 点 55 分
|
||||||
#!category=订阅管理
|
#!category=订阅管理
|
||||||
|
|
||||||
[MITM]
|
[MITM]
|
||||||
hostname = %APPEND% sub.store
|
hostname = %APPEND% sub.store
|
||||||
|
|
||||||
[Script]
|
[Script]
|
||||||
# 主程序 已经去掉 Sub-Store Core 的参数 [,ability=http-client-policy] 不会爆内存,这个参数在 Surge 非常占用内存; 如果不需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 则可以使用此脚本
|
# 主程序 已经去掉 Sub-Store Core 的参数 [,ability=http-client-policy] 不会爆内存,这个参数在 Surge 非常占用内存; 如果不需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 则可以使用此脚本
|
||||||
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120
|
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120
|
||||||
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
||||||
|
|
||||||
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
Sub-Store Sync=type=cron,cronexp=55 23 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!name=Sub-Store
|
#!name=Sub-Store
|
||||||
#!desc=高级订阅管理工具 @Peng-YM 带 ability 参数版本, 可能会爆内存, 如果不需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用不带 ability 参数版本. 定时任务默认为每天 0 点
|
#!desc=高级订阅管理工具 @Peng-YM 带 ability 参数版本, 可能会爆内存, 如果不需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 可以用不带 ability 参数版本. 定时任务默认为每天 23 点 55 分
|
||||||
#!category=订阅管理
|
#!category=订阅管理
|
||||||
|
|
||||||
[MITM]
|
[MITM]
|
||||||
@@ -9,4 +9,4 @@ hostname = %APPEND% sub.store
|
|||||||
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120,ability=http-client-policy
|
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120,ability=http-client-policy
|
||||||
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
||||||
|
|
||||||
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
Sub-Store Sync=type=cron,cronexp=55 23 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!name=Sub-Store
|
#!name=Sub-Store
|
||||||
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用带 ability 参数. 定时任务默认为每天 0 点
|
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加旗帜脚本或者cname脚本] 可以用带 ability 参数. 定时任务默认为每天 23 点 55 分
|
||||||
#!category=订阅管理
|
#!category=订阅管理
|
||||||
|
|
||||||
[MITM]
|
[MITM]
|
||||||
@@ -9,4 +9,4 @@ hostname = %APPEND% sub.store
|
|||||||
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120
|
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120
|
||||||
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
|
||||||
|
|
||||||
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
Sub-Store Sync=type=cron,cronexp=55 23 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js
|
||||||
|
|||||||
@@ -35,6 +35,49 @@ function operator(proxies = [], targetPlatform, context) {
|
|||||||
// yaml, // yaml 解析和生成
|
// yaml, // yaml 解析和生成
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// 1. Surge 输出 WireGuard 完整配置
|
||||||
|
|
||||||
|
// let proxies = await produceArtifact({
|
||||||
|
// type: 'subscription',
|
||||||
|
// name: 'sub',
|
||||||
|
// platform: 'Surge',
|
||||||
|
// produceOpts: {
|
||||||
|
// 'include-unsupported-proxy': true,
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// $content = proxies
|
||||||
|
|
||||||
|
// 2. sing-box
|
||||||
|
|
||||||
|
// 但是一般不需要这样用, 可参考 1. https://t.me/zhetengsha/1111 和 2. https://t.me/zhetengsha/1070
|
||||||
|
|
||||||
|
// let singboxProxies = await produceArtifact({
|
||||||
|
// type: 'subscription', // type: 'subscription' 或 'collection'
|
||||||
|
// name: 'sub', // subscription name
|
||||||
|
// platform: 'sing-box', // target platform
|
||||||
|
// produceType: 'internal' // 'internal' produces an Array, otherwise produces a String( JSON.parse('JSON String') )
|
||||||
|
// })
|
||||||
|
|
||||||
|
// // JSON
|
||||||
|
// $content = JSON.stringify({}, null, 2)
|
||||||
|
|
||||||
|
// 3. clash.meta
|
||||||
|
|
||||||
|
// 但是一般不需要这样用, 可参考 1. https://t.me/zhetengsha/1111 和 2. https://t.me/zhetengsha/1070
|
||||||
|
|
||||||
|
// let clashMetaProxies = await produceArtifact({
|
||||||
|
// type: 'subscription',
|
||||||
|
// name: 'sub',
|
||||||
|
// platform: 'ClashMeta',
|
||||||
|
// produceType: 'internal' // 'internal' produces an Array, otherwise produces a String( ProxyUtils.yaml.safeLoad('YAML String').proxies )
|
||||||
|
// }))
|
||||||
|
|
||||||
|
// // YAML
|
||||||
|
// $content = ProxyUtils.yaml.safeDump({})
|
||||||
|
|
||||||
|
|
||||||
|
// { $content, $files } will be passed to the next operator
|
||||||
|
// $content is the final content of the file
|
||||||
// flowUtils 为机场订阅流量信息处理工具
|
// flowUtils 为机场订阅流量信息处理工具
|
||||||
// 可参考 https://t.me/zhetengsha/948
|
// 可参考 https://t.me/zhetengsha/948
|
||||||
// https://github.com/sub-store-org/Sub-Store/blob/31b6dd0507a9286d6ab834ec94ad3050f6bdc86b/backend/src/utils/download.js#L104
|
// https://github.com/sub-store-org/Sub-Store/blob/31b6dd0507a9286d6ab834ec94ad3050f6bdc86b/backend/src/utils/download.js#L104
|
||||||
|
|||||||
1
web
1
web
Submodule web deleted from b10b708c34
Reference in New Issue
Block a user