Skip to content

Commit

Permalink
feat: SurgeMac 支持使用 mihomo 来支援 Surge 本身不支持的协议; 弃用旧的 ssr-local 方案
Browse files Browse the repository at this point in the history
  • Loading branch information
xream committed Sep 3, 2024
1 parent 99d5868 commit 5e8e52f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 30 deletions.
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.373",
"version": "2.14.374",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {
Expand Down
14 changes: 2 additions & 12 deletions backend/src/core/proxy-utils/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Base64 } from 'js-base64';

Check failure on line 1 in backend/src/core/proxy-utils/index.js

View workflow job for this annotation

GitHub Actions / build

'Base64' is defined but never used
import { Buffer } from 'buffer';
import rs from '@/utils/rs';
import YAML from '@/utils/yaml';
Expand Down Expand Up @@ -244,21 +245,10 @@ function produce(proxies, targetPlatform, type, opts = {}) {

$.log(`Producing proxies for target: ${targetPlatform}`);
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
let localPort = 10000;
let list = proxies
.map((proxy) => {
try {
let line = producer.produce(proxy, type, opts);
if (
line.length > 0 &&
line.includes('__SubStoreLocalPort__')
) {
line = line.replace(
/__SubStoreLocalPort__/g,
localPort++,
);
}
return line;
return producer.produce(proxy, type, opts);
} catch (err) {
$.error(
`Cannot produce proxy: ${JSON.stringify(
Expand Down
8 changes: 5 additions & 3 deletions backend/src/core/proxy-utils/producers/clash.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,11 @@ export default function Clash_Producer() {
delete proxy.id;
delete proxy.resolved;
delete proxy['no-resolve'];
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
if (type !== 'internal') {
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
}
}
}
if (
Expand Down
8 changes: 5 additions & 3 deletions backend/src/core/proxy-utils/producers/clashmeta.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,11 @@ export default function ClashMeta_Producer() {
delete proxy.id;
delete proxy.resolved;
delete proxy['no-resolve'];
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
if (type !== 'internal') {
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
}
}
}
if (
Expand Down
8 changes: 5 additions & 3 deletions backend/src/core/proxy-utils/producers/shadowrocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,11 @@ export default function ShadowRocket_Producer() {
delete proxy.id;
delete proxy.resolved;
delete proxy['no-resolve'];
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
if (type !== 'internal') {
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
}
}
}
if (
Expand Down
8 changes: 5 additions & 3 deletions backend/src/core/proxy-utils/producers/stash.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,11 @@ export default function Stash_Producer() {
delete proxy.id;
delete proxy.resolved;
delete proxy['no-resolve'];
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
if (type !== 'internal') {
for (const key in proxy) {
if (proxy[key] == null || /^_/i.test(key)) {
delete proxy[key];
}
}
}
if (
Expand Down
80 changes: 75 additions & 5 deletions backend/src/core/proxy-utils/producers/surgemac.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Base64 } from 'js-base64';
import { Result, isPresent } from './utils';
import Surge_Producer from './surge';
import ClashMeta_Producer from './clashmeta';
import { isIPv4, isIPv6 } from '@/utils';
import $ from '@/core/app';

Expand All @@ -8,14 +10,22 @@ const targetPlatform = 'SurgeMac';
const surge_Producer = Surge_Producer();

export default function SurgeMac_Producer() {
const produce = (proxy) => {
const produce = (proxy, type, opts = {}) => {
switch (proxy.type) {
case 'external':
return external(proxy);
case 'ssr':
return shadowsocksr(proxy);
default:
return surge_Producer.produce(proxy);
// case 'ssr':
// return shadowsocksr(proxy);
default: {
try {
return surge_Producer.produce(proxy, type, opts);
} catch (e) {
$.log(
`${proxy.name} is not supported on ${targetPlatform}, try to use Mihomo(SurgeMac - External Proxy Program) instead`,
);
return mihomo(proxy, type, opts);
}
}
}
};
return { produce };
Expand Down Expand Up @@ -60,6 +70,7 @@ function external(proxy) {

return result.toString();
}
// eslint-disable-next-line no-unused-vars
function shadowsocksr(proxy) {
const external_proxy = {
...proxy,
Expand Down Expand Up @@ -101,6 +112,65 @@ function shadowsocksr(proxy) {

return external(external_proxy);
}
// eslint-disable-next-line no-unused-vars
function mihomo(proxy, type, opts) {
const clashProxy = ClashMeta_Producer().produce([proxy], 'internal')?.[0];
if (clashProxy) {
const localPort = opts?.localPort || proxy._localPort || 65535;
const ipv6 = ['ipv4', 'v4-only'].includes(proxy['ip-version'])
? false
: true;
const external_proxy = {
name: proxy.name,
type: 'external',
exec: proxy._exec || '/usr/local/bin/mihomo',
'local-port': localPort,
args: [
'-config',
Base64.encode(
JSON.stringify({
'mixed-port': localPort,
ipv6,
mode: 'global',
dns: {
enable: true,
ipv6,
nameserver: [
'https://223.6.6.6/dns-query',
'https://120.53.53.53/dns-query',
],
},
proxies: [
{
...clashProxy,
name: 'proxy',
},
],
'proxy-groups': [
{
name: 'GLOBAL',
type: 'select',
proxies: ['proxy'],
},
],
}),
),
],
addresses: [],
};

// https://manual.nssurge.com/policy/external-proxy.html
if (isIP(proxy.server)) {
external_proxy.addresses.push(proxy.server);
} else {
$.log(
`Platform ${targetPlatform}, proxy type ${proxy.type}: addresses should be an IP address, but got ${proxy.server}`,
);
}
opts.localPort = localPort - 1;
return external(external_proxy);
}
}

function isIP(ip) {
return isIPv4(ip) || isIPv6(ip);
Expand Down

0 comments on commit 5e8e52f

Please sign in to comment.