Compare commits

..

25 Commits

Author SHA1 Message Date
asdlokj1qpi23
6227eb4e7d update docker actions 2024-03-13 09:34:17 +08:00
asdlokj1qpi23
54c8e65c70 update docker actions 2024-03-13 09:25:03 +08:00
asdlokj1qpi23
b90e63b506 fix string_icase_map.(#10) 2024-03-12 10:36:33 +08:00
asdlokj1qpi23
185e3893bf To add custom certificate configuration for HY2 protocol.(#7) 2024-01-29 19:20:59 +08:00
asdlokj1qpi23
5a4049af89 When adding Surge as a target, support for hysteria2.(#6) 2024-01-24 14:45:17 +08:00
asdlokj1qpi23
c842defea8 Fix the conversion of TLS-related issues when Singbox is used as the source. Fix the issue of missing SNI in Trojan.(#4) 2024-01-03 09:59:25 +08:00
asdlokj1qpi23
e26eaf0bf5 Fix the issue of missing sni parameters in vless, hysteria, and hysteria2. Fix the problem of dirty data during Singbox conversion. (#4) 2024-01-02 17:19:13 +08:00
asdlokj1qpi23
766bdcd6e1 Fix the issue of incorrect conversion of VLESS reality in Singbox as the source. Fix the issue of missing SS nodes with the obfs type when converting to Singbox. (#4) 2024-01-02 11:36:00 +08:00
asdlokj1qpi23
897dc5ed43 fix singbox parser bug.(#4) 2023-12-30 19:18:30 +08:00
asdlokj1qpi23
7bd6670448 change README.md 2023-12-29 19:31:47 +08:00
asdlokj1qpi23
7af3bf1794 Include Singbox as a source.(#4) 2023-12-29 18:59:20 +08:00
asdlokj1qpi23
359d9794a8 Add singbox parser vmess.Change README.md 2023-12-28 15:39:27 +08:00
asdlokj1qpi23
089f782177 Add singbox parser function. 2023-12-28 14:10:31 +08:00
asdlokj1qpi23
75023b028e fix stash vmess uuid issue. 2023-12-26 11:06:01 +08:00
asdlokj1qpi23
322924f24a fix actions issues 2023-12-25 12:44:00 +08:00
asdlokj1qpi23
04a2c24904 fix actions issues 2023-12-25 12:38:55 +08:00
asdlokj1qpi23
e80ce5833c add arm test 2023-12-25 11:33:22 +08:00
asdlokj1qpi23
31ba5373f0 add arm test 2023-12-25 11:10:37 +08:00
asdlokj1qpi23
d3801b7951 add arm test 2023-12-25 11:09:32 +08:00
asdlokj1qpi23
31775a91a8 add arm test 2023-12-25 11:01:34 +08:00
asdlokj1qpi23
af4dd857a8 Revert "fix vless short_id issue.(#1)"
This reverts commit 686f6b3517.
2023-12-25 11:00:27 +08:00
asdlokj1qpi23
686f6b3517 fix vless short_id issue.(#1) 2023-12-25 11:00:02 +08:00
asdlokj1qpi23
ebad0e96f7 fix vless short_id issue.(#1) 2023-12-25 10:51:21 +08:00
asdlokj1qpi23
927c828a27 Hy1 add ports support for clash export. 2023-12-25 10:22:33 +08:00
asdlokj1qpi23
13a372511b Hy1 add ports support. 2023-12-25 10:19:50 +08:00
9 changed files with 686 additions and 283 deletions

View File

@@ -1,7 +1,6 @@
name: GitHub CI
on:
push:
branches: [ master ]
tags:
- '**'
workflow_dispatch:
@@ -62,55 +61,59 @@ jobs:
files: subconverter_linux64.tar.gz
draft: true
# armv7_build:
# name: Linux armv7 Build
# runs-on: [self-hosted, linux, ARM]
# steps:
# - uses: actions/checkout@v3
# - name: Add commit id into version
# if: ${{ !startsWith(github.ref, 'refs/tags/') }}
# run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
# - name: Build
# run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:armv7-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh"
# - name: Upload
# uses: actions/upload-artifact@v3
# with:
# name: subconverter_armv7
# path: subconverter/
# - name: Package Release
# if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
# run: tar czf subconverter_armv7.tar.gz subconverter
# - name: Draft Release
# uses: softprops/action-gh-release@v1
# if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
# with:
# files: subconverter_armv7.tar.gz
# draft: true
#
# aarch64_build:
# name: Linux aarch64 Build
# runs-on: [self-hosted, linux, ARM64]
# steps:
# - uses: actions/checkout@v3
# - name: Add commit id into version
# if: ${{ !startsWith(github.ref, 'refs/tags/') }}
# run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
# - name: Build
# run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:aarch64-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh"
# - name: Upload
# uses: actions/upload-artifact@v3
# with:
# name: subconverter_aarch64
# path: subconverter/
# - name: Package Release
# if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
# run: tar czf subconverter_aarch64.tar.gz subconverter
# - name: Draft Release
# uses: softprops/action-gh-release@v1
# if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
# with:
# files: subconverter_aarch64.tar.gz
# draft: true
armv7_build:
name: Linux armv7 Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Add commit id into version
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Build
run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:armv7-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh"
- name: Upload
uses: actions/upload-artifact@v3
with:
name: subconverter_armv7
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf subconverter_armv7.tar.gz subconverter
- name: Draft Release
uses: softprops/action-gh-release@v1
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
with:
files: subconverter_armv7.tar.gz
draft: true
aarch64_build:
name: Linux aarch64 Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Add commit id into version
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Build
run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:aarch64-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh"
- name: Upload
uses: actions/upload-artifact@v3
with:
name: subconverter_aarch64
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf subconverter_aarch64.tar.gz subconverter
- name: Draft Release
uses: softprops/action-gh-release@v1
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
with:
files: subconverter_aarch64.tar.gz
draft: true
macos_build:
name: macOS Build

View File

@@ -4,6 +4,8 @@ on:
branches: [ master ]
tags:
- '**'
workflow_dispatch:
pull_request:
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
@@ -61,6 +63,8 @@ jobs:
platforms: linux/amd64
context: scripts/
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
outputs: type=image,push=true
- name: Save digest
@@ -106,7 +110,7 @@ jobs:
with:
platforms: linux/386
context: scripts/
tags: asdlokj1qpi23/subconverter:latest-x86
tags: asdlokj1qpi23/subconverter:latest
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
outputs: type=image,push=true
@@ -127,7 +131,9 @@ jobs:
with:
platforms: linux/386
context: scripts/
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}-x86
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}
outputs: type=image,push=true
- name: Save digest
@@ -144,150 +150,154 @@ jobs:
name: digest_386
path: /tmp/digest.txt
# armv7_build:
# name: Build ARMv7 Image
# runs-on: [self-hosted, linux, ARM]
# steps:
# - name: Checkout base
# uses: actions/checkout@v3
# with:
# fetch-depth: 0
#
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
#
# - name: Docker login
# uses: docker/login-action@v2
# with:
# username: ${{ secrets.DOCKER_USERNAME }}
# password: ${{ secrets.DOCKER_PASSWORD }}
#
# - name: Get commit SHA
# id: vars
# run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
#
# - name: Build and export
# id: build
# if: github.ref == 'refs/heads/master'
# uses: docker/build-push-action@v3
# with:
# platforms: linux/arm/v7
# context: scripts/
# tags: asdlokj1qpi23/subconverter:latest-armv7
# build-args: |
# SHA=${{ steps.vars.outputs.sha_short }}
# THREADS=4
# outputs: type=image,push=true
#
# - name: Replace tag without `v`
# if: startsWith(github.ref, 'refs/tags/')
# uses: actions/github-script@v6
# id: version
# with:
# script: |
# return context.payload.ref.replace(/\/?refs\/tags\/v/, '')
# result-encoding: string
#
# - name: Build release and export
# id: build_rel
# if: startsWith(github.ref, 'refs/tags/')
# uses: docker/build-push-action@v3
# with:
# platforms: linux/arm/v7
# context: scripts/
# tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}-armv7
# build-args: |
# THREADS=4
# outputs: type=image,push=true
#
# - name: Save digest
# if: github.ref == 'refs/heads/master'
# run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt
#
# - name: Save release digest
# if: startsWith(github.ref, 'refs/tags/')
# run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt
#
# - name: Upload artifact
# uses: actions/upload-artifact@v3
# with:
# name: digest_armv7
# path: /tmp/digest.txt
#
# arm64_build:
# name: Build ARM64 Image
# runs-on: [self-hosted, linux, ARM64]
# steps:
# - name: Checkout base
# uses: actions/checkout@v3
# with:
# fetch-depth: 0
#
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
#
# - name: Docker login
# uses: docker/login-action@v2
# with:
# username: ${{ secrets.DOCKER_USERNAME }}
# password: ${{ secrets.DOCKER_PASSWORD }}
#
# - name: Get commit SHA
# id: vars
# run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
#
# - name: Build and export
# id: build
# if: github.ref == 'refs/heads/master'
# uses: docker/build-push-action@v3
# with:
# platforms: linux/arm64
# context: scripts/
# tags: asdlokj1qpi23/subconverter:latest-arm64
# build-args: |
# SHA=${{ steps.vars.outputs.sha_short }}
# THREADS=4
# outputs: type=image,push=true
#
# - name: Replace tag without `v`
# if: startsWith(github.ref, 'refs/tags/')
# uses: actions/github-script@v6
# id: version
# with:
# script: |
# return context.payload.ref.replace(/\/?refs\/tags\/v/, '')
# result-encoding: string
#
# - name: Build release and export
# id: build_rel
# if: startsWith(github.ref, 'refs/tags/')
# uses: docker/build-push-action@v3
# with:
# platforms: linux/arm64
# context: scripts/
# tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}-arm64
# build-args: |
# THREADS=4
# outputs: type=image,push=true
#
# - name: Save digest
# if: github.ref == 'refs/heads/master'
# run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt
#
# - name: Save release digest
# if: startsWith(github.ref, 'refs/tags/')
# run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt
#
# - name: Upload artifact
# uses: actions/upload-artifact@v3
# with:
# name: digest_arm64
# path: /tmp/digest.txt
armv7_build:
name: Build ARMv7 Image
runs-on: ubuntu-latest
steps:
- name: Checkout base
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get commit SHA
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build and export
id: build
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v3
with:
platforms: linux/arm/v7
context: scripts/
tags: asdlokj1qpi23/subconverter:latest
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
THREADS=4
outputs: type=image,push=true
- name: Replace tag without `v`
if: startsWith(github.ref, 'refs/tags/')
uses: actions/github-script@v6
id: version
with:
script: |
return context.payload.ref.replace(/\/?refs\/tags\/v/, '')
result-encoding: string
- name: Build release and export
id: build_rel
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v3
with:
platforms: linux/arm/v7
context: scripts/
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
THREADS=4
outputs: type=image,push=true
- name: Save digest
if: github.ref == 'refs/heads/master'
run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt
- name: Save release digest
if: startsWith(github.ref, 'refs/tags/')
run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: digest_armv7
path: /tmp/digest.txt
arm64_build:
name: Build ARM64 Image
runs-on: ubuntu-latest
steps:
- name: Checkout base
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get commit SHA
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build and export
id: build
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v3
with:
platforms: linux/arm64
context: scripts/
tags: asdlokj1qpi23/subconverter:latest
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
THREADS=4
outputs: type=image,push=true
- name: Replace tag without `v`
if: startsWith(github.ref, 'refs/tags/')
uses: actions/github-script@v6
id: version
with:
script: |
return context.payload.ref.replace(/\/?refs\/tags\/v/, '')
result-encoding: string
- name: Build release and export
id: build_rel
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v3
with:
platforms: linux/arm64
context: scripts/
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
THREADS=4
outputs: type=image,push=true
- name: Save digest
if: github.ref == 'refs/heads/master'
run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt
- name: Save release digest
if: startsWith(github.ref, 'refs/tags/')
run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: digest_arm64
path: /tmp/digest.txt
build:
name: Build
# needs: [amd64_build, x86_build, armv7_build, arm64_build]
needs: [amd64_build, x86_build]
needs: [amd64_build, x86_build, armv7_build, arm64_build]
# needs: [amd64_build, x86_build]
runs-on: ubuntu-latest
steps:
- name: Checkout base

View File

@@ -2,7 +2,7 @@
Utility to convert between various proxy subscription formats.
[![Build Status](https://github.com/asdlokj1qpi23/subconverter/actions/workflows/build.yml/badge.svg)](https://github.com/asdlokj1qpi23/subconverter/actions)
[![Build Status](https://github.com/asdlokj1qpi23/subconverter/actions/workflows/docker.yml/badge.svg)](https://github.com/asdlokj1qpi23/subconverter/actions)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/asdlokj1qpi23/subconverter.svg)](https://github.com/asdlokj1qpi23/subconverter/tags)
[![GitHub release](https://img.shields.io/github/release/asdlokj1qpi23/subconverter.svg)](https://github.com/asdlokj1qpi23/subconverter/releases)
[![GitHub license](https://img.shields.io/github/license/asdlokj1qpi23/subconverter.svg)](https://github.com/tindy2013/subconverter/blob/master/LICENSE)
@@ -61,7 +61,8 @@ services:
| Surge 4 | ✓ | ✓ | surge&ver=4 |
| V2Ray | ✓ | ✓ | v2ray |
| Telegram-liked HTTP/Socks 5 links | ✓ | × | Only as source |
| Singbox | × | ✓ | singbox |
| Singbox | | ✓ | singbox |
Notice:
1. Shadowrocket users should use `ss`, `ssr` or `v2ray` as target.

View File

@@ -382,10 +382,14 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
case ProxyType::Trojan:
singleproxy["type"] = "trojan";
singleproxy["password"] = x.Password;
if (!x.Host.empty())
if (!x.ServerName.empty())
singleproxy["sni"] = x.ServerName;
else if (!x.Host.empty()) {
singleproxy["sni"] = x.Host;
if (std::all_of(x.Password.begin(), x.Password.end(), ::isdigit) && !x.Password.empty())
}
if (std::all_of(x.Password.begin(), x.Password.end(), ::isdigit) && !x.Password.empty()) {
singleproxy["password"].SetTag("str");
}
if (!scv.is_undef())
singleproxy["skip-cert-verify"] = scv.get();
switch (hash_(x.TransferProtocol)) {
@@ -439,12 +443,16 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singleproxy["auth-str"] = x.Auth;
singleproxy["up"] = x.UpMbps;
singleproxy["down"] = x.DownMbps;
if (!tfo.is_undef())
if (!x.Ports.empty()) {
singleproxy["ports"] = x.Ports;
}
if (!tfo.is_undef()) {
singleproxy["fast-open"] = tfo.get();
}
if (!x.FakeType.empty())
singleproxy["protocol"] = x.FakeType;
if (!x.Host.empty())
singleproxy["sni"] = x.Host;
if (!x.ServerName.empty())
singleproxy["sni"] = x.ServerName;
if (!scv.is_undef())
singleproxy["skip-cert-verify"] = scv.get();
if (x.Insecure == "1")
@@ -458,12 +466,16 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singleproxy["type"] = "hysteria2";
singleproxy["password"] = x.Password;
singleproxy["auth"] = x.Password;
if (!x.PublicKey.empty()) {
singleproxy["ca-str"] = x.PublicKey;
}
if (!x.ServerName.empty()) {
singleproxy["sni"] = x.ServerName;
}
if (!x.UpMbps.empty())
singleproxy["up"] = x.UpMbps;
if (!x.DownMbps.empty())
singleproxy["down"] = x.DownMbps;
if (!x.Host.empty())
singleproxy["sni"] = x.Host;
if (!scv.is_undef())
singleproxy["skip-cert-verify"] = scv.get();
if (!x.Alpn.empty())
@@ -481,8 +493,6 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singleproxy["tfo"] = tfo.get();
if (xudp && udp)
singleproxy["xudp"] = true;
if (!x.Host.empty())
singleproxy["servername"] = x.Host;
if (!x.Flow.empty())
singleproxy["flow"] = x.Flow;
if (!scv.is_undef())
@@ -490,6 +500,8 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
if (!x.PublicKey.empty()) {
singleproxy["reality-opts"]["public-key"] = x.PublicKey;
}
if (!x.ServerName.empty())
singleproxy["servername"] = x.ServerName;
if (!x.ShortId.empty()) {
singleproxy["reality-opts"]["short-id"] = x.ShortId;
}
@@ -498,6 +510,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
}
switch (hash_(x.TransferProtocol)) {
case "tcp"_hash:
singleproxy["network"] = x.TransferProtocol;
break;
case "ws"_hash:
singleproxy["network"] = x.TransferProtocol;
@@ -744,7 +757,7 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
processRemark(x.Remark, remarks_list);
std::string &hostname = x.Hostname, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption;
std::string &hostname = x.Hostname, &sni = x.ServerName, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption;
std::string port = std::to_string(x.Port);
bool &tlssecure = x.TLSSecure;
@@ -860,8 +873,11 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
proxy = "trojan, " + hostname + ", " + port + ", password=" + password;
if (x.SnellVersion != 0)
proxy += ", version=" + std::to_string(x.SnellVersion);
if (!host.empty())
if (!sni.empty()) {
proxy += ", sni=" + sni;
} else if (!host.empty()) {
proxy += ", sni=" + host;
}
if (!scv.is_undef())
proxy += ", skip-cert-verify=" + scv.get_str();
break;
@@ -875,6 +891,13 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
if (x.SnellVersion != 0)
proxy += ", version=" + std::to_string(x.SnellVersion);
break;
case ProxyType::Hysteria2:
if (surge_ver < 4 && surge_ver != -3)
continue;
proxy = "hysteria2, " + hostname + ", " + port + ", password=" + password;
if (!scv.is_undef())
proxy += ", skip-cert-verify=" + scv.get_str();
break;
case ProxyType::WireGuard:
if (surge_ver < 4 && surge_ver != -3)
continue;
@@ -990,7 +1013,7 @@ std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &
for (Proxy &x: nodes) {
std::string remark = x.Remark;
std::string &hostname = x.Hostname, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &faketype = x.FakeType;
std::string &hostname = x.Hostname, &sni = x.ServerName, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &faketype = x.FakeType;
bool &tlssecure = x.TLSSecure;
std::string port = std::to_string(x.Port);
std::string aid = std::to_string(x.AlterId);
@@ -1040,8 +1063,11 @@ std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &
continue;
proxyStr = "trojan://" + password + "@" + hostname + ":" + port + "?allowInsecure=" +
(x.AllowInsecure.get() ? "1" : "0");
if (!host.empty())
if (!sni.empty()) {
proxyStr += "&sni=" + sni;
} else if (!host.empty()) {
proxyStr += "&sni=" + host;
}
if (transproto == "ws") {
proxyStr += "&ws=1";
if (!path.empty())
@@ -2163,6 +2189,9 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
if (!x.Plugin.empty() && !x.PluginOption.empty()) {
if (x.Plugin == "simple-obfs")
x.Plugin = "obfs-local";
if (x.Plugin != "obfs-local" && x.Plugin != "v2ray-plugin") {
continue;
}
proxy.AddMember("plugin", rapidjson::StringRef(x.Plugin.c_str()), allocator);
proxy.AddMember("plugin_opts", rapidjson::StringRef(x.PluginOption.c_str()), allocator);
}
@@ -2276,7 +2305,9 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
auto reserved = stringArrayToJsonArray(x.ClientId, ",", allocator);
peer.AddMember("reserved", reserved, allocator);
}
if (!x.Password.empty()) {
proxy.AddMember("pre_shared_key", rapidjson::StringRef(x.Password.c_str()), allocator);
}
rapidjson::Value peers(rapidjson::kArrayType);
peers.PushBack(peer, allocator);
proxy.AddMember("peers", peers, allocator);
@@ -2325,6 +2356,9 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
auto alpns = stringArrayToJsonArray(x.Alpn, ",", allocator);
tls.AddMember("alpn", alpns, allocator);
}
if (!x.ServerName.empty()) {
tls.AddMember("server_name", rapidjson::StringRef(x.ServerName.c_str()), allocator);
}
tls.AddMember("insecure", buildBooleanValue(scv), allocator);
proxy.AddMember("tls", tls, allocator);
}
@@ -2338,12 +2372,18 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
addSingBoxCommonMembers(proxy, x, "hysteria2", allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
if (!x.TLSSecure) {
rapidjson::Value tls(rapidjson::kObjectType);
tls.AddMember("enabled", true, allocator);
if (!x.ServerName.empty())
tls.AddMember("server_name", rapidjson::StringRef(x.ServerName.c_str()), allocator);
if (!x.Alpn.empty()) {
auto alpns = stringArrayToJsonArray(x.Alpn, ",", allocator);
tls.AddMember("alpn", alpns, allocator);
}
if (!x.PublicKey.empty()) {
tls.AddMember("certificate", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
}
tls.AddMember("insecure", buildBooleanValue(scv), allocator);
proxy.AddMember("tls", tls, allocator);
}
@@ -2366,15 +2406,13 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
proxy.AddMember("down_mbps", std::stoi(x.DownMbps), allocator);
}
if (!x.OBFSParam.empty()) {
rapidjson::Value obfs(rapidjson::kObjectType);
obfs.AddMember("type", rapidjson::StringRef(x.OBFSParam.c_str()), allocator);
if (!x.OBFSPassword.empty()) {
proxy.AddMember("obfs", rapidjson::StringRef(std::string(
R"({ "type": )" + x.OBFSParam + ",password: \"" + x.OBFSPassword + "\"}").c_str()),
allocator);
} else {
proxy.AddMember("obfs",
rapidjson::StringRef(std::string(R"({ "type": )" + x.OBFSParam + "}").c_str()),
allocator);
obfs.AddMember("password", rapidjson::StringRef(x.OBFSPassword.c_str()), allocator);
}
proxy.AddMember("obfs", obfs, allocator);
}
break;
}
@@ -2394,10 +2432,6 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
if (x.Type == ProxyType::VLESS) {
rapidjson::Value reality(rapidjson::kObjectType);
if (!x.PublicKey.empty() || !x.ShortId.empty()) {
if (!x.Host.empty()) {
tls.EraseMember("server_name");
tls.AddMember("server_name", rapidjson::StringRef(x.Host.c_str()), allocator);
}
rapidjson::Value utls(rapidjson::kObjectType);
utls.AddMember("enabled", true, allocator);
utls.AddMember("fingerprint", rapidjson::StringRef("chrome"), allocator);
@@ -2406,8 +2440,12 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
if (!x.PublicKey.empty()) {
reality.AddMember("public_key", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
}
auto shortIds = stringArrayToJsonArray(x.Alpn, ",", allocator);
reality.AddMember("short_id", shortIds, allocator);
// auto shortIds = stringArrayToJsonArray(x.ShortId, ",", allocator);
if (!x.ShortId.empty()) {
reality.AddMember("short_id", rapidjson::StringRef(x.ShortId.c_str()), allocator);
} else {
reality.AddMember("short_id", rapidjson::StringRef(""), allocator);
}
tls.AddMember("reality", reality, allocator);
}
}

View File

@@ -109,7 +109,7 @@ struct Proxy {
uint16_t KeepAlive = 0;
String TestUrl;
String ClientId;
String Ports;
String Auth;
String Alpn;
String UpMbps;

View File

@@ -12,6 +12,7 @@
#include "utils/yamlcpp_extra.h"
#include "config/proxy.h"
#include "subparser.h"
#include "utils/logger.h"
using namespace rapidjson;
using namespace rapidjson_ext;
@@ -115,7 +116,8 @@ void httpConstruct(Proxy &node, const std::string &group, const std::string &rem
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &network,
const std::string &host, const std::string &path, const std::string &fp, bool tlssecure,
const std::string &host, const std::string &path, const std::string &fp, const std::string &sni,
bool tlssecure,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13);
@@ -125,6 +127,7 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
node.TransferProtocol = network.empty() ? "tcp" : network;
node.Path = path;
node.Fingerprint = fp;
node.ServerName = sni;
}
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
@@ -156,9 +159,12 @@ void wireguardConstruct(Proxy &node, const std::string &group, const std::string
}
void hysteriaConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &auth,const std::string &auth_str,
const std::string &port, const std::string &type, const std::string &auth,
const std::string &auth_str,
const std::string &host, const std::string &up, const std::string &down, const std::string &alpn,
const std::string &obfsParam, const std::string &insecure, tribool udp, tribool tfo, tribool scv,
const std::string &obfsParam, const std::string &insecure, const std::string &ports,
const std::string &sni, tribool udp,
tribool tfo, tribool scv,
tribool tls13) {
commonConstruct(node, ProxyType::Hysteria, group, remarks, add, port, udp, tfo, scv, tls13);
node.Auth = auth;
@@ -170,6 +176,8 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
node.Insecure = insecure;
node.FakeType = type;
node.AuthStr = auth_str;
node.Ports = ports;
node.ServerName = sni;
}
@@ -177,7 +185,8 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
const std::string &net, const std::string &cipher, const std::string &flow, const std::string &mode,
const std::string &path, const std::string &host, const std::string &edge, const std::string &tls,
const std::string &pbk, const std::string &sid, const std::string &fp, tribool udp, tribool tfo,
const std::string &pbk, const std::string &sid, const std::string &fp, const std::string &sni,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::VLESS, group, remarks, add, port, udp, tfo, scv, tls13);
node.UserId = id.empty() ? "00000000-0000-0000-0000-000000000000" : id;
@@ -191,7 +200,7 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
node.PublicKey = pbk;
node.ShortId = sid;
node.Fingerprint = fp;
node.ServerName = sni;
switch (hash_(net)) {
case "grpc"_hash:
node.Host = host;
@@ -213,7 +222,9 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &password, const std::string &host,
const std::string &up, const std::string &down, const std::string &alpn,
const std::string &obfsParam, const std::string &obfsPassword, tribool udp, tribool tfo,
const std::string &obfsParam, const std::string &obfsPassword, const std::string &sni,
const std::string &publicKey,
tribool udp, tribool tfo,
tribool scv) {
commonConstruct(node, ProxyType::Hysteria2, group, remarks, add, port, udp, tfo, scv, tribool());
node.Password = password;
@@ -223,6 +234,8 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
node.Alpn = alpn;
node.OBFSParam = obfsParam;
node.OBFSPassword = obfsPassword;
node.ServerName = sni;
node.PublicKey = publicKey;
}
void explodeVmess(std::string vmess, Proxy &node) {
@@ -796,7 +809,7 @@ void explodeHTTPSub(std::string link, Proxy &node) {
}
void explodeTrojan(std::string trojan, Proxy &node) {
std::string server, port, psk, addition, group, remark, host, path, network, fp;
std::string server, port, psk, addition, group, remark, host, path, network, fp, sni;
tribool tfo, scv;
if (startsWith(trojan, "trojan://")) {
trojan.erase(0, 9);
@@ -821,6 +834,7 @@ void explodeTrojan(std::string trojan, Proxy &node) {
return;
host = getUrlArg(addition, "sni");
sni = getUrlArg(addition, "sni");
if (host.empty())
host = getUrlArg(addition, "peer");
tfo = getUrlArg(addition, "tfo");
@@ -846,7 +860,7 @@ void explodeTrojan(std::string trojan, Proxy &node) {
if (group.empty())
group = TROJAN_DEFAULT_GROUP;
trojanConstruct(node, group, remark, server, port, psk, network, host, path, fp, true, tribool(), tfo, scv);
trojanConstruct(node, group, remark, server, port, psk, network, host, path, fp, sni, true, tribool(), tfo, scv);
}
void explodeVless(std::string vless, Proxy &node) {
@@ -858,6 +872,7 @@ void explodeVless(std::string vless, Proxy &node) {
void explodeHysteria(std::string hysteria, Proxy &node) {
printf("explodeHysteria\n");
hysteria = regReplace(hysteria, "(hysteria|hy)://", "hysteria://");
if (regMatch(hysteria, "hysteria://(.*?)[:](.*)")) {
explodeStdHysteria(hysteria, node);
return;
@@ -1021,9 +1036,11 @@ void explodeNetch(std::string netch, Proxy &node) {
path = GetMember(json, "Path");
transprot = GetMember(json, "TransferProtocol");
tls = GetMember(json, "TLSSecure");
sni = host;
if (group.empty())
group = TROJAN_DEFAULT_GROUP;
trojanConstruct(node, group, remark, address, port, password, transprot, host, path, fp, tls == "true", udp,
trojanConstruct(node, group, remark, address, port, password, transprot, host, path, fp, sni, tls == "true",
udp,
tfo, scv);
break;
case "Snell"_hash:
@@ -1040,22 +1057,22 @@ void explodeNetch(std::string netch, Proxy &node) {
}
void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
std::string proxytype, ps, server, port, cipher, group, password = "", tempPassword; //common
std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni; //vmess
std::string fp = "chrome", pbk, sid; //vless
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string flow, mode; //trojan
std::string user; //socks
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
std::string obfsPassword;//hysteria2
string_array dns_server;
tribool udp, tfo, scv;
Node singleproxy;
uint32_t index = nodes.size();
const std::string section = yamlnode["proxies"].IsDefined() ? "proxies" : "Proxy";
for (uint32_t i = 0; i < yamlnode[section].size(); i++) {
std::string proxytype, ps, server, port, cipher, group, password = "", ports, tempPassword; //common
std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni; //vmess
std::string fp = "chrome", pbk, sid; //vless
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string flow, mode; //trojan
std::string user; //socks
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
std::string obfsPassword;//hysteria2
string_array dns_server;
tribool udp, tfo, scv;
Proxy node;
singleproxy = yamlnode[section][i];
singleproxy["type"] >>= proxytype;
@@ -1068,9 +1085,11 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
scv = safe_as<std::string>(singleproxy["skip-cert-verify"]);
switch (hash_(proxytype)) {
case "vmess"_hash:
group = V2RAY_DEFAULT_GROUP;
singleproxy["uuid"] >>= id;
if (id.length() < 36) {
break;
}
group = V2RAY_DEFAULT_GROUP;
singleproxy["alterId"] >>= aid;
singleproxy["cipher"] >>= cipher;
net = singleproxy["network"].IsDefined() ? safe_as<std::string>(singleproxy["network"]) : "tcp";
@@ -1212,6 +1231,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
group = TROJAN_DEFAULT_GROUP;
singleproxy["password"] >>= password;
singleproxy["sni"] >>= host;
singleproxy["sni"] >>= sni;
singleproxy["network"] >>= net;
switch (hash_(net)) {
case "grpc"_hash:
@@ -1226,7 +1246,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
break;
}
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, true, udp, tfo, scv);
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, true, udp, tfo, scv);
break;
case "snell"_hash:
group = SNELL_DEFAULT_GROUP;
@@ -1300,7 +1320,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["flow"] >>= flow;
vlessConstruct(node, XRAY_DEFAULT_GROUP, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp);
host, "", tls, pbk, sid, fp, sni);
break;
case "hysteria"_hash:
group = HYSTERIA_DEFAULT_GROUP;
@@ -1318,8 +1338,10 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["sni"] >> host;
singleproxy["alpn"][0] >> alpn;
singleproxy["protocol"] >> insecure;
hysteriaConstruct(node, group, ps, server, port, type, auth,"", host, up, down, alpn, obfsParam, insecure,
singleproxy["ports"] >> ports;
sni = host;
hysteriaConstruct(node, group, ps, server, port, type, auth, "", host, up, down, alpn, obfsParam,
insecure, ports, sni,
udp, tfo, scv);
break;
case "hysteria2"_hash:
@@ -1333,9 +1355,9 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["obfs-password"] >>= obfsPassword;
singleproxy["sni"] >>= host;
singleproxy["alpn"][0] >>= alpn;
sni = host;
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, udp, tfo, scv);
obfsPassword, sni, public_key, udp, tfo, scv);
break;
default:
continue;
@@ -1389,7 +1411,7 @@ void explodeStdVMess(std::string vmess, Proxy &node) {
void explodeStdHysteria(std::string hysteria, Proxy &node) {
std::string add, port, type, auth, host, insecure, up, down, alpn, obfsParam, remarks,auth_str;
std::string add, port, type, auth, host, insecure, up, down, alpn, obfsParam, remarks, auth_str, sni;
std::string addition;
hysteria = hysteria.substr(11);
string_size pos;
@@ -1411,16 +1433,19 @@ void explodeStdHysteria(std::string hysteria, Proxy &node) {
down = getUrlArg(addition, "downmbps");
alpn = getUrlArg(addition, "alpn");
obfsParam = getUrlArg(addition, "obfsParam");
sni = getUrlArg(addition, "peer");
if (remarks.empty())
remarks = add + ":" + port;
hysteriaConstruct(node, HYSTERIA_DEFAULT_GROUP, remarks, add, port, type, auth,auth_str, host, up, down, alpn, obfsParam,
insecure);
hysteriaConstruct(node, HYSTERIA_DEFAULT_GROUP, remarks, add, port, type, auth, auth_str, host, up, down, alpn,
obfsParam,
insecure, "", sni);
return;
}
void explodeStdHysteria2(std::string hysteria2, Proxy &node) {
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks;
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks, sni;
std::string addition;
tribool scv;
hysteria2 = hysteria2.substr(12);
@@ -1460,18 +1485,18 @@ void explodeStdHysteria2(std::string hysteria2, Proxy &node) {
obfsParam = getUrlArg(addition, "obfs");
obfsPassword = getUrlArg(addition, "obfs-password");
host = getUrlArg(addition, "sni");
sni = getUrlArg(addition, "sni");
if (remarks.empty())
remarks = add + ":" + port;
hysteria2Construct(node, HYSTERIA2_DEFAULT_GROUP, remarks, add, port, password, host, up, down, alpn, obfsParam,
obfsPassword, tribool(), tribool(), scv);
obfsPassword, host, "", tribool(), tribool(), scv);
return;
}
void explodeStdVless(std::string vless, Proxy &node) {
std::string add, port, type, id, aid, net, flow, pbk, sid, fp, mode, path, host, tls, remarks;
std::string add, port, type, id, aid, net, flow, pbk, sid, fp, mode, path, host, tls, remarks, sni;
std::string addition;
vless = vless.substr(8);
string_size pos;
@@ -1516,9 +1541,9 @@ void explodeStdVless(std::string vless, Proxy &node) {
if (remarks.empty())
remarks = add + ":" + port;
sni = getUrlArg(addition, "sni");
vlessConstruct(node, XRAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", flow, mode, path, host, "",
tls, pbk, sid, fp);
tls, pbk, sid, fp, sni);
return;
}
@@ -1655,7 +1680,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
const std::string proxystr = "(.*?)\\s*=\\s*(.*)";
for (auto &x: proxies) {
std::string remarks, server, port, method, username, password; //common
std::string remarks, server, port, method, username, password, sni; //common
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, mod_url, mod_md5; //ss
std::string id, net, tls, host, edge, path, fp; //v2
std::string protocol, protoparam; //ssr
@@ -1926,6 +1951,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
break;
case "sni"_hash:
host = itemVal;
sni = itemVal;
break;
case "udp-relay"_hash:
udp = itemVal;
@@ -1944,7 +1970,8 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
}
}
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", fp, true,
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", fp, sni,
true,
udp,
tfo, scv);
break;
@@ -2233,6 +2260,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
break;
case "tls-host"_hash:
host = itemVal;
sni = itemVal;
break;
case "udp-relay"_hash:
udp = itemVal;
@@ -2257,6 +2285,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
remarks = server + ":" + port;
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", fp,
sni,
tls == "true", udp, tfo, scv, tls13);
break;
case "http"_hash: //quantumult x style http links
@@ -2443,6 +2472,237 @@ int explodeConfContent(const std::string &content, std::vector<Proxy> &nodes) {
return !nodes.empty();
}
void explodeSingboxTransport(rapidjson::Value &singboxNode, std::string &net, std::string &host, std::string &path,
std::string edge) {
if (singboxNode.HasMember("transport") && singboxNode["transport"].IsObject()) {
rapidjson::Value transport = singboxNode["transport"].GetObject();
net = GetMember(transport, "type");
switch (hash_(net)) {
case "http"_hash: {
host = GetMember(transport, "host");
break;
}
case "ws"_hash: {
path = GetMember(transport, "path");
if (transport.HasMember("headers") && transport["headers"].IsObject()) {
rapidjson::Value headers = transport["headers"].GetObject();
host = GetMember(headers, "Host");
edge = GetMember(headers, "Edge");
}
break;
}
case "grpc"_hash: {
path = GetMember(transport, "service_name");
break;
}
default:
net = "tcp";
path.clear();
break;
}
} else {
net = "tcp";
host.clear();
edge.clear();
path.clear();
}
}
void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
uint32_t index = nodes.size();
for (rapidjson::SizeType i = 0; i < outbounds.Size(); ++i) {
if (outbounds[i].IsObject()) {
std::string proxytype, ps, server, port, cipher, group, password, ports, tempPassword; //common
std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni; //vmess
std::string fp = "chrome", pbk, sid; //vless
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string flow, mode; //trojan
std::string user; //socks
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
std::string obfsPassword;//hysteria2
string_array dns_server;
tribool udp, tfo, scv;
rapidjson::Value singboxNode = outbounds[i].GetObject();
if (singboxNode.HasMember("type") && singboxNode["type"].IsString()) {
Proxy node;
proxytype = singboxNode["type"].GetString();
ps = GetMember(singboxNode, "tag");
server = GetMember(singboxNode, "server");
port = GetMember(singboxNode, "server_port");
tfo = GetMember(singboxNode, "tcp_fast_open");
if (singboxNode.HasMember("tls") && singboxNode["tls"].IsObject()) {
rapidjson::Value tlsObj = singboxNode["tls"].GetObject();
if (tlsObj.HasMember("enabled") && tlsObj["enabled"].IsBool() && tlsObj["enabled"].GetBool()) {
tls = "tls";
}
sni = GetMember(tlsObj, "server_name");
if (tlsObj.HasMember("alpn") && tlsObj["alpn"].IsArray() && !tlsObj["alpn"].Empty()) {
rapidjson::Value alpns = tlsObj["alpn"].GetArray();
if (alpns.Size() > 0) {
alpn = alpns[0].GetString();
}
}
if (tlsObj.HasMember("insecure") && tlsObj["insecure"].IsBool()) {
scv = tlsObj["insecure"].GetBool();
}
if (tlsObj.HasMember("certificate") && tlsObj["certificate"].IsString()) {
public_key = tlsObj["certificate"].GetString();
}
if (tlsObj.HasMember("reality") && tlsObj["reality"].IsObject()) {
tls = "reality";
rapidjson::Value reality = tlsObj["reality"].GetObject();
if (reality.HasMember("server_name") && reality["server_name"].IsString()) {
host = reality["server_name"].GetString();
}
if (reality.HasMember("public_key") && reality["public_key"].IsString()) {
pbk = reality["public_key"].GetString();
}
if (reality.HasMember("short_id") && reality["short_id"].IsString()) {
sid = reality["short_id"].GetString();
}
}
} else {
tls = "false";
}
switch (hash_(proxytype)) {
case "vmess"_hash:
group = V2RAY_DEFAULT_GROUP;
id = GetMember(singboxNode, "uuid");
if (id.length() < 36) {
break;
}
aid = GetMember(singboxNode, "alter_id");
cipher = GetMember(singboxNode, "security");
explodeSingboxTransport(singboxNode, net, host, path, edge);
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls,
sni, udp,
tfo, scv);
break;
case "shadowsocks"_hash:
group = SS_DEFAULT_GROUP;
cipher = GetMember(singboxNode, "method");
password = GetMember(singboxNode, "password");
plugin = GetMember(singboxNode, "plugin");
pluginopts = GetMember(singboxNode, "plugin_opts");
ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv);
break;
case "trojan"_hash:
group = TROJAN_DEFAULT_GROUP;
password = GetMember(singboxNode, "password");
explodeSingboxTransport(singboxNode, net, host, path, edge);
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, true, udp,
tfo,
scv);
break;
case "vless"_hash:
group = XRAY_DEFAULT_GROUP;
id = GetMember(singboxNode, "uuid");
flow = GetMember(singboxNode, "flow");
if (singboxNode.HasMember("transport") && singboxNode["transport"].IsObject()) {
rapidjson::Value transport = singboxNode["transport"].GetObject();
net = GetMember(transport, "type");
switch (hash_(net)) {
case "tcp"_hash: {
break;
}
case "ws"_hash: {
path = GetMember(transport, "path");
if (transport.HasMember("headers") && transport["headers"].IsObject()) {
rapidjson::Value headers = transport["headers"].GetObject();
host = GetMember(headers, "Host");
edge = GetMember(headers, "Edge");
}
break;
}
case "http"_hash: {
host = GetMember(transport, "host");
path = GetMember(transport, "path");
edge.clear();
break;
}
case "httpupgrade"_hash: {
net = "h2";
host = GetMember(transport, "host");
path = GetMember(transport, "path");
edge.clear();
break;
}
case "grpc"_hash: {
host = server;
path = GetMember(transport, "service_name");
break;
}
}
}
vlessConstruct(node, group, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp, sni);
break;
case "http"_hash:
password = GetMember(singboxNode, "password");
user = GetMember(singboxNode, "username");
httpConstruct(node, group, ps, server, port, user, password, tls == "tls", tfo, scv);
break;
case "wireguard"_hash:
group = WG_DEFAULT_GROUP;
ip = GetMember(singboxNode, "inet4_bind_address");
ipv6 = GetMember(singboxNode, "inet6_bind_address");
public_key = GetMember(singboxNode, "private_key");
private_key = GetMember(singboxNode, "public_key");
mtu = GetMember(singboxNode, "mtu");
password = GetMember(singboxNode, "pre_shared_key");
dns_server = {"8.8.8.8"};
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp);
break;
case "socks"_hash:
group = SOCKS_DEFAULT_GROUP;
user = GetMember(singboxNode, "username");
password = GetMember(singboxNode, "password");
socksConstruct(node, group, ps, server, port, user, password);
break;
case "hysteria"_hash:
group = HYSTERIA_DEFAULT_GROUP;
up = GetMember(singboxNode, "up");
if (up.empty()) {
up = GetMember(singboxNode, "up_mbps");
}
down = GetMember(singboxNode, "down");
if (down.empty()) {
down = GetMember(singboxNode, "down_mbps");
}
auth = GetMember(singboxNode, "auth_str");
type = GetMember(singboxNode, "network");
obfsParam = GetMember(singboxNode, "obfs");
hysteriaConstruct(node, group, ps, server, port, type, auth, "", host, up, down, alpn,
obfsParam, insecure, ports, sni,
udp, tfo, scv);
break;
case "hysteria2"_hash:
group = HYSTERIA2_DEFAULT_GROUP;
password = GetMember(singboxNode, "password");
up = GetMember(singboxNode, "up");
down = GetMember(singboxNode, "down");
if (singboxNode.HasMember("obfs") && singboxNode["obfs"].IsObject()) {
rapidjson::Value obfsOpt = singboxNode["obfs"].GetObject();
obfsParam = GetMember(obfsOpt, "type");
obfsPassword = GetMember(obfsOpt, "password");
}
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, sni,public_key, udp, tfo, scv);
break;
default:
continue;
}
node.Id = index;
nodes.emplace_back(std::move(node));
index++;
}
}
}
}
void explode(const std::string &link, Proxy &node) {
if (startsWith(link, "ssr://"))
explodeSSR(link, node);
@@ -2460,7 +2720,7 @@ void explode(const std::string &link, Proxy &node) {
explodeTrojan(link, node);
else if (strFind(link, "vless://") || strFind(link, "vless1://"))
explodeVless(link, node);
else if (strFind(link, "hysteria://"))
else if (strFind(link, "hysteria://") || strFind(link, "hy://"))
explodeHysteria(link, node);
else if (strFind(link, "hysteria2://") || strFind(link, "hy2://"))
explodeHysteria2(link, node);
@@ -2495,7 +2755,33 @@ void explodeSub(std::string sub, std::vector<Proxy> &nodes) {
//ignore
throw;
}
try {
std::string pattern = "\"?(inbounds)\"?:";
if (!processed &&
regFind(sub, pattern)) {
pattern = "\"?(outbounds)\"?:";
if (regFind(sub, pattern)) {
pattern = "\"?(route)\"?:";
if (regFind(sub, pattern)) {
rapidjson::Document document;
document.Parse(sub.c_str());
if (!document.HasParseError() || document.IsObject()) {
rapidjson::Value &value = document["outbounds"];
if (value.IsArray() && !value.Empty()) {
explodeSingbox(value, nodes);
processed = true;
}
}
}
}
}
}
catch (std::exception &e) {
writeLog(LOG_TYPE_ERROR, e.what(), LOG_LEVEL_ERROR);
//writeLog(0, e.what(), LOG_LEVEL_DEBUG);
//ignore
throw;
}
//try to parse as surge configuration
if (!processed && explodeSurge(sub, nodes)) {
processed = true;

View File

@@ -5,8 +5,7 @@
#include "config/proxy.h"
enum class ConfType
{
enum class ConfType {
Unknow,
SS,
SSR,
@@ -19,36 +18,104 @@ enum class ConfType
SUB,
Local
};
void hysteriaConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add, const std::string &port, const std::string &type, const std::string &auth, const std::string &auth_str, const std::string &host, const std::string &up, const std::string &down, const std::string &alpn, const std::string &obfsParam, const std::string &insecure ,tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add, const std::string &port, const std::string &password, const std::string &host, const std::string &up, const std::string &down, const std::string &alpn, const std::string &obfsParam, const std::string &obfsPassword, const std::string &insecure ,tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void vlessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add, const std::string &port, const std::string &type, const std::string &id, const std::string &aid, const std::string &net, const std::string &cipher, const std::string &flow, const std::string &mode, const std::string &path, const std::string &host, const std::string &edge, const std::string &tls,const std::string &pkd, const std::string &sid, const std::string &fp, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void vmessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add, const std::string &port, const std::string &type, const std::string &id, const std::string &aid, const std::string &net, const std::string &cipher, const std::string &path, const std::string &host, const std::string &edge, const std::string &tls, const std::string &sni, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &protocol, const std::string &method, const std::string &obfs, const std::string &password, const std::string &obfsparam, const std::string &protoparam, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &method, const std::string &plugin, const std::string &pluginopts, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &network, const std::string &host, const std::string &path,const std::string &fp, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &obfs, const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
void hysteriaConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &auth,
const std::string &auth_str, const std::string &host, const std::string &up,
const std::string &down, const std::string &alpn, const std::string &obfsParam,
const std::string &insecure, const std::string &ports, const std::string &sni,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &password, const std::string &host,
const std::string &up, const std::string &down, const std::string &alpn,
const std::string &obfsParam, const std::string &obfsPassword, const std::string &sni,
const std::string &publicKey,
tribool udp, tribool tfo,
tribool scv);
void vlessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
const std::string &net, const std::string &cipher, const std::string &flow, const std::string &mode,
const std::string &path, const std::string &host, const std::string &edge, const std::string &tls,
const std::string &pkd, const std::string &sid, const std::string &fp, const std::string &sni,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
void vmessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
const std::string &net, const std::string &cipher, const std::string &path, const std::string &host,
const std::string &edge, const std::string &tls, const std::string &sni, tribool udp = tribool(),
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &protocol, const std::string &method,
const std::string &obfs, const std::string &password, const std::string &obfsparam,
const std::string &protoparam, tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool());
void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &method,
const std::string &plugin, const std::string &pluginopts, tribool udp = tribool(),
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password, bool tls,
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &network,
const std::string &host, const std::string &path, const std::string &fp, const std::string &sni,
bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &obfs,
const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool());
void explodeVmess(std::string vmess, Proxy &node);
void explodeSSR(std::string ssr, Proxy &node);
void explodeSS(std::string ss, Proxy &node);
void explodeTrojan(std::string trojan, Proxy &node);
void explodeQuan(const std::string &quan, Proxy &node);
void explodeStdVMess(std::string vmess, Proxy &node);
void explodeStdVless(std::string vless, Proxy &node);
void explodeStdHysteria(std::string hysteria, Proxy &node);
void explodeStdHysteria2(std::string hysteria2, Proxy &node);
void explodeShadowrocket(std::string kit, Proxy &node);
void explodeKitsunebi(std::string kit, Proxy &node);
void explodeVless(std::string vless, Proxy &node);
void explodeHysteria(std::string hysteria, Proxy &node);
void explodeHysteria2(std::string hysteria2, Proxy &node);
/// Parse a link
void explode(const std::string &link, Proxy &node);
void explodeSSD(std::string link, std::vector<Proxy> &nodes);
void explodeSub(std::string sub, std::vector<Proxy> &nodes);
int explodeConf(const std::string &filepath, std::vector<Proxy> &nodes);
int explodeConfContent(const std::string &content, std::vector<Proxy> &nodes);
#endif // SUBPARSER_H_INCLUDED

View File

@@ -5,11 +5,9 @@
#include <map>
#include <string.h>
struct strICaseComp
{
bool operator() (const std::string &lhs, const std::string &rhs) const
{
return strcasecmp(lhs.c_str(), rhs.c_str());
struct strICaseComp {
bool operator()(const std::string &lhs, const std::string &rhs) const {
return strcasecmp(lhs.c_str(), rhs.c_str()) > 0;
}
};

View File

@@ -1,6 +1,6 @@
#ifndef VERSION_H_INCLUDED
#define VERSION_H_INCLUDED
#define VERSION "v0.9.0"
#define VERSION "v0.9.3"
#endif // VERSION_H_INCLUDED