mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-09-15 00:33:15 +08:00
feat: 支持 Surfboard(前端 > 2.14.27)
This commit is contained in:
parent
36db057e32
commit
bc5ae9a2ef
20
README.md
20
README.md
@ -7,7 +7,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center" color="#6a737d">
|
<p align="center" color="#6a737d">
|
||||||
Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.
|
Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/sub-store-org/Sub-Store/actions/workflows/main.yml)     
|
[](https://github.com/sub-store-org/Sub-Store/actions/workflows/main.yml)     
|
||||||
@ -31,23 +31,25 @@ Core functionalities:
|
|||||||
- [x] SSD URI
|
- [x] SSD URI
|
||||||
- [x] V2RayN URI
|
- [x] V2RayN URI
|
||||||
- [x] Hysteria2 URI
|
- [x] Hysteria2 URI
|
||||||
- [x] QX (SS, SSR, VMess, Trojan, HTTP)
|
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5)
|
||||||
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, WireGuard, VLESS, Hysteria2)
|
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, SOCKS5, WireGuard, VLESS, Hysteria2)
|
||||||
- [x] Surge (SS, VMess, Trojan, HTTP, TUIC, Snell, Hysteria2, SSR(external, only for macOS), WireGuard(Surge to Surge))
|
- [x] Surge (SS, VMess, Trojan, HTTP, SOCKS5, TUIC, Snell, Hysteria2, SSR(external, only for macOS), WireGuard(Surge to Surge))
|
||||||
- [x] ShadowRocket (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, Hysteria2)
|
- [x] Surfboard (SS, VMess, Trojan, HTTP, SOCKS5, WireGuard(Surfboard to Surfboard))
|
||||||
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria, Hysteria2)
|
- [x] Shadowrocket (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria2, TUIC)
|
||||||
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria)
|
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria2, TUIC)
|
||||||
- [x] Clash (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard)
|
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC)
|
||||||
|
- [x] Clash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard)
|
||||||
|
|
||||||
### Supported Target Platforms
|
### Supported Target Platforms
|
||||||
|
|
||||||
- [x] QX
|
- [x] QX
|
||||||
- [x] Loon
|
- [x] Loon
|
||||||
- [x] Surge
|
- [x] Surge
|
||||||
|
- [x] Surfboard
|
||||||
- [x] Stash
|
- [x] Stash
|
||||||
- [x] Clash.Meta
|
- [x] Clash.Meta
|
||||||
- [x] Clash
|
- [x] Clash
|
||||||
- [x] ShadowRocket
|
- [x] Shadowrocket
|
||||||
- [x] V2Ray
|
- [x] V2Ray
|
||||||
- [x] V2Ray URI
|
- [x] V2Ray URI
|
||||||
- [x] Plain JSON
|
- [x] Plain JSON
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.133",
|
"version": "2.14.134",
|
||||||
"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,7 @@ import URI_Producer from './uri';
|
|||||||
import V2Ray_Producer from './v2ray';
|
import V2Ray_Producer from './v2ray';
|
||||||
import QX_Producer from './qx';
|
import QX_Producer from './qx';
|
||||||
import ShadowRocket_Producer from './shadowrocket';
|
import ShadowRocket_Producer from './shadowrocket';
|
||||||
|
import Surfboard_Producer from './surfboard';
|
||||||
|
|
||||||
function JSON_Producer() {
|
function JSON_Producer() {
|
||||||
const type = 'ALL';
|
const type = 'ALL';
|
||||||
@ -27,4 +28,5 @@ export default {
|
|||||||
JSON: JSON_Producer(),
|
JSON: JSON_Producer(),
|
||||||
Stash: Stash_Producer(),
|
Stash: Stash_Producer(),
|
||||||
ShadowRocket: ShadowRocket_Producer(),
|
ShadowRocket: ShadowRocket_Producer(),
|
||||||
|
Surfboard: Surfboard_Producer(),
|
||||||
};
|
};
|
||||||
|
199
backend/src/core/proxy-utils/producers/surfboard.js
Normal file
199
backend/src/core/proxy-utils/producers/surfboard.js
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import { Result, isPresent } from './utils';
|
||||||
|
import { isNotBlank } from '@/utils';
|
||||||
|
// import $ from '@/core/app';
|
||||||
|
|
||||||
|
const targetPlatform = 'Surfboard';
|
||||||
|
|
||||||
|
export default function Surfboard_Producer() {
|
||||||
|
const produce = (proxy) => {
|
||||||
|
switch (proxy.type) {
|
||||||
|
case 'ss':
|
||||||
|
return shadowsocks(proxy);
|
||||||
|
case 'trojan':
|
||||||
|
return trojan(proxy);
|
||||||
|
case 'vmess':
|
||||||
|
return vmess(proxy);
|
||||||
|
case 'http':
|
||||||
|
return http(proxy);
|
||||||
|
case 'socks5':
|
||||||
|
return socks5(proxy);
|
||||||
|
case 'wireguard-surge':
|
||||||
|
return wireguard(proxy);
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return { produce };
|
||||||
|
}
|
||||||
|
|
||||||
|
function shadowsocks(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
||||||
|
result.append(`,encrypt-method=${proxy.cipher}`);
|
||||||
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
// obfs
|
||||||
|
if (isPresent(proxy, 'plugin')) {
|
||||||
|
if (proxy.plugin === 'obfs') {
|
||||||
|
result.append(`,obfs=${proxy['plugin-opts'].mode}`);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,obfs-host=${proxy['plugin-opts'].host}`,
|
||||||
|
'plugin-opts.host',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,obfs-uri=${proxy['plugin-opts'].path}`,
|
||||||
|
'plugin-opts.path',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error(`plugin ${proxy.plugin} is not supported`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function trojan(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
||||||
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
// transport
|
||||||
|
handleTransport(result, proxy);
|
||||||
|
|
||||||
|
// tls
|
||||||
|
result.appendIfPresent(`,tls=${proxy.tls}`, 'tls');
|
||||||
|
|
||||||
|
// tls verification
|
||||||
|
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
|
||||||
|
// tfo
|
||||||
|
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function vmess(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
|
||||||
|
result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid');
|
||||||
|
|
||||||
|
// transport
|
||||||
|
handleTransport(result, proxy);
|
||||||
|
|
||||||
|
// AEAD
|
||||||
|
if (isPresent(proxy, 'aead')) {
|
||||||
|
result.append(`,vmess-aead=${proxy.aead}`);
|
||||||
|
} else {
|
||||||
|
result.append(`,vmess-aead=${proxy.alterId === 0}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tls
|
||||||
|
result.appendIfPresent(`,tls=${proxy.tls}`, 'tls');
|
||||||
|
|
||||||
|
// tls verification
|
||||||
|
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function http(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
const type = proxy.tls ? 'https' : 'http';
|
||||||
|
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
|
||||||
|
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||||
|
result.appendIfPresent(`,${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
// tls verification
|
||||||
|
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function socks5(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
const type = proxy.tls ? 'socks5-tls' : 'socks5';
|
||||||
|
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
|
||||||
|
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||||
|
result.appendIfPresent(`,${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
// tls verification
|
||||||
|
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function wireguard(proxy) {
|
||||||
|
const result = new Result(proxy);
|
||||||
|
|
||||||
|
result.append(`${proxy.name}=wireguard`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,section-name=${proxy['section-name']}`,
|
||||||
|
'section-name',
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTransport(result, proxy) {
|
||||||
|
if (isPresent(proxy, 'network')) {
|
||||||
|
if (proxy.network === 'ws') {
|
||||||
|
result.append(`,ws=true`);
|
||||||
|
if (isPresent(proxy, 'ws-opts')) {
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,ws-path=${proxy['ws-opts'].path}`,
|
||||||
|
'ws-opts.path',
|
||||||
|
);
|
||||||
|
if (isPresent(proxy, 'ws-opts.headers')) {
|
||||||
|
const headers = proxy['ws-opts'].headers;
|
||||||
|
const value = Object.keys(headers)
|
||||||
|
.map((k) => {
|
||||||
|
let v = headers[k];
|
||||||
|
if (['Host'].includes(k)) {
|
||||||
|
v = `"${v}"`;
|
||||||
|
}
|
||||||
|
return `${k}:${v}`;
|
||||||
|
})
|
||||||
|
.join('|');
|
||||||
|
if (isNotBlank(value)) {
|
||||||
|
result.append(`,ws-headers=${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`network ${proxy.network} is unsupported`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Result } from './utils';
|
import { Result } from './utils';
|
||||||
import Surge_Producer from './surge';
|
import Surge_Producer from './surge';
|
||||||
|
|
||||||
const targetPlatform = 'SurgeMac';
|
// const targetPlatform = 'SurgeMac';
|
||||||
|
|
||||||
const surge_Producer = Surge_Producer();
|
const surge_Producer = Surge_Producer();
|
||||||
|
|
||||||
@ -10,24 +10,9 @@ export default function SurgeMac_Producer() {
|
|||||||
switch (proxy.type) {
|
switch (proxy.type) {
|
||||||
case 'ssr':
|
case 'ssr':
|
||||||
return shadowsocksr(proxy);
|
return shadowsocksr(proxy);
|
||||||
case 'ss':
|
default:
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'trojan':
|
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'vmess':
|
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'http':
|
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'socks5':
|
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'snell':
|
|
||||||
return surge_Producer.produce(proxy);
|
|
||||||
case 'tuic':
|
|
||||||
return surge_Producer.produce(proxy);
|
return surge_Producer.produce(proxy);
|
||||||
}
|
}
|
||||||
throw new Error(
|
|
||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
return { produce };
|
return { produce };
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ export function getPlatformFromHeaders(headers) {
|
|||||||
}
|
}
|
||||||
if (UA.indexOf('Quantumult%20X') !== -1) {
|
if (UA.indexOf('Quantumult%20X') !== -1) {
|
||||||
return 'QX';
|
return 'QX';
|
||||||
|
} else if (UA.indexOf('Surfboard') !== -1) {
|
||||||
|
return 'Surfboard';
|
||||||
} else if (UA.indexOf('Surge Mac') !== -1) {
|
} else if (UA.indexOf('Surge Mac') !== -1) {
|
||||||
return 'SurgeMac';
|
return 'SurgeMac';
|
||||||
} else if (UA.indexOf('Surge') !== -1) {
|
} else if (UA.indexOf('Surge') !== -1) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user