Compare commits

..

108 Commits

Author SHA1 Message Date
asdlokj1qpi23
3971468034 Update subexport.cpp
Some checks failed
GitHub CI / macOS ${{ matrix.arch }} Build (arm, subconverter_darwinarm, macos-14) (push) Waiting to run
GitHub CI / macOS ${{ matrix.arch }} Build (x86, subconverter_darwin64, macos-13) (push) Waiting to run
GitHub CI / Windows ${{ matrix.arch }} Build (amd64, subconverter_win64, x86_64, MINGW64) (push) Waiting to run
GitHub CI / Windows ${{ matrix.arch }} Build (x86, subconverter_win32, i686, MINGW32) (push) Waiting to run
GitHub CI / Linux ${{ matrix.arch }} Build (aarch64, subconverter_aarch64, ubuntu-latest) (push) Failing after 38s
GitHub CI / Linux ${{ matrix.arch }} Build (amd64, subconverter_linux64, ubuntu-latest) (push) Failing after 16s
GitHub CI / Linux ${{ matrix.arch }} Build (armv7, subconverter_armv7, ubuntu-latest) (push) Failing after 19s
GitHub CI / Linux ${{ matrix.arch }} Build (x86, subconverter_linux32, ubuntu-latest) (push) Failing after 22s
Publish Docker Image / Build ${{ matrix.platform }} Image (ubuntu-latest, linux/386) (push) Failing after 6m49s
Publish Docker Image / Build ${{ matrix.platform }} Image (ubuntu-latest, linux/arm/v7) (push) Has been cancelled
Publish Docker Image / Build ${{ matrix.platform }} Image (ubuntu-latest, linux/arm64) (push) Has been cancelled
Publish Docker Image / Merge (push) Has been cancelled
Publish Docker Image / Build ${{ matrix.platform }} Image (ubuntu-latest, linux/amd64) (push) Has been cancelled
2025-03-25 23:23:37 +08:00
asdlokj1qpi23
75a7b1c84c fix windows build error 2025-03-25 19:00:21 +08:00
asdlokj1qpi23
4ee3e11950 fix windows build error 2025-03-25 18:51:53 +08:00
asdlokj1qpi23
68f2f3bb56 fix windows build error 2025-03-25 18:41:14 +08:00
asdlokj1qpi23
79b2e31096 fix windows build error 2025-03-25 18:25:57 +08:00
asdlokj1qpi23
d5e6159fbd fix windows build error 2025-03-25 18:07:08 +08:00
asdlokj1qpi23
eec5113947 fix windows build error 2025-03-25 17:54:07 +08:00
asdlokj1qpi23
695f5eb6d7 fix windows build error 2025-03-25 17:45:08 +08:00
asdlokj1qpi23
a0ad2b46e0 fix windows build error 2025-03-25 17:35:30 +08:00
asdlokj1qpi23
2b0011a127 fix windows build error 2025-03-25 17:27:28 +08:00
asdlokj1qpi23
f69597efb7 Merge pull request #17 from brillcn/master
Update ruleconvert.cpp
2025-03-25 16:56:30 +08:00
asdlokj1qpi23
ffbd262aae fix bug (#11) 2025-03-25 16:41:46 +08:00
asdlokj1qpi23
3ea867e4b8 fix actions error 2025-03-25 15:02:07 +08:00
asdlokj1qpi23
090c2def1d merge tindy2013 2025-03-25 14:55:22 +08:00
asdlokj1qpi23
e88f8fd485 Merge remote-tracking branch 'fork/master' into dev
# Conflicts:
#	.github/workflows/build.yml
#	.github/workflows/docker.yml
#	.gitignore
#	base/pref.example.toml
#	base/snippets/emoji.toml
#	base/snippets/emoji.txt
#	scripts/build.macos.release.sh
#	scripts/build.windows.release.sh
#	scripts/rules_config.conf
#	src/generator/config/subexport.cpp
#	src/handler/interfaces.cpp
#	src/handler/settings.cpp
#	src/parser/config/proxy.h
#	src/parser/subparser.cpp
#	src/parser/subparser.h
#	src/utils/map_extra.h
#	src/version.h
2025-03-25 14:08:43 +08:00
BrilliantChen
292850818a Update ruleconvert.cpp
support meta all rules
2025-01-24 17:32:20 +08:00
Tindy X
92f66bf5b5 Fix Clash classical rule provider not renaming properly 2025-01-16 18:08:34 +08:00
Tindy X
b39de30db9 Update toml11 to v4.3.0 in Dockerfile 2025-01-16 17:31:30 +08:00
Tindy X
223d75a10a Fix Clash rule provider did not trim domains and ip-cidrs 2025-01-16 17:29:46 +08:00
Tindy X
691193731f Update toml11 to v4.3.0 2025-01-16 17:26:52 +08:00
Tindy X
05959b09b4 Url-decode file name before adding as Clash rule provider (#815) 2025-01-16 17:11:45 +08:00
Tindy X
3f5ed82672 Add CORS header to httplib webserver 2024-12-31 15:38:56 +08:00
Fanx
05910ac5dd Update Flag category (#810) 2024-12-31 15:37:24 +08:00
Tindy X
1d56f44696 Add TCP Fast Open option to Clash configs 2024-12-08 22:27:01 +08:00
Lai Zn
c207bfc1f0 Add Hysteria & Hysteria 2 support (#731)
* feat: add hysteria & hysteria 2 support

* Fix build error

* Remove deleted rules repository

---------

Co-authored-by: Tindy X <49061470+tindy2013@users.noreply.github.com>
2024-11-29 01:00:26 +08:00
TAKO
3a8762c307 update .gitignore 2024-10-28 10:57:30 +08:00
asdlokj1qpi23
bc7e2c2e94 Merge pull request #3 from FanxJK/master
Update Flag category
2024-10-28 10:23:33 +08:00
Fanx
ad47d18a23 Update Flag category 2024-10-25 19:09:18 +08:00
star
79a7e888b1 Add underlying-proxy, smart policy group support for surge and renaming surge wireguard section (#747)
* Use short hash of wireguard name for surge section name
Add underlying-proxy support for clash parser and surge exporter

* Add surge smart group support

* Allow clash to fallback to url-test in smart proxygroup

* Fix duplicate break statement in binding.h
2024-09-30 06:39:23 +08:00
asdlokj1qpi23
a1f919eafb update version and docs. 2024-08-30 10:28:16 +08:00
asdlokj1qpi23
33f32deb32 fix actions error 2024-08-29 18:45:59 +08:00
asdlokj1qpi23
258a64ed4f update doc 2024-08-29 17:49:37 +08:00
asdlokj1qpi23
7e16236595 update doc 2024-08-29 17:41:22 +08:00
TioaChan
644b9040b9 Add timezone env to Docker image (#776) 2024-08-27 17:34:01 +08:00
ak1ra
3f2281e284 Add clash.external_controller option in config file (#772) 2024-08-27 17:33:17 +08:00
SpadeLushen
0c11565cc9 Use Proxy.Host as alternative tls.server_name in sing-box to support Trojan's sni (#777)
Co-authored-by: Spade Lushen <7971040+SpadeLushen@users.noreply.github.com>
2024-08-27 17:33:02 +08:00
asdlokj1qpi23
4e6e25c710 Fix short-id issues.Add udp and packet-encoding config for vless.(#33) 2024-07-26 13:16:08 +08:00
asdlokj1qpi23
7dec83d529 Fix alpn issues.(#30) 2024-07-25 10:53:56 +08:00
asdlokj1qpi23
c4aa8c5b5e Fix bug.(#30) 2024-07-23 19:25:41 +08:00
asdlokj1qpi23
e22f043213 Resolve the priority issue with SCV,UDP parameters.(#29) 2024-07-19 11:30:04 +08:00
asdlokj1qpi23
e9c39481df Add insecure for tuic in singbox. 2024-07-18 09:28:13 +08:00
asdlokj1qpi23
6854ea4923 Fix windows compilation error.(#26) 2024-07-17 14:34:19 +08:00
asdlokj1qpi23
dc5c13c76c Fix windows compilation error. 2024-07-17 14:33:44 +08:00
asdlokj1qpi23
5f644b0b08 Change windows script. 2024-07-17 14:19:06 +08:00
asdlokj1qpi23
73352ecb43 Change windows script. 2024-07-17 11:26:07 +08:00
asdlokj1qpi23
34adb36029 Change windows script. 2024-07-17 11:17:26 +08:00
asdlokj1qpi23
311c696c1d Change windows script. 2024-07-17 11:06:47 +08:00
asdlokj1qpi23
33660d7f1b Change windows script. 2024-07-17 10:44:49 +08:00
asdlokj1qpi23
0844ebcae7 Change windows script. 2024-07-16 17:38:01 +08:00
asdlokj1qpi23
27e82ca60c Change windows script. 2024-07-16 17:29:33 +08:00
asdlokj1qpi23
bd06896454 Change windows script. 2024-07-16 17:13:22 +08:00
asdlokj1qpi23
72ea8a098f Change windows script. 2024-07-16 16:55:22 +08:00
asdlokj1qpi23
456fc328d5 Change windows script. 2024-07-16 16:45:41 +08:00
asdlokj1qpi23
19fcccf7f8 Change windows script. 2024-07-16 16:36:49 +08:00
asdlokj1qpi23
e3101cfa5e Change windows script. 2024-07-16 16:16:33 +08:00
asdlokj1qpi23
198fe253d1 Change scripts toml11 version. 2024-07-16 15:59:12 +08:00
asdlokj1qpi23
3589cfd615 Fix windows sh remove curl and test. 2024-07-16 15:28:00 +08:00
asdlokj1qpi23
c204199477 Fix windows sh. 2024-07-16 14:55:05 +08:00
asdlokj1qpi23
dbba931701 Fix bugs for tuic in Clash.(#23) 2024-07-16 14:22:28 +08:00
asdlokj1qpi23
ee9b239e21 Fix bugs for tuic in Singbox.(#23) 2024-07-15 09:33:54 +08:00
asdlokj1qpi23
c56685fd40 Add TUIC protocol support to Clash and Singbox.(#23) 2024-07-12 21:56:29 +08:00
asdlokj1qpi23
3b2a2632d9 Fix vless bug for Quanx.(#16) 2024-07-12 15:41:44 +08:00
asdlokj1qpi23
c359424242 fix build issue. 2024-06-27 17:10:16 +08:00
asdlokj1qpi23
4d0ed9a105 v0.9.5 2024-06-27 15:16:27 +08:00
asdlokj1qpi23
63eee92062 Edit docs. 2024-06-25 16:38:43 +08:00
asdlokj1qpi23
b9b864cf51 Hy2 supports obtaining port hopping parameters from a link. 2024-06-19 14:56:59 +08:00
asdlokj1qpi23
bdd6bbf67a Fix Issue.Add default value.(#22) 2024-06-19 10:41:55 +08:00
asdlokj1qpi23
8a18d3564b Fix Issue.(#22) 2024-06-17 11:28:12 +08:00
asdlokj1qpi23
2ee7c3aa04 Fix Actions Issue.(#22) 2024-06-14 09:30:37 +08:00
asdlokj1qpi23
598f6ac414 Fix Bug.(#22) 2024-06-13 17:30:34 +08:00
asdlokj1qpi23
6c296bfbf2 Add Hy2 for Loon.(#22) 2024-06-13 17:29:22 +08:00
asdlokj1qpi23
43fc751a2d fix bugs.(#16) 2024-05-22 09:41:37 +08:00
asdlokj1qpi23
99c1ef8b1a Support vless for quanx.(#16) 2024-05-17 09:59:48 +08:00
asdlokj1qpi23
53b561bce7 Fix github actions. 2024-05-09 16:50:20 +08:00
asdlokj1qpi23
469feaf0f5 Fix github actions. 2024-05-09 16:34:20 +08:00
asdlokj1qpi23
0895a16876 Fix the bug related to certificate validation in the Hysteria2 protocol.(#17) 2024-05-09 15:34:06 +08:00
TAKO
6974910734 Update Flag category (#744)
* Update emoji.toml

* Update emoji.txt
2024-04-18 15:47:39 +08:00
Tindy X
0c8574755a Enhancements
Fix not properly handling data from multipart-form POST (#739).
Fix not cleaning up request parameters when generating profiles (#741).
2024-04-09 01:11:29 +08:00
Tindy X
b9ad0c2ee2 Bump version to v0.9.0 2024-04-08 16:31:25 +08:00
Tindy X
04ac98725c Add clash_api to default sing-box config base 2024-04-08 16:21:29 +08:00
Tindy X
6af2c56fc8 Do not add check-interval and tolerance to SSID groups in QuanX configs 2024-04-06 21:30:10 +08:00
Tindy X
fb6a830d7b Add lhie1 rules to auto update config 2024-04-06 19:21:00 +08:00
Tindy X
b82d49200d Fix update_rules checkout branch 2024-04-06 19:04:51 +08:00
Tindy X
40ba3fd970 Update rules updater script 2024-04-06 18:56:52 +08:00
Tindy X
1f57413025 Fix Linux self-hosted build 2024-04-05 21:48:03 +08:00
Tindy X
b228255d3b Update build script 2024-04-05 21:46:04 +08:00
Tindy X
55e765e7f9 Fix broken string split (#736 #737 #738) 2024-04-05 14:55:24 +08:00
Tindy X
535d1d01e1 Fix "Profile not found" when generating artifact (#719) 2024-04-03 19:55:38 +08:00
Tindy X
7fdba81f2c Fix implementation of getting random string (#726) 2024-04-03 19:43:33 +08:00
Tindy X
6c38710312 Add missing libraries 2024-04-03 19:16:13 +08:00
Tindy X
eeffa0f544 Use brew provided path for libraries on macOS 2024-04-03 19:13:12 +08:00
Tindy X
73da1a87ad Run with sudo when building for macOS 2024-04-03 18:57:30 +08:00
Tindy X
670544cfb1 Add macOS ARM build 2024-04-03 18:50:35 +08:00
Tindy X
4864a6b13c Support setting output style for proxy groups in Clash configs (#734) 2024-04-03 18:07:12 +08:00
Chi Zhang
cb15d568c0 Fix missing classical rulesets when exporting Clash configs with expand=false (#715)
* 尝试修正缺少RULE-SET问题
2024-04-03 17:15:35 +08:00
Tindy X
0f2cefd537 Enhancements
Read template_args from root in TOML preferences (#717).
Make max_workers work for httplib.
Fix implementation of str_icase_map for HTTP headers.
2024-04-03 17:09:21 +08:00
Tindy X
9e66b07251 Force delete 2024-04-03 16:45:05 +08:00
Tindy X
624f5cd120 Clean up digests before creating new image digest 2024-04-03 16:40:41 +08:00
Tindy X
c711f1ad05 Update Docker build workflow 2024-04-03 16:24:31 +08:00
Tindy X
88635b6ed8 Fix build error 2024-04-03 16:08:19 +08:00
Tindy X
0cb4053f8d Fix build error 2024-04-03 16:01:59 +08:00
Tindy X
fb2aca3237 * Fix Docker build 2024-04-03 15:51:20 +08:00
SummonHIM
37c4e13071 Add UA of Clash Verge to auto target (#713) 2024-04-02 18:37:09 +08:00
moexiami
623ffbb23f Set most node_pref settings to indeterminate by default (#728)
Settings within node_pref should be established with a thorough understanding of the subscription sources' configurations.
Additionally, defaulting skip_cert_verify_flag to true exposes security risks.

Since pref.example.toml serves as the default configuration file, it is suggested to reset these settings. Also moving us toward Secure-by-Default.

Signed-off-by: moexiami <i@f2light.com>
2024-04-02 18:34:50 +08:00
aylz10
be2de49360 Fix bug of request header forwarding (#709)
* Fix bug of request header forwarding

* Replace insert(make_pair()) with emplace()

---------

Co-authored-by: Tindy X <49061470+tindy2013@users.noreply.github.com>
2024-04-02 18:34:33 +08:00
asdlokj1qpi23
a8292b1fc6 Add support for Hysteria2 ports. 2024-03-13 18:12:36 +08:00
asdlokj1qpi23
1ff018c47b update docker actions 2024-03-13 10:23:15 +08:00
Tindy X
eef5328506 Enhancements
Refine libcurl logs.
Do not retry web request on API mode.
Optimize codes.
2023-12-22 14:46:52 +08:00
40 changed files with 1869 additions and 1398 deletions

View File

@@ -1,224 +1,150 @@
name: GitHub CI
on:
on:
push:
branches: [ master ]
tags:
- '**'
workflow_dispatch:
pull_request:
concurrency:
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
jobs:
linux32_build:
name: Linux x86 Build
runs-on: ubuntu-latest
linux_build:
strategy:
matrix:
include:
- arch: x86
artifact: subconverter_linux32
os: ubuntu-latest
- arch: amd64
artifact: subconverter_linux64
os: ubuntu-latest
- arch: armv7
artifact: subconverter_armv7
os: ubuntu-latest
- arch: aarch64
artifact: subconverter_aarch64
os: ubuntu-latest
runs-on: ${{ matrix.os }}
name: Linux ${{ matrix.arch }} Build
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:x86-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_linux32
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf subconverter_linux32.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_linux32.tar.gz
draft: true
linux64_build:
name: Linux x86_64 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: Build
run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:amd64-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_linux64
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf subconverter_linux64.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_linux64.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
- name: Checkout base
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@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:${{ matrix.arch }}-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@v4
with:
name: ${{ matrix.artifact }}
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf ${{ matrix.artifact }}.tar.gz subconverter
- name: Draft Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2
with:
files: ${{ matrix.artifact }}.tar.gz
draft: true
macos_build:
name: macOS Build
runs-on: macos-latest
strategy:
matrix:
include:
- arch: x86
artifact: subconverter_darwin64
os: macos-13
- arch: arm
artifact: subconverter_darwinarm
os: macos-14
runs-on: ${{ matrix.os }}
name: macOS ${{ matrix.arch }} Build
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Add commit id into version
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: SHA=$(git rev-parse --short HEAD) && sed -i -e 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
- name: Build
run: bash scripts/build.macos.release.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: subconverter_darwin64
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf subconverter_darwin64.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_darwin64.tar.gz
draft: true
- name: Checkout base
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Add commit id into version
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: SHA=$(git rev-parse --short HEAD) && sed -i -e 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h
- name: Build
run: bash scripts/build.macos.release.sh
- name: Upload
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: tar czf ${{ matrix.artifact }}.tar.gz subconverter
- name: Draft Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2
with:
files: ${{ matrix.artifact }}.tar.gz
draft: true
windows64_build:
name: Windows x86_64 Build
windows_build:
strategy:
matrix:
include:
- arch: x86
artifact: subconverter_win32
env: i686
msystem: MINGW32
- arch: amd64
artifact: subconverter_win64
env: x86_64
msystem: MINGW64
runs-on: windows-latest
name: Windows ${{ matrix.arch }} Build
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- uses: actions/setup-node@v3
with:
node-version: '16'
- uses: msys2/setup-msys2@v2
with:
update: true
install: base-devel git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-pcre2 patch
msystem: MINGW64
path-type: inherit
- 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: bash scripts/build.windows.release.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: subconverter_win64
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: 7z a subconverter_win64.7z subconverter/
- name: Draft Release
uses: softprops/action-gh-release@v1
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
with:
files: subconverter_win64.7z
draft: true
windows32_build:
name: Windows x86 Build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- uses: actions/setup-node@v3
with:
node-version: '16'
- uses: msys2/setup-msys2@v2
with:
update: true
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-cmake mingw-w64-i686-pcre2 patch
msystem: MINGW32
path-type: inherit
- 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: bash scripts/build.windows.release.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: subconverter_win32
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: 7z a subconverter_win32.7z subconverter/
- name: Draft Release
uses: softprops/action-gh-release@v1
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
with:
files: subconverter_win32.7z
draft: true
- name: Checkout base
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '16'
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
update: true
install: base-devel git mingw-w64-${{ matrix.env }}-gcc mingw-w64-${{ matrix.env }}-cmake mingw-w64-${{ matrix.env }}-pcre2 patch
msystem: ${{ matrix.msystem }}
path-type: inherit
- 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: bash scripts/build.windows.release.sh
- name: Upload
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: subconverter/
- name: Package Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
run: 7z a ${{ matrix.artifact }}.7z subconverter/
- name: Draft Release
if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2
with:
files: ${{ matrix.artifact }}.7z
draft: true

View File

@@ -4,343 +4,127 @@ on:
branches: [ master ]
tags:
- '**'
workflow_dispatch:
pull_request:
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
env:
REGISTRY_IMAGE: asdlokj1qpi23/subconverter
jobs:
amd64_build:
name: Build AMD64 Image
runs-on: ubuntu-latest
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/amd64
context: scripts/
tags: asdlokj1qpi23/subconverter:latest
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
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/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
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_amd64
path: /tmp/digest.txt
x86_build:
name: Build x86 Image
runs-on: ubuntu-latest
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/386
context: scripts/
tags: asdlokj1qpi23/subconverter:latest
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
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/386
context: scripts/
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
tags: asdlokj1qpi23/subconverter:${{steps.version.outputs.result}}
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_386
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]
runs-on: ubuntu-latest
strategy:
matrix:
include:
- platform: linux/amd64
os: ubuntu-latest
- platform: linux/386
os: ubuntu-latest
- platform: linux/arm/v7
os: ubuntu-latest
- platform: linux/arm64
os: ubuntu-latest
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.platform }} Image
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout base
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
config-inline: |
[worker.oci]
max-parallelism = 1
uses: docker/setup-buildx-action@v3
- name: Download artifact
uses: actions/download-artifact@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
path: /tmp/images/
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Docker login
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- 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: Merge and push manifest on master branch
- name: Get commit SHA
if: github.ref == 'refs/heads/master'
run: python scripts/merge_manifest.py
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Merge and push manifest on release
if: startsWith(github.ref, 'refs/tags/')
run: python scripts/merge_manifest.py ${{steps.version.outputs.result}}
- name: Build and export
id: build
uses: docker/build-push-action@v5
with:
platforms: ${{ matrix.platform }}
context: scripts/
labels: ${{ steps.meta.outputs.labels }}
build-args: |
SHA=${{ steps.vars.outputs.sha_short }}
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
rm -rf /tmp/digests
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: digest-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
name: Merge
needs: build
runs-on: ubuntu-latest
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digest-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Docker login
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}

6
.gitignore vendored
View File

@@ -3,3 +3,9 @@ subconverter.exe
cmake-build-debug
.idea
base/cache
scripts/quickjspp
scripts/yaml-cpp
.DS_Store
src/.DS_Store
build

View File

@@ -4,6 +4,10 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.4)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include/")
if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition")
endif()
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release)
ENDIF()

View File

@@ -2,10 +2,12 @@
Utility to convert between various proxy subscription formats.
[![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)
original git: https://github.com/asdlokj1qpi23/subconverter
[![Build Status](https://github.com/asdlokj1qpi233/subconverter/actions/workflows/docker.yml/badge.svg)](https://github.com/asdlokj1qpi233/subconverter/actions)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/asdlokj1qpi233/subconverter.svg)](https://github.com/asdlokj1qpi23/subconverter/tags)
[![GitHub release](https://img.shields.io/github/release/asdlokj1qpi233/subconverter.svg)](https://github.com/asdlokj1qpi233/subconverter/releases)
[![GitHub license](https://img.shields.io/github/license/asdlokj1qpi233/subconverter.svg)](https://github.com/tindy2013/subconverter/blob/master/LICENSE)
[Docker README](https://github.com/asdlokj1qpi23/subconverter/blob/master/README-docker.md)
@@ -59,6 +61,7 @@ services:
| Surge 2 | ✓ | ✓ | surge&ver=2 |
| Surge 3 | ✓ | ✓ | surge&ver=3 |
| Surge 4 | ✓ | ✓ | surge&ver=4 |
| Surge 5 | ✓ | ✓ | surge&ver=5 |
| V2Ray | ✓ | ✓ | v2ray |
| Telegram-liked HTTP/Socks 5 links | ✓ | × | Only as source |
| Singbox | ✓ | ✓ | singbox |

View File

@@ -5,7 +5,7 @@ socks-port: {{ default(global.clash.socks_port, "7891") }}
allow-lan: {{ default(global.clash.allow_lan, "true") }}
mode: Rule
log-level: {{ default(global.clash.log_level, "info") }}
external-controller: :9090
external-controller: {{ default(global.clash.external_controller, "127.0.0.1:9090") }}
{% if default(request.clash.dns, "") == "1" %}
dns:
enable: true
@@ -378,7 +378,16 @@ enhanced-mode-by-rule = true
"rules": [],
"auto_detect_interface": true
},
"experimental": {}
"experimental": {
"cache_file": {
"enabled": true,
"store_fakeip": true
},
"clash_api": {
"external_controller": "{{ default(global.clash.external_controller, "127.0.0.1:9090") }}",
"external_ui": "dashboard"
}
}
}
{% endif %}

View File

@@ -100,5 +100,14 @@
"rules": [],
"auto_detect_interface": true
},
"experimental": {}
"experimental": {
"cache_file": {
"enabled": true,
"store_fakeip": true
},
"clash_api": {
"external_controller": "127.0.0.1:9090",
"external_ui": "dashboard"
}
}
}

View File

@@ -109,13 +109,14 @@ filter_deprecated_nodes=false
append_sub_userinfo=true
clash_use_new_field_name=true
;Generate style of the proxies section of Clash subscriptions.
;Generate style of the proxies and proxy groups section of Clash subscriptions.
;Supported styles: block, flow, compact
;Block: - name: name1 Flow: - {name: name1, key: value} Compact: [{name: name1, key: value},{name: name2, key: value}]
; key: value - {name: name2, key: value}
; - name: name2
; key: value
clash_proxies_style=flow
clash_proxy_groups_style=block
;add Clash mode to sing-box rules, and add a GLOBAL group to end of outbounds
singbox_add_clash_modes=true
@@ -232,6 +233,7 @@ clash.http_port=7890
clash.socks_port=7891
clash.allow_lan=true
clash.log_level=info
clash.external_controller=127.0.0.1:9090
singbox.allow_lan=true
singbox.mixed_port=2080

View File

@@ -117,10 +117,10 @@ match = '^Smart Access expire: (\d+)/(\d+)/(\d+)$'
replace = '$1:$2:$3:0:0:0'
[node_pref]
udp_flag = true
tcp_fast_open_flag = false
skip_cert_verify_flag = true
tls13_flag = false
#udp_flag = false
#tcp_fast_open_flag = false
#skip_cert_verify_flag = false
#tls13_flag = false
sort_flag = false
# Script used for sorting nodes. A "compare" function with 2 arguments which are the 2 nodes to be compared should be defined in the script. Supports inline script and script path.
@@ -135,13 +135,14 @@ filter_deprecated_nodes = false
append_sub_userinfo = true
clash_use_new_field_name = true
# Generate style of the proxies section of Clash subscriptions.
# Generate style of the proxies and proxy groups section of Clash subscriptions.
# Supported styles: block, flow, compact
# Block: - name: name1 Flow: - {name: name1, key: value} Compact: [{name: name1, key: value},{name: name2, key: value}]
# key: value - {name: name2, key: value}
# - name: name2
# key: value
clash_proxies_style = "flow"
clash_proxy_groups_style = "block"
# add Clash mode to sing-box rules, and add a GLOBAL group to end of outbounds
singbox_add_clash_modes = true
@@ -243,6 +244,10 @@ value = "true"
key = "clash.log_level"
value = "info"
[[template.globals]]
key = "clash.external_controller"
value = "127.0.0.1:9090"
[[template.globals]]
key = "singbox.allow_lan"
value = "true"

View File

@@ -50,6 +50,7 @@ node_pref:
append_sub_userinfo: true
clash_use_new_field_name: true
clash_proxies_style: flow
clash_proxy_groups_style: block
singbox_add_clash_modes: true
rename_node:
# - {match: "\\(?((x|X)?(\\d+)(\\.?\\d+)?)((\\s?倍率?)|(x|X))\\)?", replace: "$1x"}
@@ -108,9 +109,10 @@ template:
- {key: clash.socks_port, value: 7891}
- {key: clash.allow_lan, value: true}
- {key: clash.log_level, value: info}
- {key: clash.external_controller, value: '127.0.0.1:9090'}
- {key: singbox.allow_lan, value: true}
- {key: singbox.mixed_port, value: 2080}
aliases:
- {uri: /v, target: /version}
- {uri: /clash, target: "/sub?target=clash"}

View File

@@ -3,15 +3,15 @@ match = "(?i:Bandwidth|expire|流量|时间|应急|过期)"
emoji = "🏳️‍🌈"
[[emoji]]
match = "(?i:\\bHK[G]?\\b|Hong.*?Kong|\\bHKT\\b|\\bHKBN\\b|\\bHGC\\b|\\bWTT\\b|\\bCMI\\b|[^-]港)"
match = "(?i:\\bHK[G]?\\d*\\b|Hong.*?Kong|\\bHKT\\b|\\bHKBN\\b|\\bHGC\\b|\\bWTT\\b|\\bCMI\\b|[^-]港)"
emoji = "🇭🇰"
[[emoji]]
match = "(?i:\\bTW[N]?\\b|Taiwan|新北|彰化|\\bCHT\\b|台湾|[^-]台|\\bHINET\\b)"
match = "(?i:\\bTW[N]?\\d*\\b|Taiwan|新北|彰化|\\bCHT\\b|台湾|[^-]台|\\bHINET\\b)"
emoji = "🇨🇳"
[[emoji]]
match = "(?i:\\bSG[P]?\\b|Singapore|新加坡|狮城|[^-]新)"
match = "(?i:\\bSG[P]?\\d*\\b|Singapore|新加坡|狮城|[^-]新)"
emoji = "🇸🇬"
[[emoji]]
@@ -19,15 +19,15 @@ match = "(尼日利亚|Nigeria)"
emoji = "🇳🇬"
[[emoji]]
match = "(?i:\\bJP[N]?\\b|Japan|Tokyo|Osaka|Saitama|日本|东京|大阪|埼玉|[^-]日)"
match = "(?i:\\bJP[N]?\\d*\\b|Japan|Tokyo|Osaka|Saitama|日本|东京|大阪|埼玉|[^-]日)"
emoji = "🇯🇵"
[[emoji]]
match = "(?i:\\bK[O]?R\\b|Korea|首尔|韩|韓)"
match = "(?i:(?<!North\\s)(\\bK[O]?R\\d*\\b|Korea|首尔|韩|韓))"
emoji = "🇰🇷"
[[emoji]]
match = "(?i:\\bUS[A]?\\b|America|United.*?States|美国|[^-]美|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥)"
match = "(?i:\\bUS[A]?\\d*\\b|America|United.*?States|美国|[^-]美|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥)"
emoji = "🇺🇸"
[[emoji]]
@@ -42,6 +42,10 @@ emoji = "🇦🇪"
match = "(阿尔巴尼亚|Albania)"
emoji = "🇦🇱"
[[emoji]]
match = "(南极|Antarctica)"
emoji = "🇦🇶"
[[emoji]]
match = "(Argentina|阿根廷)"
emoji = "🇦🇷"
@@ -51,7 +55,7 @@ match = "(Austria|Vienna|奥地利|维也纳)"
emoji = "🇦🇹"
[[emoji]]
match = "(?i:\\bAU[S]?\\b|Australia|Sydney|澳大利亚|澳洲|悉尼)"
match = "(?i:\\bAU[S]?\\d*\\b|Australia|Sydney|澳大利亚|澳洲|悉尼)"
emoji = "🇦🇺"
[[emoji]]
@@ -75,7 +79,7 @@ match = "(Brazil|Paulo|巴西|圣保罗)"
emoji = "🇧🇷"
[[emoji]]
match = "(?i:\\bCA[N]?\\b|Canada|Toronto|Montreal|Vancouver|加拿大|蒙特利尔|温哥华|楓葉|枫叶)"
match = "(?i:\\bCA[N]?\\d*\\b|Canada|Toronto|Montreal|Vancouver|加拿大|蒙特利尔|温哥华|楓葉|枫叶)"
emoji = "🇨🇦"
[[emoji]]
@@ -103,7 +107,7 @@ match = "(Czech|捷克)"
emoji = "🇨🇿"
[[emoji]]
match = "(?i:\\bDE[U]?\\b|Germany|法兰克福|德(国|意志)|中德|^德$)"
match = "(?i:\\bDE[U]?\\d*\\b|Germany|法兰克福|德(国|意志)|中德|^德$)"
emoji = "🇩🇪"
[[emoji]]
@@ -119,7 +123,7 @@ match = "(埃及|Egypt)"
emoji = "🇪🇬"
[[emoji]]
match = "(?i:\\bES[P]?\\b|Spain|西班牙)"
match = "(?i:\\bES[P]?\\d*\\b|Spain|西班牙)"
emoji = "🇪🇸"
[[emoji]]
@@ -131,11 +135,11 @@ match = "(Finland|Helsinki|芬兰|赫尔辛基)"
emoji = "🇫🇮"
[[emoji]]
match = "(?i:\\bFR[A]?\\b|France|Paris|法国|巴黎)"
match = "(?i:\\bFR[A]?\\d*\\b|France|Paris|法国|巴黎)"
emoji = "🇫🇷"
[[emoji]]
match = "(?i:\\bUK\\b|\\bGB[R]?\\b|England|United.*?Kingdom|London|英国|[^-]英|伦敦)"
match = "(?i:\\bUK\\d*\\b|\\bGB[R]?\\d*\\b|England|United.*?Kingdom|London|英国|[^-]英|伦敦)"
emoji = "🇬🇧"
[[emoji]]
@@ -171,7 +175,7 @@ match = "(马恩岛|Mann)"
emoji = "🇮🇲"
[[emoji]]
match = "(?i:\\bIN[D]?\\b|India|Mumbai|印度|孟买|加尔各答|贾坎德|泰米尔纳德)"
match = "(?i:\\bIN[D]?\\d*\\b|India|Mumbai|印度|孟买|加尔各答|贾坎德|泰米尔纳德)"
emoji = "🇮🇳"
[[emoji]]
@@ -179,11 +183,11 @@ match = "(伊朗|Iran)"
emoji = "🇮🇷"
[[emoji]]
match = "(?i:\\bIS[L]?\\b|Iceland|冰岛)"
match = "(?i:\\bIS[L]?\\d*\\b|Iceland|冰岛)"
emoji = "🇮🇸"
[[emoji]]
match = "(Italy|Milan|意大利|米兰)"
match = "(Italy|Italia|Milan|意大利|米兰)"
emoji = "🇮🇹"
[[emoji]]
@@ -202,7 +206,6 @@ emoji = "🇰🇬"
match = "(柬埔寨|Cambodia)"
emoji = "🇰🇭"
[[emoji]]
match = "(North.*?Korea|朝鲜)"
emoji = "🇰🇵"
@@ -231,6 +234,10 @@ emoji = "🇲🇩"
match = "(北马其顿|Macedonia)"
emoji = "🇲🇰"
[[emoji]]
match = "(缅甸|Myanmar)"
emoji = "🇲🇲"
[[emoji]]
match = "(蒙古|Монголулс|Mongolia)"
emoji = "🇲🇳"
@@ -248,7 +255,7 @@ match = "(Malaysia|马来|MY)"
emoji = "🇲🇾"
[[emoji]]
match = "(?i:\\bNL[D]?\\b|Netherlands|荷兰|阿姆斯特丹)"
match = "(?i:\\bNL[D]?\\d*\\b|Netherlands|荷兰|阿姆斯特丹)"
emoji = "🇳🇱"
[[emoji]]
@@ -260,7 +267,7 @@ match = "(新西兰|纽西兰|New Zealand)"
emoji = "🇳🇿"
[[emoji]]
match = "(Philippines|菲律宾)"
match = "(?i:\\bP[O]?H\\d*\\b|Philippines|菲律宾)"
emoji = "🇵🇭"
[[emoji]]
@@ -292,7 +299,7 @@ match = "(塞尔维亚|Serbia)"
emoji = "🇷🇸"
[[emoji]]
match = "(?i:\\bRU[S]?\\b|Russia|Moscow|Petersburg|Siberia|伯力|莫斯科|圣彼得堡|西伯利亚|新西伯利亚|哈巴罗夫斯克|俄罗斯|[^-]俄)"
match = "(?i:\\bRU[S]?\\d*\\b|Russia|Moscow|Petersburg|Siberia|伯力|莫斯科|圣彼得堡|西伯利亚|新西伯利亚|哈巴罗夫斯克|俄罗斯|[^-]俄)"
emoji = "🇷🇺"
[[emoji]]
@@ -320,7 +327,7 @@ match = "(突尼斯|Tunisia)"
emoji = "🇹🇳"
[[emoji]]
match = "(Turkey|土耳其|伊斯坦布尔)"
match = "(Turkey|Türkiye|土耳其|伊斯坦布尔)"
emoji = "🇹🇷"
[[emoji]]
@@ -364,4 +371,4 @@ emoji = "🇧🇩"
[[emoji]]
match = "(?i:\\bC[H]?N\\b|China|back|回国|中国[^-]|江苏[^-]|北京[^-]|上海[^-]|广州[^-]|深圳[^-]|杭州[^-]|常州[^-]|徐州[^-]|青岛[^-]|宁波[^-]|镇江[^-]|成都[^-]|河北[^-]|山西[^-]|辽宁[^-]|吉林[^-]|黑龙江[^-]|江苏[^-]|浙江[^-]|安徽[^-]|福建[^-]|江西[^-]|山东[^-]|河南[^-]|湖北[^-]|湖南[^-]|广东[^-]|海南[^-]|四川[^-]|贵州[^-]|云南[^-]|陕西[^-]|甘肃[^-]|青海[^-]|内蒙古[^-]|广西[^-]|西藏[^-]|宁夏[^-]|新疆[^-])"
emoji = "🇨🇳"
emoji = "🇨🇳"

View File

@@ -1,38 +1,39 @@
(?i:Bandwidth|expire|流量|时间|应急|过期),🏳️‍🌈
(?i:\bHK[G]?\b|Hong.*?Kong|\bHKT\b|\bHKBN\b|\bHGC\b|\bWTT\b|\bCMI\b|[^-]港),🇭🇰
(?i:\bTW[N]?\b|Taiwan|新北|彰化|\bCHT\b|台湾|[^-]台|\bHINET\b),🇨🇳
(?i:\bSG[P]?\b|Singapore|新加坡|狮城|[^-]新),🇸🇬
(?i:\bHK[G]?\d*\b|Hong.*?Kong|\bHKT\b|\bHKBN\b|\bHGC\b|\bWTT\b|\bCMI\b|[^-]港),🇭🇰
(?i:\bTW[N]?\d*\b|Taiwan|新北|彰化|\bCHT\b|台湾|[^-]台|\bHINET\b),🇨🇳
(?i:\bSG[P]?\d*\b|Singapore|新加坡|狮城|[^-]新),🇸🇬
(尼日利亚|Nigeria),🇳🇬
(?i:\bJP[N]?\b|Japan|Tokyo|Osaka|Saitama|日本|东京|大阪|埼玉|[^-]日),🇯🇵
(?i:\bK[O]?R\b|Korea|首尔|韩|韓),🇰🇷
(?i:\bUS[A]?\b|America|United.*?States|美国|[^-]美|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥),🇺🇸
(?i:\bJP[N]?\d*\b|Japan|Tokyo|Osaka|Saitama|日本|东京|大阪|埼玉|[^-]日),🇯🇵
(?i:(?<!North\s)(\bK[O]?R\d*\b|Korea|首尔|韩|韓)),🇰🇷
(?i:\bUS[A]?\d*\b|America|United.*?States|美国|[^-]美|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥),🇺🇸
(Ascension|阿森松),🇦🇨
(?i:\bUAE\b|Dubai|阿联酋|迪拜),🇦🇪
(阿尔巴尼亚|Albania),🇦🇱
(南极|Antarctica),🇦🇶
(Argentina|阿根廷),🇦🇷
(Austria|Vienna|奥地利|维也纳),🇦🇹
(?i:\bAU[S]?\b|Australia|Sydney|澳大利亚|澳洲|悉尼),🇦🇺
(?i:\bAU[S]?\d*\b|Australia|Sydney|澳大利亚|澳洲|悉尼),🇦🇺
(阿塞拜疆|Azerbaijan),🇦🇿
(波黑共和国|波士尼亚与赫塞哥维纳|Bosnia|Herzegovina),🇧🇦
(Belgium|比利时),🇧🇪
(保加利亚|Bulgaria),🇧🇬
(Brazil|Paulo|巴西|圣保罗),🇧🇷
(?i:\bCA[N]?\b|Canada|Toronto|Montreal|Vancouver|加拿大|蒙特利尔|温哥华|楓葉|枫叶),🇨🇦
(?i:\bCA[N]?\d*\b|Canada|Toronto|Montreal|Vancouver|加拿大|蒙特利尔|温哥华|楓葉|枫叶),🇨🇦
(Switzerland|Zurich|瑞士|苏黎世),🇨🇭
(智利|Chile),🇨🇱
(Colombia|哥伦比亚),🇨🇴
(Costa Rica|哥斯达黎加),🇨🇷
(塞浦路斯|Cyprus),🇨🇾
(Czech|捷克),🇨🇿
(?i:\bDE[U]?\b|Germany|法兰克福|德(国|意志)|中德|^德$),🇩🇪
(?i:\bDE[U]?\d*\b|Germany|法兰克福|德(国|意志)|中德|^德$),🇩🇪
(?i:\bD[N]?K\b|Denmark|丹麦),🇩🇰
(爱沙尼亚|Estonia),🇪🇪
(埃及|Egypt),🇪🇬
(?i:\bES[P]?\b|Spain|西班牙),🇪🇸
(?i:\bES[P]?\d*\b|Spain|西班牙),🇪🇸
(Europe|欧洲),🇪🇺
(Finland|Helsinki|芬兰|赫尔辛基),🇫🇮
(?i:\bFR[A]?\b|France|Paris|法国|巴黎),🇫🇷
(?i:\bUK\b|\bGB[R]?\b|England|United.*?Kingdom|London|英国|[^-]英|伦敦),🇬🇧
(?i:\bFR[A]?\d*\b|France|Paris|法国|巴黎),🇫🇷
(?i:\bUK\d*\b|\bGB[R]?\d*\b|England|United.*?Kingdom|London|英国|[^-]英|伦敦),🇬🇧
(希腊|Greece),🇬🇷
(格鲁吉亚|Georgia),🇬🇪
(克罗地亚|Croatia),🇭🇷
@@ -41,10 +42,10 @@
(Ireland|Dublin|爱尔兰|都柏林),🇮🇪
(Israel|以色列),🇮🇱
(马恩岛|Mann),🇮🇲
(?i:\bIN[D]?\b|India|Mumbai|印度|孟买|加尔各答|贾坎德|泰米尔纳德),🇮🇳
(?i:\bIN[D]?\d*\b|India|Mumbai|印度|孟买|加尔各答|贾坎德|泰米尔纳德),🇮🇳
(伊朗|Iran),🇮🇷
(?i:\bIS[L]?\b|Iceland|冰岛),🇮🇸
(Italy|Milan|意大利|米兰),🇮🇹
(?i:\bIS[L]?\d*\b|Iceland|冰岛),🇮🇸
(Italy|Italia|Milan|意大利|米兰),🇮🇹
(约旦|Jordan),🇯🇴
(肯尼亚|Kenya),🇰🇪
(吉尔吉斯斯坦|Kyrgyzstan),🇰🇬
@@ -56,14 +57,15 @@
(拉脱维亚|Latvia),🇱🇻
(Moldova|摩尔多瓦),🇲🇩
(北马其顿|Macedonia),🇲🇰
(缅甸|Myanmar),🇲🇲
(蒙古|Монголулс|Mongolia),🇲🇳
(Macao|澳门|\bCTM\b),🇲🇴
(墨西哥|Mexico),🇲🇽
(Malaysia|马来|MY),🇲🇾
(?i:\bNL[D]?\b|Netherlands|荷兰|阿姆斯特丹),🇳🇱
(?i:\bNL[D]?\d*\b|Netherlands|荷兰|阿姆斯特丹),🇳🇱
(挪威|Norway),🇳🇴
(新西兰|纽西兰|New Zealand),🇳🇿
(Philippines|菲律宾),🇵🇭
(?i:\bP[O]?H\d*\b|Philippines|菲律宾),🇵🇭
(Pakistan|巴基斯坦),🇵🇰
(?i:\bP[O]?L\b|Poland|波兰),🇵🇱
(巴拿马|Panama),🇵🇦
@@ -71,15 +73,16 @@
(葡萄牙|Portugal),🇵🇹
(Romania|罗马尼亚),🇷🇴
(塞尔维亚|Serbia),🇷🇸
(?i:\bRU[S]?\b|Russia|Moscow|Petersburg|Siberia|伯力|莫斯科|圣彼得堡|西伯利亚|新西伯利亚|哈巴罗夫斯克|俄罗斯|[^-]俄),🇷🇺
(?i:\bRU[S]?\d*\b|Russia|Moscow|Petersburg|Siberia|伯力|莫斯科|圣彼得堡|西伯利亚|新西伯利亚|哈巴罗夫斯克|俄罗斯|[^-]俄),🇷🇺
(Arabia|沙特),🇸🇦
(Sweden|瑞典),🇸🇪
(斯洛文尼亚|Slovenia),🇸🇮
(斯洛伐克|Slovensko),🇸🇰
(Thailand|泰国|曼谷),🇹🇭
(突尼斯|Tunisia),🇹🇳
(Turkey|土耳其|伊斯坦布尔),🇹🇷
(Turkey|Türkiye|土耳其|伊斯坦布尔),🇹🇷
(乌拉圭|Uruguay),🇺🇾
(梵蒂冈|Vatican),🇻🇦
(Vietnam|越南),🇻🇳
(Africa|南非),🇿🇦
(Ukraine|UA|乌克兰),🇺🇦

View File

@@ -30,12 +30,12 @@ RUN set -xe && \
install -d /usr/include/date/ && \
install -m644 libcron/externals/date/include/date/* /usr/include/date/ && \
cd .. && \
git clone https://github.com/ToruNiina/toml11 --branch="v3.7.1" --depth=1 && \
git clone https://github.com/ToruNiina/toml11 --branch="v4.3.0" --depth=1 && \
cd toml11 && \
cmake -DCMAKE_CXX_STANDARD=11 . && \
make install -j $THREADS && \
cd .. && \
git clone https://github.com/asdlokj1qpi23/subconverter --depth=1 && \
git clone https://github.com/asdlokj1qpi233/subconverter --depth=1 && \
cd subconverter && \
[ -n "$SHA" ] && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h;\
python3 -m ensurepip && \
@@ -53,6 +53,10 @@ RUN apk add --no-cache --virtual subconverter-deps pcre2 libcurl yaml-cpp
COPY --from=builder /subconverter/subconverter /usr/bin/
COPY --from=builder /subconverter/base /base/
ENV TZ=Africa/Abidjan
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime
RUN echo $TZ > /etc/timezone
# set entry
WORKDIR /base
CMD subconverter

View File

@@ -4,7 +4,7 @@ set -xe
apk add gcc g++ build-base linux-headers cmake make autoconf automake libtool python2 python3
apk add mbedtls-dev mbedtls-static zlib-dev rapidjson-dev zlib-static pcre2-dev
git clone https://github.com/curl/curl --depth=1 --branch curl-8_4_0
git clone https://github.com/curl/curl --depth=1 --branch curl-8_6_0
cd curl
cmake -DCURL_USE_MBEDTLS=ON -DHTTP_ONLY=ON -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_USE_LIBSSH2=OFF -DBUILD_CURL_EXE=OFF . > /dev/null
make install -j2 > /dev/null
@@ -34,7 +34,7 @@ cmake -DCMAKE_BUILD_TYPE=Release .
make libcron install -j3
cd ..
git clone https://github.com/ToruNiina/toml11 --branch="v3.7.1" --depth=1
git clone https://github.com/ToruNiina/toml11 --branch="v4.3.0" --depth=1
cd toml11
cmake -DCMAKE_CXX_STANDARD=11 .
make install -j4

View File

@@ -14,49 +14,47 @@ brew reinstall rapidjson zlib pcre2 pkgconfig
git clone https://github.com/jbeder/yaml-cpp --depth=1
cd yaml-cpp
cmake -DCMAKE_BUILD_TYPE=Release -DYAML_CPP_BUILD_TESTS=OFF -DYAML_CPP_BUILD_TOOLS=OFF . > /dev/null
make install -j8 > /dev/null
make -j6 > /dev/null
sudo make install > /dev/null
cd ..
git clone https://github.com/ftk/quickjspp --depth=1
cd quickjspp
cmake -DCMAKE_BUILD_TYPE=Release .
make quickjs -j8
install -d /usr/local/lib/quickjs/
install -m644 quickjs/libquickjs.a /usr/local/lib/quickjs/
install -d /usr/local/include/quickjs/
install -m644 quickjs/quickjs.h quickjs/quickjs-libc.h /usr/local/include/quickjs/
install -m644 quickjspp.hpp /usr/local/include/
make quickjs -j6 > /dev/null
sudo install -d /usr/local/lib/quickjs/
sudo install -m644 quickjs/libquickjs.a /usr/local/lib/quickjs/
sudo install -d /usr/local/include/quickjs/
sudo install -m644 quickjs/quickjs.h quickjs/quickjs-libc.h /usr/local/include/quickjs/
sudo install -m644 quickjspp.hpp /usr/local/include/
cd ..
git clone https://github.com/PerMalmberg/libcron --depth=1
cd libcron
git submodule update --init
cmake -DCMAKE_BUILD_TYPE=Release .
make libcron install -j8
install -m644 libcron/out/Release/liblibcron.a /usr/local/lib/
install -d /usr/local/include/libcron/
install -m644 libcron/include/libcron/* /usr/local/include/libcron/
install -d /usr/local/include/date/
install -m644 libcron/externals/date/include/date/* /usr/local/include/date/
make libcron -j6
sudo install -m644 libcron/out/Release/liblibcron.a /usr/local/lib/
sudo install -d /usr/local/include/libcron/
sudo install -m644 libcron/include/libcron/* /usr/local/include/libcron/
sudo install -d /usr/local/include/date/
sudo install -m644 libcron/externals/date/include/date/* /usr/local/include/date/
cd ..
git clone https://github.com/ToruNiina/toml11 --depth=1
git clone https://github.com/ToruNiina/toml11 --branch="v4.3.0" --depth=1
cd toml11
cmake -DCMAKE_CXX_STANDARD=11 .
make install -j4
sudo make install -j6 > /dev/null
cd ..
cp /usr/local/opt/zlib/lib/libz.a .
cp /usr/local/lib/libpcre2-8.a .
cmake -DCMAKE_BUILD_TYPE=Release .
make -j8
make -j6
rm subconverter
# shellcheck disable=SC2046
c++ -Xlinker -unexported_symbol -Xlinker "*" -o base/subconverter -framework CoreFoundation -framework Security $(find CMakeFiles/subconverter.dir/src/ -name "*.o") $(find . -name "*.a") -lcurl -O3
c++ -Xlinker -unexported_symbol -Xlinker "*" -o base/subconverter -framework CoreFoundation -framework Security $(find CMakeFiles/subconverter.dir/src/ -name "*.o") "$(brew --prefix zlib)/lib/libz.a" "$(brew --prefix pcre2)/lib/libpcre2-8.a" $(find . -name "*.a") -lcurl -O3
python -m ensurepip
python -m pip install gitpython
sudo python -m pip install gitpython
python scripts/update_rules.py -c scripts/rules_config.conf
cd base

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -xe
git clone https://github.com/curl/curl --depth=1 --branch curl-8_4_0
git clone https://github.com/curl/curl --depth=1 --branch curl-8_6_0
cd curl
cmake -DCMAKE_BUILD_TYPE=Release -DCURL_USE_LIBSSH2=OFF -DHTTP_ONLY=ON -DCURL_USE_SCHANNEL=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_CURL_EXE=OFF -DCMAKE_INSTALL_PREFIX="$MINGW_PREFIX" -G "Unix Makefiles" -DHAVE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF .
make install -j4
@@ -16,8 +16,26 @@ cd ..
git clone https://github.com/ftk/quickjspp --depth=1
cd quickjspp
patch quickjs/quickjs-libc.c -i ../scripts/patches/0001-quickjs-libc-add-realpath-for-Windows.patch
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_FLAGS="-D__MINGW_FENV_DEFINED" .
make quickjs -j4
# 如果是 32 位编译,则处理 libquickjs.a去掉重复定义的符号
# 注意:此处通过检测目标架构环境变量,你也可以根据实际情况加个判断
echo "处理 32 位 libquickjs.a去除重复定义的符号..."
mkdir -p tmp_lib
cd tmp_lib
# 解包静态库
ar x ../quickjs/libquickjs.a
# 对每个目标文件,删除这几个符号
for obj in *.o; do
objcopy --strip-symbol=__mingw_fe_pc53_env --strip-symbol=__mingw_fe_pc64_env --strip-symbol=__mingw_fe_dfl_env "$obj"
done
# 重新打包为新的静态库
ar rcs ../quickjs/libquickjs_fixed.a *.o
cd ..
# 用处理后的库覆盖原库(或直接安装新库)
mv quickjs/libquickjs_fixed.a quickjs/libquickjs.a
install -d "$MINGW_PREFIX/lib/quickjs/"
install -m644 quickjs/libquickjs.a "$MINGW_PREFIX/lib/quickjs/"
install -d "$MINGW_PREFIX/include/quickjs"
@@ -38,7 +56,7 @@ cmake -DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF -DRAPIDJSON_BUILD
make install -j4
cd ..
git clone https://github.com/ToruNiina/toml11 --depth=1
git clone https://github.com/ToruNiina/toml11 --branch "v4.3.0" --depth=1
cd toml11
cmake -DCMAKE_INSTALL_PREFIX="$MINGW_PREFIX" -G "Unix Makefiles" -DCMAKE_CXX_STANDARD=11 .
make install -j4
@@ -54,4 +72,4 @@ make -j4
rm subconverter.exe
# shellcheck disable=SC2046
g++ $(find CMakeFiles/subconverter.dir/src -name "*.obj") curl/lib/libcurl.a -o base/subconverter.exe -static -lbcrypt -lpcre2-8 -l:quickjs/libquickjs.a -llibcron -lyaml-cpp -liphlpapi -lcrypt32 -lws2_32 -lwsock32 -lz -s
mv base subconverter
mv base subconverter

View File

@@ -1,23 +1,23 @@
[ACL4SSR]
name=ACL4SSR
url=https://github.com/ACL4SSR/ACL4SSR
checkout=1dc5c92b0c8ceaaecbc66530c309961f53e52c8c
branch=master
match=Clash/*.list|Clash/Ruleset/**
[ACL4SSR_config]
name=ACL4SSR
url=https://github.com/ACL4SSR/ACL4SSR
checkout=1dc5c92b0c8ceaaecbc66530c309961f53e52c8c
branch=master
match=Clash/config/**
dest=base/config/
keep_tree=false
[DivineEngine]
url=https://github.com/DivineEngine/Profiles
checkout=f4d75f7d48a3f42129e030bef751d4d22bca02da
match=Surge/Ruleset/**
[NobyDa]
url=https://github.com/NobyDa/Script
checkout=ae4c12f23de8078e02c373c9969b19af28257fcb
branch=master
match=Surge/*.list
[lhie1]
url=https://github.com/dler-io/Rules
branch=main
match=Surge/Surge 3/Provider/**

View File

@@ -0,0 +1,23 @@
[ACL4SSR]
name=ACL4SSR
url=https://github.com/ACL4SSR/ACL4SSR
checkout=1dc5c92b0c8ceaaecbc66530c309961f53e52c8c
match=Clash/*.list|Clash/Ruleset/**
[ACL4SSR_config]
name=ACL4SSR
url=https://github.com/ACL4SSR/ACL4SSR
checkout=1dc5c92b0c8ceaaecbc66530c309961f53e52c8c
match=Clash/config/**
dest=base/config/
keep_tree=false
[DivineEngine]
url=https://github.com/DivineEngine/Profiles
checkout=f4d75f7d48a3f42129e030bef751d4d22bca02da
match=Surge/Ruleset/**
[NobyDa]
url=https://github.com/NobyDa/Script
checkout=ae4c12f23de8078e02c373c9969b19af28257fcb
match=Surge/*.list

View File

@@ -22,10 +22,13 @@ def open_repo(path: str):
return None
def update_rules(repo_path, save_path, commit, matches, keep_tree):
def update_rules(repo_path: str, save_path: str, matches: list[str], keep_tree: bool):
os.makedirs(save_path, exist_ok=True)
for pattern in matches:
files = glob.glob(os.path.join(repo_path, pattern), recursive=True)
if len(files) == 0:
logging.warn(f"no files found for pattern {pattern}")
continue
for file in files:
if os.path.isdir(file):
continue
@@ -51,12 +54,13 @@ def main():
for section in config.sections():
repo = config.get(section, "name", fallback=section)
url = config.get(section, "url")
commit = config.get(section, "checkout")
commit = config.get(section, "commit", fallback=None)
branch = config.get(section, "branch", fallback=None)
matches = config.get(section, "match").split("|")
save_path = config.get(section, "dest", fallback=f"base/rules/{repo}")
keep_tree = config.getboolean(section, "keep_tree", fallback=True)
logging.info(f"reading files from url {url} with commit {commit} and matches {matches}, save to {save_path} keep_tree {keep_tree}")
logging.info(f"reading files from url {url}, matches {matches}, save to {save_path} keep_tree {keep_tree}")
repo_path = os.path.join("./tmp/repo/", repo)
@@ -67,8 +71,21 @@ def main():
else:
logging.info(f"repo {repo_path} exists")
r.git.checkout(commit)
update_rules(repo_path, save_path, commit, matches, keep_tree)
try:
if commit is not None:
logging.info(f"checking out to commit {commit}")
r.git.checkout(commit)
elif branch is not None:
logging.info(f"checking out to branch {branch}")
r.git.checkout(branch)
else:
logging.info(f"checking out to default branch")
r.active_branch.checkout()
except Exception as e:
logging.error(f"checkout failed {e}")
continue
update_rules(repo_path, save_path, matches, keep_tree)
shutil.rmtree("./tmp", ignore_errors=True)

View File

@@ -17,9 +17,9 @@ namespace toml
static ProxyGroupConfig from_toml(const value& v)
{
ProxyGroupConfig conf;
conf.Name = toml::find<String>(v, "name");
String type = toml::find<String>(v, "type");
String strategy = toml::find_or<String>(v, "strategy", "");
conf.Name = find<String>(v, "name");
String type = find<String>(v, "type");
String strategy = find_or<String>(v, "strategy", "");
switch(hash_(type))
{
case "select"_hash:
@@ -27,18 +27,18 @@ namespace toml
break;
case "url-test"_hash:
conf.Type = ProxyGroupType::URLTest;
conf.Url = toml::find<String>(v, "url");
conf.Interval = toml::find<Integer>(v, "interval");
conf.Tolerance = toml::find_or<Integer>(v, "tolerance", 0);
conf.Url = find<String>(v, "url");
conf.Interval = find<Integer>(v, "interval");
conf.Tolerance = find_or<Integer>(v, "tolerance", 0);
if(v.contains("lazy"))
conf.Lazy = toml::find_or<bool>(v, "lazy", false);
conf.Lazy = find_or<bool>(v, "lazy", false);
if(v.contains("evaluate-before-use"))
conf.EvaluateBeforeUse = toml::find_or(v, "evaluate-before-use", conf.EvaluateBeforeUse.get());
conf.EvaluateBeforeUse = find_or(v, "evaluate-before-use", conf.EvaluateBeforeUse.get());
break;
case "load-balance"_hash:
conf.Type = ProxyGroupType::LoadBalance;
conf.Url = toml::find<String>(v, "url");
conf.Interval = toml::find<Integer>(v, "interval");
conf.Url = find<String>(v, "url");
conf.Interval = find<Integer>(v, "interval");
switch(hash_(strategy))
{
case "consistent-hashing"_hash:
@@ -49,14 +49,14 @@ namespace toml
break;
}
if(v.contains("persistent"))
conf.Persistent = toml::find_or(v, "persistent", conf.Persistent.get());
conf.Persistent = find_or(v, "persistent", conf.Persistent.get());
break;
case "fallback"_hash:
conf.Type = ProxyGroupType::Fallback;
conf.Url = toml::find<String>(v, "url");
conf.Interval = toml::find<Integer>(v, "interval");
conf.Url = find<String>(v, "url");
conf.Interval = find<Integer>(v, "interval");
if(v.contains("evaluate-before-use"))
conf.EvaluateBeforeUse = toml::find_or(v, "evaluate-before-use", conf.EvaluateBeforeUse.get());
conf.EvaluateBeforeUse = find_or(v, "evaluate-before-use", conf.EvaluateBeforeUse.get());
break;
case "relay"_hash:
conf.Type = ProxyGroupType::Relay;
@@ -64,16 +64,26 @@ namespace toml
case "ssid"_hash:
conf.Type = ProxyGroupType::SSID;
break;
case "smart"_hash:
conf.Type = ProxyGroupType::Smart;
conf.Url = find<String>(v, "url");
conf.Interval = find<Integer>(v, "interval");
conf.Tolerance = find_or<Integer>(v, "tolerance", 0);
if(v.contains("lazy"))
conf.Lazy = find_or<bool>(v, "lazy", false);
if(v.contains("evaluate-before-use"))
conf.EvaluateBeforeUse = find_or(v, "evaluate-before-use", conf.EvaluateBeforeUse.get());
break;
default:
throw toml::syntax_error("Proxy Group has incorrect type, should be one of following:\n select, url-test, load-balance, fallback, relay, ssid", v.at("type").location());
throw serialization_error(format_error("Proxy Group has unsupported type!", v.at("type").location(), "should be one of following: select, url-test, load-balance, fallback, relay, ssid"), v.at("type").location());
}
conf.Timeout = toml::find_or(v, "timeout", 5);
conf.Proxies = toml::find_or<StrArray>(v, "rule", {});
conf.UsingProvider = toml::find_or<StrArray>(v, "use", {});
conf.Timeout = find_or(v, "timeout", 5);
conf.Proxies = find_or<StrArray>(v, "rule", {});
conf.UsingProvider = find_or<StrArray>(v, "use", {});
if(conf.Proxies.empty() && conf.UsingProvider.empty())
throw toml::syntax_error("Proxy Group must contains at least one of proxy match rule or provider", v.location());
throw serialization_error(format_error("Proxy Group must contains at least one of proxy match rule or provider!", v.location(), "here"), v.location());
if(v.contains("disable-udp"))
conf.DisableUdp = toml::find_or(v, "disable-udp", conf.DisableUdp.get());
conf.DisableUdp = find_or(v, "disable-udp", conf.DisableUdp.get());
return conf;
}
};
@@ -84,8 +94,8 @@ namespace toml
static RulesetConfig from_toml(const value& v)
{
RulesetConfig conf;
conf.Group = toml::find<String>(v, "group");
String type = toml::find_or<String>(v, "type", "surge-ruleset");
conf.Group = find<String>(v, "group");
String type = find_or<String>(v, "type", "surge-ruleset");
switch(hash_(type))
{
/*
@@ -122,10 +132,10 @@ namespace toml
conf.Url = type + ":";
break;
default:
throw toml::syntax_error("Ruleset has incorrect type, should be one of following:\n surge-ruleset, quantumultx, clash-domain, clash-ipcidr, clash-classic", v.at("type").location());
throw serialization_error(format_error("Ruleset has unsupported type!", v.at("type").location(), "should be one of following: surge-ruleset, quantumultx, clash-domain, clash-ipcidr, clash-classic"), v.at("type").location());
}
conf.Url += toml::find<String>(v, "ruleset");
conf.Interval = toml::find_or<Integer>(v, "interval", 86400);
conf.Url += find<String>(v, "ruleset");
conf.Interval = find_or<Integer>(v, "interval", 86400);
return conf;
}
};
@@ -138,14 +148,14 @@ namespace toml
RegexMatchConfig conf;
if(v.contains("script"))
{
conf.Script = toml::find<String>(v, "script");
conf.Script = find<String>(v, "script");
return conf;
}
conf.Match = toml::find<String>(v, "match");
conf.Match = find<String>(v, "match");
if(v.contains("emoji"))
conf.Replace = toml::find<String>(v, "emoji");
conf.Replace = find<String>(v, "emoji");
else
conf.Replace = toml::find<String>(v, "replace");
conf.Replace = find<String>(v, "replace");
return conf;
}
};
@@ -156,10 +166,10 @@ namespace toml
static CronTaskConfig from_toml(const value& v)
{
CronTaskConfig conf;
conf.Name = toml::find<String>(v, "name");
conf.CronExp = toml::find<String>(v, "cronexp");
conf.Path = toml::find<String>(v, "path");
conf.Timeout = toml::find_or<Integer>(v, "timeout", 0);
conf.Name = find<String>(v, "name");
conf.CronExp = find<String>(v, "cronexp");
conf.Path = find<String>(v, "path");
conf.Timeout = find_or<Integer>(v, "timeout", 0);
return conf;
}
};
@@ -220,6 +230,9 @@ namespace INIBinding
case "ssid"_hash:
conf.Type = ProxyGroupType::SSID;
break;
case "smart"_hash:
conf.Type = ProxyGroupType::Smart;
break;
default:
continue;
}

View File

@@ -3,17 +3,18 @@
#include "def.h"
enum ProxyGroupType
enum class ProxyGroupType
{
Select,
URLTest,
Fallback,
LoadBalance,
Relay,
SSID
SSID,
Smart
};
enum BalanceStrategy
enum class BalanceStrategy
{
ConsistentHashing,
RoundRobin
@@ -45,6 +46,7 @@ struct ProxyGroupConfig
case ProxyGroupType::Fallback: return "fallback";
case ProxyGroupType::Relay: return "relay";
case ProxyGroupType::SSID: return "ssid";
case ProxyGroupType::Smart: return "smart";
}
return "";
}

View File

@@ -3,7 +3,7 @@
#include "def.h"
enum RulesetType
enum class RulesetType
{
SurgeRuleset,
QuantumultX,

View File

@@ -10,7 +10,9 @@
/// rule type lists
#define basic_types "DOMAIN", "DOMAIN-SUFFIX", "DOMAIN-KEYWORD", "IP-CIDR", "SRC-IP-CIDR", "GEOIP", "MATCH", "FINAL"
string_array ClashRuleTypes = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-PORT", "PROCESS-NAME"};
// 新增meta路由规则
//string_array ClashRuleTypes = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-PORT", "PROCESS-NAME"};
string_array ClashRuleTypes = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-PORT", "PROCESS-NAME", "DOMAIN-REGEX", "GEOSITE", "IP-SUFFIX", "IP-ASN", "SRC-GEOIP", "SRC-IP-ASN", "SRC-IP-SUFFIX", "IN-PORT", "IN-TYPE", "IN-USER", "IN-NAME", "PROCESS-PATH-REGEX", "PROCESS-PATH", "PROCESS-NAME-REGEX", "UID", "NETWORK", "DSCP", "SUB-RULE", "RULE-SET", "AND", "OR", "NOT"};
string_array Surge2RuleTypes = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
string_array SurgeRuleTypes = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "AND", "OR", "NOT", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
string_array QuanXRuleTypes = {basic_types, "USER-AGENT", "HOST", "HOST-SUFFIX", "HOST-KEYWORD"};
@@ -248,8 +250,26 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent>
strLine.erase(strLine.find("//"));
strLine = trimWhitespace(strLine);
}
strLine = transformRuleToCommon(temp, strLine, rule_group);
output_content += " - " + strLine + "\n";
//AND & OR & NOT
if(startsWith(strLine, "AND") || startsWith(strLine, "OR") || startsWith(strLine, "NOT"))
{
output_content += " - " + strLine + "," + rule_group + "\n";
}
//SUB-RULE & RULE-SET
else if (startsWith(strLine, "SUB-RULE") || startsWith(strLine, "RULE-SET"))
{
output_content += " - " + strLine + "\n";
}
else
//OTHER
{
strLine = transformRuleToCommon(temp, strLine, rule_group);
output_content += " - " + strLine + "\n";
}
//strLine = transformRuleToCommon(temp, strLine, rule_group);
//output_content += " - " + strLine + "\n";
total_rules++;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@ struct extra_settings
bool clash_classical_ruleset = false;
std::string sort_script;
std::string clash_proxies_style = "flow";
std::string clash_proxy_groups_style = "flow";
bool authorized = false;
extra_settings() = default;

View File

@@ -357,10 +357,10 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
if(x.rule_type == RULESET_CLASH_IPCIDR || x.rule_type == RULESET_CLASH_DOMAIN || x.rule_type == RULESET_CLASH_CLASSICAL)
{
//rule_name = std::to_string(hash_(rule_group + rule_path));
rule_name = old_rule_name = findFileName(rule_path);
rule_name = old_rule_name = urlDecode(findFileName(rule_path));
int idx = 2;
while(std::find(groups.begin(), groups.end(), rule_name) != groups.end())
rule_name = old_rule_name + "_" + std::to_string(idx++);
rule_name = old_rule_name + " " + std::to_string(idx++);
names[rule_name] = rule_group;
urls[rule_name] = "*" + rule_path;
rule_type[rule_name] = x.rule_type;
@@ -386,10 +386,10 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
if(fileExist(rule_path, true) || isLink(rule_path))
{
//rule_name = std::to_string(hash_(rule_group + rule_path));
rule_name = old_rule_name = findFileName(rule_path);
rule_name = old_rule_name = urlDecode(findFileName(rule_path));
int idx = 2;
while(std::find(groups.begin(), groups.end(), rule_name) != groups.end())
rule_name = old_rule_name + "_" + std::to_string(idx++);
rule_name = old_rule_name + " " + std::to_string(idx++);
names[rule_name] = rule_group;
urls[rule_name] = rule_path_typed;
rule_type[rule_name] = x.rule_type;
@@ -436,9 +436,9 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
if(vArray.size() < 2)
continue;
if(keywords.find(rule_name) == keywords.end())
keywords[rule_name] = "\"" + vArray[1] + "\"";
keywords[rule_name] = "\"" + trim(vArray[1]) + "\"";
else
keywords[rule_name] += ",\"" + vArray[1] + "\"";
keywords[rule_name] += ",\"" + trim(vArray[1]) + "\"";
}
else
{
@@ -449,7 +449,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
}
else
{
strLine = vArray[0] + "," + vArray[1] + "," + rule_group;
strLine = vArray[0] + "," + trim(vArray[1]) + "," + rule_group;
if(vArray.size() > 2)
strLine += "," + vArray[2];
}
@@ -466,14 +466,16 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
}
}
if(has_domain[rule_name] && !script)
rules.emplace_back("RULE-SET," + rule_name + "_domain," + rule_group);
rules.emplace_back("RULE-SET," + rule_name + " (Domain)," + rule_group);
if(has_ipcidr[rule_name] && !script)
{
if(has_no_resolve)
rules.emplace_back("RULE-SET," + rule_name + "_ipcidr," + rule_group + ",no-resolve");
rules.emplace_back("RULE-SET," + rule_name + " (IP-CIDR)," + rule_group + ",no-resolve");
else
rules.emplace_back("RULE-SET," + rule_name + "_ipcidr," + rule_group);
rules.emplace_back("RULE-SET," + rule_name + " (IP-CIDR)," + rule_group);
}
if(!has_domain[rule_name] && !has_ipcidr[rule_name] && !script)
rules.emplace_back("RULE-SET," + rule_name + "," + rule_group);
if(std::find(groups.begin(), groups.end(), rule_name) == groups.end())
groups.emplace_back(rule_name);
}
@@ -488,14 +490,14 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
{
std::string yaml_key = x;
if(rule_type[x] != RULESET_CLASH_DOMAIN)
yaml_key += "_domain";
yaml_key += " (Domain)";
base_rule["rule-providers"][yaml_key]["type"] = "http";
base_rule["rule-providers"][yaml_key]["behavior"] = "domain";
if(url[0] == '*')
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
else
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=3&url=" + urlSafeBase64Encode(url);
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + yaml_key + ".yaml";
base_rule["rule-providers"][yaml_key]["path"] = "./providers/" + std::to_string(hash_(url)) + "_domain.yaml";
if(interval)
base_rule["rule-providers"][yaml_key]["interval"] = interval;
}
@@ -503,14 +505,14 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
{
std::string yaml_key = x;
if(rule_type[x] != RULESET_CLASH_IPCIDR)
yaml_key += "_ipcidr";
yaml_key += " (IP-CIDR)";
base_rule["rule-providers"][yaml_key]["type"] = "http";
base_rule["rule-providers"][yaml_key]["behavior"] = "ipcidr";
if(url[0] == '*')
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
else
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=4&url=" + urlSafeBase64Encode(url);
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + yaml_key + ".yaml";
base_rule["rule-providers"][yaml_key]["path"] = "./providers/" + std::to_string(hash_(url)) + "_ipcidr.yaml";
if(interval)
base_rule["rule-providers"][yaml_key]["interval"] = interval;
}
@@ -523,7 +525,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector<RulesetContent> &rulese
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
else
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlSafeBase64Encode(url);
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + yaml_key + ".yaml";
base_rule["rule-providers"][yaml_key]["path"] = "./providers/" + std::to_string(hash_(url)) + ".yaml";
if(interval)
base_rule["rule-providers"][yaml_key]["interval"] = interval;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
#include <string>
#include <mutex>
#include <toml.hpp>
#include "config/binding.h"
#include "handler/webget.h"
@@ -566,13 +565,13 @@ void readYAMLConf(YAML::Node &node)
}
template <class T, class... U>
void find_if_exist(const toml::value &v, const toml::key &k, T& target, U&&... args)
void find_if_exist(const toml::value &v, const toml::value::key_type &k, T& target, U&&... args)
{
if(v.contains(k)) target = toml::find<T>(v, k);
if constexpr (sizeof...(args) > 0) find_if_exist(v, std::forward<U>(args)...);
}
void operate_toml_kv_table(const std::vector<toml::table> &arr, const toml::key &key_name, const toml::key &value_name, std::function<void (const toml::value&, const toml::value&)> binary_op)
void operate_toml_kv_table(const std::vector<toml::table> &arr, const toml::value::key_type &key_name, const toml::value::key_type &value_name, std::function<void (const toml::value&, const toml::value&)> binary_op)
{
for(const toml::table &table : arr)
{
@@ -801,7 +800,7 @@ void readConf()
return readYAMLConf(yaml);
}
toml::value conf = parseToml(prefdata, global.prefPath);
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
if(!conf.is_empty() && toml::find_or<int>(conf, "version", 0))
return readTOMLConf(conf);
}
catch (YAML::Exception &e)
@@ -1210,7 +1209,7 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
if(yaml.size() && yaml["custom"].IsDefined())
return loadExternalYAML(yaml, ext);
toml::value conf = parseToml(base_content, path);
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
if(!conf.is_empty() && toml::find_or<int>(conf, "version", 0))
return loadExternalTOML(conf, ext);
}
catch (YAML::Exception &e)

View File

@@ -13,6 +13,7 @@
#include "utils/string.h"
#include "utils/stl_extra.h"
#include "utils/tribool.h"
#include <toml.hpp>
struct Settings
{
@@ -48,7 +49,7 @@ struct Settings
tribool UDPFlag, TFOFlag, skipCertVerify, TLS13Flag, enableInsert;
bool enableSort = false, updateStrict = false;
bool clashUseNewField = false, singBoxAddClashModes = true;
std::string clashProxiesStyle = "flow";
std::string clashProxiesStyle = "flow", clashProxyGroupsStyle = "block";
std::string proxyConfig, proxyRuleset, proxySubscription;
int updateInterval = 0;
std::string sortScript, filterScript;
@@ -100,7 +101,12 @@ extern Settings global;
int importItems(string_array &target, bool scope_limit = true);
int loadExternalConfig(std::string &path, ExternalConfig &ext);
//template <class T, class... U>
//void find_if_exist(const toml::value &v, const toml::key &k, T& target, U&&... args)
//{
// if(v.contains(k)) target = toml::find<T>(v, k);
// if constexpr (sizeof...(args) > 0) find_if_exist(v, std::forward<U>(args)...);
//}
template <class... Args>
void parseGroupTimes(const std::string &src, Args... args)
{

View File

@@ -87,11 +87,13 @@ static int logger(CURL *handle, curl_infotype type, char *data, size_t size, voi
switch(type)
{
case CURLINFO_TEXT:
prefix = "CURL_INFO";
prefix = "CURL_INFO: ";
break;
case CURLINFO_HEADER_IN:
prefix = "CURL_HEADER: < ";
break;
case CURLINFO_HEADER_OUT:
prefix = "CURL_HEADER";
prefix = "CURL_HEADER: > ";
break;
case CURLINFO_DATA_IN:
case CURLINFO_DATA_OUT:
@@ -105,7 +107,6 @@ static int logger(CURL *handle, curl_infotype type, char *data, size_t size, voi
for(auto &x : lines)
{
std::string log_content = prefix;
log_content += ": ";
log_content += x;
writeLog(0, log_content, LOG_LEVEL_VERBOSE);
}
@@ -113,7 +114,6 @@ static int logger(CURL *handle, curl_infotype type, char *data, size_t size, voi
else
{
std::string log_content = prefix;
log_content += ": ";
log_content += trimWhitespace(content);
writeLog(0, log_content, LOG_LEVEL_VERBOSE);
}
@@ -172,7 +172,8 @@ static int curlGet(const FetchArgument &argument, FetchResult &result)
{
for(auto &x : *argument.request_headers)
{
header_list = curl_slist_append(header_list, (x.first + ": " + x.second).data());
auto header = x.first + ": " + x.second;
header_list = curl_slist_append(header_list, header.data());
}
if(!argument.request_headers->contains("User-Agent"))
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, user_agent_str);
@@ -233,7 +234,7 @@ static int curlGet(const FetchArgument &argument, FetchResult &result)
while(true)
{
retVal = curl_easy_perform(curl_handle);
if(retVal == CURLE_OK || max_fails <= fail_count)
if(retVal == CURLE_OK || max_fails <= fail_count || global.APIMode)
break;
else
fail_count++;

View File

@@ -233,10 +233,10 @@ int main(int argc, char *argv[])
}
}
std::string type = getUrlArg(request.argument, "type");
if(type == "form")
fileWrite(global.prefPath, getFormData(request.postdata), true);
else if(type == "direct")
if(type == "form" || type == "direct")
{
fileWrite(global.prefPath, request.postdata, true);
}
else
{
response.status_code = 501;

View File

@@ -9,7 +9,8 @@
using String = std::string;
using StringArray = std::vector<String>;
enum class ProxyType {
enum class ProxyType
{
Unknown,
Shadowsocks,
ShadowsocksR,
@@ -22,7 +23,8 @@ enum class ProxyType {
WireGuard,
VLESS,
Hysteria,
Hysteria2
Hysteria2,
TUIC
};
inline String getProxyTypeName(ProxyType type) {
@@ -51,6 +53,8 @@ inline String getProxyTypeName(ProxyType type) {
return "Hysteria";
case ProxyType::Hysteria2:
return "Hysteria2";
case ProxyType::TUIC:
return "Tuic";
default:
return "Unknown";
}
@@ -64,7 +68,7 @@ struct Proxy {
String Remark;
String Hostname;
uint16_t Port = 0;
String CongestionControl;
String Username;
String Password;
String EncryptMethod;
@@ -122,6 +126,17 @@ struct Proxy {
String ShortId;
String Flow;
bool FlowShow = false;
tribool DisableSni;
uint32_t UpSpeed;
uint32_t DownSpeed;
String SNI;
tribool ReduceRtt;
String UdpRelayMode = "native";
uint16_t RequestTimeout = 15000;
String token;
String UnderlyingProxy;
std::vector<String> AlpnList;
String PacketEncoding;
};
#define SS_DEFAULT_GROUP "SSProvider"
@@ -135,5 +150,6 @@ struct Proxy {
#define XRAY_DEFAULT_GROUP "XRayProvider"
#define HYSTERIA_DEFAULT_GROUP "HysteriaProvider"
#define HYSTERIA2_DEFAULT_GROUP "Hysteria2Provider"
#define TUIC_DEFAULT_GROUP "TuicProvider"
#endif // PROXY_H_INCLUDED

View File

@@ -36,7 +36,7 @@ std::string modSSMD5 = "f7653207090ce3389115e9c88541afe0";
void commonConstruct(Proxy &node, ProxyType type, const std::string &group, const std::string &remarks,
const std::string &server, const std::string &port, const tribool &udp, const tribool &tfo,
const tribool &scv, const tribool &tls13) {
const tribool &scv, const tribool &tls13,const std::string& underlying_proxy) {
node.Type = type;
node.Group = group;
node.Remark = remarks;
@@ -46,14 +46,16 @@ void commonConstruct(Proxy &node, ProxyType type, const std::string &group, cons
node.TCPFastOpen = tfo;
node.AllowInsecure = scv;
node.TLS13 = tls13;
node.UnderlyingProxy = underlying_proxy;
}
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 tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::VMess, group, remarks, add, port, udp, tfo, scv, tls13);
const std::string &edge, const std::string &tls, const std::string &sni,
const std::vector<std::string> &alpnList, tribool udp, tribool tfo,
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::VMess, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.UserId = id.empty() ? "00000000-0000-0000-0000-000000000000" : id;
node.AlterId = to_int(aid);
node.EncryptMethod = cipher;
@@ -75,8 +77,8 @@ void vmessConstruct(Proxy &node, const std::string &group, const std::string &re
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 tfo, tribool scv) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool());
const std::string &protoparam, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.EncryptMethod = method;
node.Protocol = protocol;
@@ -88,8 +90,8 @@ void ssrConstruct(Proxy &node, const std::string &group, const std::string &rema
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 tfo, tribool scv,
tribool tls13) {
commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13);
tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13,underlying_proxy);
node.Password = password;
node.EncryptMethod = method;
node.Plugin = plugin;
@@ -98,17 +100,17 @@ void ssConstruct(Proxy &node, const std::string &group, const std::string &remar
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 tfo, tribool scv) {
commonConstruct(node, ProxyType::SOCKS5, group, remarks, server, port, udp, tfo, scv, tribool());
tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::SOCKS5, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Username = username;
node.Password = password;
}
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 scv, tribool tls13) {
tribool tfo, tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, tls ? ProxyType::HTTPS : ProxyType::HTTP, group, remarks, server, port, tribool(), tfo, scv,
tls13);
tls13,underlying_proxy);
node.Username = username;
node.Password = password;
node.TLSSecure = tls;
@@ -117,10 +119,11 @@ 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, const std::string &sni,
const std::vector<std::string> &alpnList,
bool tlssecure,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13);
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13,underlying_proxy);
node.Password = password;
node.Host = host;
node.TLSSecure = tlssecure;
@@ -128,12 +131,13 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
node.Path = path;
node.Fingerprint = fp;
node.ServerName = sni;
node.AlpnList = alpnList;
}
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, tribool udp, tribool tfo, tribool scv) {
commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool());
const std::string &host, uint16_t version, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.OBFS = obfs;
node.Host = host;
@@ -144,8 +148,8 @@ void wireguardConstruct(Proxy &node, const std::string &group, const std::string
const std::string &port, const std::string &selfIp, const std::string &selfIpv6,
const std::string &privKey, const std::string &pubKey, const std::string &psk,
const string_array &dns, const std::string &mtu, const std::string &keepalive,
const std::string &testUrl, const std::string &clientId, const tribool &udp) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool());
const std::string &testUrl, const std::string &clientId, const tribool &udp,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool(),underlying_proxy);
node.SelfIP = selfIp;
node.SelfIPv6 = selfIpv6;
node.PrivateKey = privKey;
@@ -165,8 +169,8 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
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);
tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Hysteria, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.Auth = auth;
node.Host = (host.empty() && !isIPv4(add) && !isIPv6(add)) ? add.data() : trim(host);
node.UpMbps = up;
@@ -186,9 +190,10 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
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, const std::string &sni,
const std::vector<std::string> &alpnList,const std::string &packet_encoding,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::VLESS, group, remarks, add, port, udp, tfo, scv, tls13);
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::VLESS, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.UserId = id.empty() ? "00000000-0000-0000-0000-000000000000" : id;
node.AlterId = to_int(aid);
node.EncryptMethod = cipher;
@@ -201,6 +206,8 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
node.ShortId = sid;
node.Fingerprint = fp;
node.ServerName = sni;
node.AlpnList = alpnList;
node.PacketEncoding = packet_encoding;
switch (hash_(net)) {
case "grpc"_hash:
node.Host = host;
@@ -223,10 +230,10 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
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,
const std::string &publicKey, const std::string &ports,
tribool udp, tribool tfo,
tribool scv) {
commonConstruct(node, ProxyType::Hysteria2, group, remarks, add, port, udp, tfo, scv, tribool());
tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Hysteria2, group, remarks, add, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.Host = (host.empty() && !isIPv4(add) && !isIPv6(add)) ? add.data() : trim(host);
node.UpMbps = up;
@@ -236,8 +243,30 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
node.OBFSPassword = obfsPassword;
node.ServerName = sni;
node.PublicKey = publicKey;
node.Ports = ports;
}
void tuicConstruct(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 &congestion_control,
const std::string &alpn,
const std::string &sni, const std::string &uuid, const std::string &udpRelayMode,
const std::string &token,
tribool udp, tribool tfo,
tribool scv, tribool reduceRtt, tribool disableSni, uint16_t request_timeout,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::TUIC, group, remarks, add, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.Alpn = alpn;
node.ServerName = sni;
node.CongestionControl = congestion_control;
node.ReduceRtt = reduceRtt;
node.DisableSni = disableSni;
node.UserId = uuid;
node.UdpRelayMode = udpRelayMode;
node.token = token;
node.RequestTimeout = request_timeout;
}
void explodeVmess(std::string vmess, Proxy &node) {
std::string version, ps, add, port, type, id, aid, net, path, host, tls, sni;
Document jsondata;
@@ -297,7 +326,7 @@ void explodeVmess(std::string vmess, Proxy &node) {
add = trim(add);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, ps, add, port, type, id, aid, net, "auto", path, host, "", tls, sni);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, ps, add, port, type, id, aid, net, "auto", path, host, "", tls, sni,std::vector<std::string>{});
}
void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
@@ -368,7 +397,7 @@ void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
}
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, add + ":" + port, add, port, type, id, aid, net, cipher, path,
host, edge, tls, "", udp, tfo, scv);
host, edge, tls, "",std::vector<std::string>{}, udp, tfo, scv);
nodes.emplace_back(std::move(node));
}
return;
@@ -421,7 +450,7 @@ void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
json["vmess"][i]["security"] >> cipher;
json["vmess"][i]["sni"] >> sni;
vmessConstruct(node, V2RAY_DEFAULT_GROUP, ps, add, port, type, id, aid, net, cipher, path, host, "",
tls, sni, udp, tfo, scv);
tls, sni,std::vector<std::string>{}, udp, tfo, scv);
break;
case 3: //ss config
json["vmess"][i]["id"] >> id;
@@ -859,8 +888,13 @@ void explodeTrojan(std::string trojan, Proxy &node) {
remark = server + ":" + port;
if (group.empty())
group = TROJAN_DEFAULT_GROUP;
trojanConstruct(node, group, remark, server, port, psk, network, host, path, fp, sni, true, tribool(), tfo, scv);
std::string alpn = getUrlArg(addition, "alpn");
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
trojanConstruct(node, group, remark, server, port, psk, network, host, path, fp, sni, alpnList, true, tribool(),
tfo, scv);
}
void explodeVless(std::string vless, Proxy &node) {
@@ -948,7 +982,7 @@ void explodeQuan(const std::string &quan, Proxy &node) {
if (path.empty())
path = "/";
vmessConstruct(node, group, ps, add, port, type, id, aid, net, cipher, path, host, edge, tls, "");
vmessConstruct(node, group, ps, add, port, type, id, aid, net, cipher, path, host, edge, tls, "",std::vector<std::string>{});
}
}
@@ -1014,10 +1048,11 @@ void explodeNetch(std::string netch, Proxy &node) {
edge = GetMember(json, "Edge");
tls = GetMember(json, "TLSSecure");
sni = GetMember(json, "ServerName");
if (group.empty())
group = V2RAY_DEFAULT_GROUP;
vmessConstruct(node, group, remark, address, port, faketype, id, aid, transprot, method, path, host, edge,
tls, sni, udp, tfo, scv);
tls, sni,std::vector<std::string>{}, udp, tfo, scv);
break;
case "Socks5"_hash:
username = GetMember(json, "Username");
@@ -1039,7 +1074,8 @@ void explodeNetch(std::string netch, Proxy &node) {
sni = host;
if (group.empty())
group = TROJAN_DEFAULT_GROUP;
trojanConstruct(node, group, remark, address, port, password, transprot, host, path, fp, sni, tls == "true",
trojanConstruct(node, group, remark, address, port, password, transprot, host, path, fp, sni,
std::vector<std::string>{}, tls == "true",
udp,
tfo, scv);
break;
@@ -1063,7 +1099,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
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 fp = "chrome", pbk, sid,packet_encoding; //vless
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string flow, mode; //trojan
@@ -1071,8 +1107,11 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
std::string ip, ipv6, private_key, public_key, mtu; //wireguard
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
std::string obfsPassword;//hysteria2
std::string congestion_control, udp_relay_mode, token;// tuic
string_array dns_server;
tribool udp, tfo, scv;
bool reduceRtt, disableSni;//tuic
std::vector<std::string> alpnList;
Proxy node;
singleproxy = yamlnode[section][i];
singleproxy["type"] >>= proxytype;
@@ -1125,8 +1164,9 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
break;
}
tls = safe_as<std::string>(singleproxy["tls"]) == "true" ? "tls" : "";
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni, udp,
singleproxy["alpn"] >>= alpnList;
vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni,
alpnList, udp,
tfo, scv);
break;
case "ss"_hash:
@@ -1245,8 +1285,10 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
path.clear();
break;
}
singleproxy["alpn"] >>= alpnList;
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, true, udp, tfo, scv);
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, alpnList, true, udp,
tfo, scv);
break;
case "snell"_hash:
group = SNELL_DEFAULT_GROUP;
@@ -1268,7 +1310,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["ipv6"] >>= ipv6;
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp);
dns_server, mtu, "0", "", "", udp,"");
break;
case "vless"_hash:
group = XRAY_DEFAULT_GROUP;
@@ -1318,9 +1360,13 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["reality-opts"]["short-id"] >>= sid;
}
singleproxy["flow"] >>= flow;
singleproxy["client-fingerprint"] >>= fp;
singleproxy["alpn"] >>= alpnList;
singleproxy["packet-encoding"] >>= packet_encoding;
bool vless_udp;
singleproxy["udp"] >> vless_udp;
vlessConstruct(node, XRAY_DEFAULT_GROUP, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp, sni);
host, "", tls, pbk, sid, fp, sni, alpnList,packet_encoding,udp);
break;
case "hysteria"_hash:
group = HYSTERIA_DEFAULT_GROUP;
@@ -1337,6 +1383,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["protocol"] >> type;
singleproxy["sni"] >> host;
singleproxy["alpn"][0] >> alpn;
singleproxy["alpn"] >> alpnList;
singleproxy["protocol"] >> insecure;
singleproxy["ports"] >> ports;
sni = host;
@@ -1355,9 +1402,31 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["obfs-password"] >>= obfsPassword;
singleproxy["sni"] >>= host;
singleproxy["alpn"][0] >>= alpn;
singleproxy["ports"] >> ports;
sni = host;
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, sni, public_key, udp, tfo, scv);
obfsPassword, sni, public_key, ports, udp, tfo, scv);
break;
case "tuic"_hash:
group = TUIC_DEFAULT_GROUP;
uint16_t request_timeout;
singleproxy["password"] >>= password;
singleproxy["uuid"] >>= id;
singleproxy["congestion-controller"] >>= congestion_control;
singleproxy["udp-relay-mode"] >>= udp_relay_mode;
singleproxy["sni"] >>= sni;
if (!singleproxy["alpn"].IsNull()) {
singleproxy["alpn"][0] >>= alpn;
}
singleproxy["disable-sni"] >>= disableSni;
singleproxy["reduce-rtt"] >>= reduceRtt;
singleproxy["token"] >>= token;
singleproxy["request-timeout"] >>= request_timeout;
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn, sni, id,
udp_relay_mode, token,
tribool(),
tribool(), scv, reduceRtt, disableSni, request_timeout);
break;
default:
continue;
@@ -1405,8 +1474,12 @@ void explodeStdVMess(std::string vmess, Proxy &node) {
if (remarks.empty())
remarks = add + ":" + port;
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", path, host, "", tls, "");
std::string alpn = getUrlArg(addition, "alpn");
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", path, host, "", tls, "",alpnList);
}
@@ -1437,7 +1510,10 @@ void explodeStdHysteria(std::string hysteria, Proxy &node) {
if (remarks.empty())
remarks = add + ":" + port;
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
hysteriaConstruct(node, HYSTERIA_DEFAULT_GROUP, remarks, add, port, type, auth, auth_str, host, up, down, alpn,
obfsParam,
insecure, "", sni);
@@ -1445,7 +1521,7 @@ void explodeStdHysteria(std::string hysteria, Proxy &node) {
}
void explodeStdHysteria2(std::string hysteria2, Proxy &node) {
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks, sni;
std::string add, port, password, host, insecure, up, down, alpn, obfsParam, obfsPassword, remarks, sni, ports;
std::string addition;
tribool scv;
hysteria2 = hysteria2.substr(12);
@@ -1486,11 +1562,12 @@ void explodeStdHysteria2(std::string hysteria2, Proxy &node) {
obfsPassword = getUrlArg(addition, "obfs-password");
host = getUrlArg(addition, "sni");
sni = getUrlArg(addition, "sni");
ports = getUrlArg(addition, "ports");
if (remarks.empty())
remarks = add + ":" + port;
hysteria2Construct(node, HYSTERIA2_DEFAULT_GROUP, remarks, add, port, password, host, up, down, alpn, obfsParam,
obfsPassword, host, "", tribool(), tribool(), scv);
obfsPassword, host, "", ports, tribool(), tribool(), scv);
return;
}
@@ -1506,7 +1583,7 @@ void explodeStdVless(std::string vless, Proxy &node) {
remarks = urlDecode(vless.substr(pos + 1));
vless.erase(pos);
}
const std::string stdvless_matcher = R"(^([\da-f]{4}(?:[\da-f]{4}-){4}[\da-f]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
const std::string stdvless_matcher = R"(^([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
if (regGetMatch(vless, stdvless_matcher, 5, 0, &id, &add, &port, &addition))
return;
@@ -1516,7 +1593,12 @@ void explodeStdVless(std::string vless, Proxy &node) {
pbk = getUrlArg(addition, "pbk");
sid = getUrlArg(addition, "sid");
fp = getUrlArg(addition, "fp");
std::string packet_encoding = getUrlArg(addition, "packet-encoding");
std::string alpn = getUrlArg(addition, "alpn");
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
switch (hash_(net)) {
case "tcp"_hash:
case "ws"_hash:
@@ -1543,7 +1625,7 @@ void explodeStdVless(std::string vless, Proxy &node) {
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, sni);
tls, pbk, sid, fp, sni, alpnList,packet_encoding);
return;
}
@@ -1582,8 +1664,12 @@ void explodeShadowrocket(std::string rocket, Proxy &node) {
if (remarks.empty())
remarks = add + ":" + port;
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "");
std::string alpn = getUrlArg(addition, "alpn");
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",alpnList);
}
void explodeKitsunebi(std::string kit, Proxy &node) {
@@ -1617,8 +1703,12 @@ void explodeKitsunebi(std::string kit, Proxy &node) {
if (remarks.empty())
remarks = add + ":" + port;
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "");
std::string alpn = getUrlArg(addition, "alpn");
std::vector<std::string> alpnList;
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",alpnList);
}
// peer = (public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, allowed-ips = "0.0.0.0/0, ::/0", endpoint = engage.cloudflareclient.com:2408, client-id = 139/184/125),(public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, endpoint = engage.cloudflareclient.com:2408)
@@ -1904,7 +1994,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, server, port, "", id, aead, net, method, path, host,
edge, tls, "", udp, tfo, scv, tls13);
edge, tls, "",std::vector<std::string>{}, udp, tfo, scv, tls13);
break;
case "http"_hash: //http proxy
server = trim(configs[1]);
@@ -1971,6 +2061,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
}
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", fp, sni,
std::vector<std::string>{},
true,
udp,
tfo, scv);
@@ -2070,7 +2161,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
}
wireguardConstruct(node, WG_DEFAULT_GROUP, remarks, "", "0", ip, ipv6, private_key, "", "", dns_servers,
mtu, keepalive, test_url, "", udp);
mtu, keepalive, test_url, "", udp,"");
parsePeers(node, peer);
break;
default:
@@ -2234,7 +2325,74 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
remarks = server + ":" + port;
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, server, port, "", id, aead, net, method,
path, host, "", tls, "", udp, tfo, scv, tls13);
path, host, "", tls, "",std::vector<std::string>{}, udp, tfo, scv, tls13);
break;
case "vless"_hash: //quantumult x style vless link
server = trim(configs[0].substr(0, configs[0].rfind(":")));
port = trim(configs[0].substr(configs[0].rfind(":") + 1));
if (port == "0")
continue;
net = "tcp";
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
itemVal = trim(vArray[1]);
switch (hash_(itemName)) {
case "method"_hash:
method = itemVal;
break;
case "password"_hash:
id = itemVal;
break;
case "tag"_hash:
remarks = itemVal;
break;
case "obfs"_hash:
switch (hash_(itemVal)) {
case "ws"_hash:
net = "ws";
break;
case "over-tls"_hash:
tls = "tls";
break;
case "wss"_hash:
net = "ws";
tls = "tls";
break;
}
break;
case "obfs-host"_hash:
host = itemVal;
break;
case "obfs-uri"_hash:
path = itemVal;
break;
case "over-tls"_hash:
tls = itemVal == "true" ? "tls" : "";
break;
case "udp-relay"_hash:
udp = itemVal;
break;
case "fast-open"_hash:
tfo = itemVal;
break;
case "tls13"_hash:
tls13 = itemVal;
break;
case "aead"_hash:
aead = itemVal == "true" ? "0" : "1";
default:
continue;
}
}
if (remarks.empty())
remarks = server + ":" + port;
vlessConstruct(node, XRAY_DEFAULT_GROUP, remarks, server, port, "", id, aead, net, method,
"chrome", "", path, host, "",
tls, "", "", fp, sni, std::vector<std::string>{},"", udp, tfo, scv, tls13);
break;
case "trojan"_hash: //quantumult x style trojan link
server = trim(configs[0].substr(0, configs[0].rfind(':')));
@@ -2285,7 +2443,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,
sni, std::vector<std::string>{},
tls == "true", udp, tfo, scv, tls13);
break;
case "http"_hash: //quantumult x style http links
@@ -2514,7 +2672,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
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 fp = "chrome", pbk, sid,packet_encoding; //vless
std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss
std::string protocol, protoparam, obfs, obfsparam; //ssr
std::string flow, mode; //trojan
@@ -2523,7 +2681,8 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
std::string auth, up, down, obfsParam, insecure, alpn;//hysteria
std::string obfsPassword;//hysteria2
string_array dns_server;
tribool udp, tfo, scv;
std::string congestion_control, udp_relay_mode;//quic
tribool udp, tfo, scv, rrt, disableSni;
rapidjson::Value singboxNode = outbounds[i].GetObject();
if (singboxNode.HasMember("type") && singboxNode["type"].IsString()) {
Proxy node;
@@ -2532,6 +2691,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
server = GetMember(singboxNode, "server");
port = GetMember(singboxNode, "server_port");
tfo = GetMember(singboxNode, "tcp_fast_open");
std::vector<std::string> alpnList;
if (singboxNode.HasMember("tls") && singboxNode["tls"].IsObject()) {
rapidjson::Value tlsObj = singboxNode["tls"].GetObject();
if (tlsObj.HasMember("enabled") && tlsObj["enabled"].IsBool() && tlsObj["enabled"].GetBool()) {
@@ -2542,11 +2702,18 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
rapidjson::Value alpns = tlsObj["alpn"].GetArray();
if (alpns.Size() > 0) {
alpn = alpns[0].GetString();
for (auto &item: tlsObj["alpn"].GetArray()) {
if (item.IsString())
alpnList.emplace_back(item.GetString());
}
}
}
if (tlsObj.HasMember("insecure") && tlsObj["insecure"].IsBool()) {
scv = tlsObj["insecure"].GetBool();
}
if (tlsObj.HasMember("disable_sni") && tlsObj["disable_sni"].IsBool()) {
disableSni = tlsObj["disable_sni"].GetBool();
}
if (tlsObj.HasMember("certificate") && tlsObj["certificate"].IsString()) {
public_key = tlsObj["certificate"].GetString();
}
@@ -2577,7 +2744,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
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,
sni,alpnList, udp,
tfo, scv);
break;
case "shadowsocks"_hash:
@@ -2592,7 +2759,8 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
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,
trojanConstruct(node, group, ps, server, port, password, net, host, path, fp, sni, alpnList,
true, udp,
tfo,
scv);
break;
@@ -2600,6 +2768,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
group = XRAY_DEFAULT_GROUP;
id = GetMember(singboxNode, "uuid");
flow = GetMember(singboxNode, "flow");
packet_encoding = GetMember(singboxNode,"packet_encoding");
if (singboxNode.HasMember("transport") && singboxNode["transport"].IsObject()) {
rapidjson::Value transport = singboxNode["transport"].GetObject();
net = GetMember(transport, "type");
@@ -2636,8 +2805,9 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
}
}
}
vlessConstruct(node, group, ps, server, port, type, id, aid, net, "auto", flow, mode, path,
host, "", tls, pbk, sid, fp, sni);
host, "", tls, pbk, sid, fp, sni, alpnList,packet_encoding,udp);
break;
case "http"_hash:
password = GetMember(singboxNode, "password");
@@ -2654,7 +2824,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
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);
dns_server, mtu, "0", "", "", udp,"");
break;
case "socks"_hash:
group = SOCKS_DEFAULT_GROUP;
@@ -2690,7 +2860,21 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
obfsPassword = GetMember(obfsOpt, "password");
}
hysteria2Construct(node, group, ps, server, port, password, host, up, down, alpn, obfsParam,
obfsPassword, sni,public_key, udp, tfo, scv);
obfsPassword, sni, public_key, "", udp, tfo, scv);
break;
case "tuic"_hash:
group = TUIC_DEFAULT_GROUP;
password = GetMember(singboxNode, "password");
id = GetMember(singboxNode, "uuid");
congestion_control = GetMember(singboxNode, "congestion_control");
if (singboxNode.HasMember("zero_rtt_handshake") && singboxNode["zero_rtt_handshake"].IsBool()) {
rrt = singboxNode["zero_rtt_handshake"].GetBool();
}
udp_relay_mode = GetMember(singboxNode, "udp_relay_mode");
tuicConstruct(node, TUIC_DEFAULT_GROUP, ps, server, port, password, congestion_control, alpn,
sni, id, udp_relay_mode, "",
tribool(),
tribool(), scv, rrt, disableSni);
break;
default:
continue;
@@ -2703,6 +2887,67 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
}
}
void explodeTuic(const std::string &tuic, Proxy &node) {
std::string add, port, password, host, insecure, alpn, remarks, sni, ports, congestion_control;
std::string addition;
tribool scv;
std::string link = tuic.substr(7);
string_size pos;
pos = link.rfind("#");
if (pos != std::string::npos) {
remarks = urlDecode(link.substr(pos + 1));
link.erase(pos);
}
pos = link.rfind("?");
if (pos != std::string::npos) {
addition = link.substr(pos + 1);
link.erase(pos);
}
std::string uuid;
pos = link.find(":");
if (pos != std::string::npos) {
uuid = link.substr(0, pos);
link = link.substr(pos + 1);
if (strFind(link, "@")) {
pos = link.find("@");
if (pos != std::string::npos) {
password = link.substr(0, pos);
link = link.substr(pos + 1);
}
}
}
pos = link.find(":");
if (pos != std::string::npos) {
add = link.substr(0, pos);
link = link.substr(pos + 1);
pos = link.find("?");
if (pos != std::string::npos) {
port = link.substr(0, pos);
addition = link.substr(pos + 1);
} else {
port = link;
}
}
scv = getUrlArg(addition, "insecure");
alpn = getUrlArg(addition, "alpn");
sni = getUrlArg(addition, "sni");
congestion_control = getUrlArg(addition, "congestion_control");
if (remarks.empty())
remarks = add + ":" + port;
tuicConstruct(node, TUIC_DEFAULT_GROUP, remarks, add, port, password, congestion_control, alpn, sni, uuid, "native",
"",
tribool(),
tribool(), scv);
return;
}
void explode(const std::string &link, Proxy &node) {
if (startsWith(link, "ssr://"))
explodeSSR(link, node);
@@ -2722,6 +2967,8 @@ void explode(const std::string &link, Proxy &node) {
explodeVless(link, node);
else if (strFind(link, "hysteria://") || strFind(link, "hy://"))
explodeHysteria(link, node);
else if (strFind(link, "tuic://"))
explodeTuic(link, node);
else if (strFind(link, "hysteria2://") || strFind(link, "hy2://"))
explodeHysteria2(link, node);
else if (isLink(link))

View File

@@ -25,59 +25,71 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
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());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
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,
const std::string &publicKey, const std::string &ports,
tribool udp, tribool tfo,
tribool scv);
tribool scv,const std::string& underlying_proxy="");
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,
const std::vector<std::string> &alpnList,const std::string &packet_encoding,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
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());
const std::string &edge, const std::string &tls, const std::string &sni,
const std::vector<std::string> &alpnList, tribool udp = tribool(),
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
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());
tribool scv = tribool(),const std::string& underlying_proxy="");
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());
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
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());
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),const std::string& underlying_proxy="");
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());
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
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,
const std::vector<std::string> &alpnList,
bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
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());
tribool scv = tribool(),const std::string& underlying_proxy="");
void tuicConstruct(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 &congestion_control,
const std::string &alpn,
const std::string &sni, const std::string &uuid, const std::string &udpRelayMode,
const std::string &token,
tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool(), tribool reduceRtt = tribool(), tribool disableSni = tribool(),
uint16_t request_timeout = 15000,const std::string& underlying_proxy="");
void explodeVmess(std::string vmess, Proxy &node);

View File

@@ -2,6 +2,7 @@
#include <map>
#include <iostream>
#include <quickjspp.hpp>
#include <utility>
#include <quickjs/quickjs-libc.h>
#ifdef _WIN32
@@ -226,7 +227,7 @@ public:
qjs_fetch_Headers headers;
std::string cookies;
std::string postdata;
explicit qjs_fetch_Request(const std::string &url) : url(url) {}
explicit qjs_fetch_Request(std::string url) : url(std::move(url)) {}
};
class qjs_fetch_Response
@@ -389,7 +390,7 @@ void script_runtime_init(qjs::Runtime &runtime)
js_std_init_handlers(runtime.rt);
}
int ShowMsgbox(const std::string &title, std::string content, uint16_t type = 0)
int ShowMsgbox(const std::string &title, const std::string &content, uint16_t type = 0)
{
#ifdef _WIN32
if(!type)
@@ -424,7 +425,7 @@ struct Lambda {
uint32_t currentTime()
{
return time(NULL);
return time(nullptr);
}
int script_context_init(qjs::Context &context)
@@ -525,7 +526,7 @@ int script_context_init(qjs::Context &context)
)", "<import>", JS_EVAL_TYPE_MODULE);
return 0;
}
catch(qjs::exception)
catch(qjs::exception&)
{
script_print_stack(context);
return 1;

View File

@@ -47,16 +47,23 @@ static httplib::Server::Handler makeHandler(const responseRoute &rr)
{
continue;
}
req.headers[h.first] = h.second;
req.headers.emplace(h.first.data(), h.second.data());
}
req.argument = request.params;
if (request.get_header_value("Content-Type") == "application/x-www-form-urlencoded")
if (request.method == "POST" || request.method == "PUT" || request.method == "PATCH")
{
req.postdata = urlDecode(request.body);
}
else
{
req.postdata = request.body;
if (request.is_multipart_form_data() && !request.files.empty())
{
req.postdata = request.files.begin()->second.content;
}
else if (request.get_header_value("Content-Type") == "application/x-www-form-urlencoded")
{
req.postdata = urlDecode(request.body);
}
else
{
req.postdata = request.body;
}
}
auto result = rr.rc(req, resp);
response.status = resp.status_code;
@@ -163,6 +170,7 @@ int WebServer::start_web_server_multi(listener_args *args)
{
res.set_header("Access-Control-Allow-Headers", req.get_header_value("Access-Control-Request-Headers"));
}
res.set_header("Access-Control-Allow-Origin", "*");
return httplib::Server::HandlerResponse::Unhandled;
});
for (auto &x : redirect_map)
@@ -187,7 +195,7 @@ int WebServer::start_web_server_multi(listener_args *args)
{
try
{
std::rethrow_exception(e);
if (e) std::rethrow_exception(e);
}
catch (const httplib::Error &err)
{
@@ -212,6 +220,9 @@ int WebServer::start_web_server_multi(listener_args *args)
{
server.set_mount_point("/", serve_file_root);
}
server.new_task_queue = [args] {
return new httplib::ThreadPool(args->max_workers);
};
server.bind_to_port(args->listen_address, args->port, 0);
std::thread thread([&]()

View File

@@ -26,7 +26,8 @@ std::string getTime(int type)
format = "%Y%m%d-%H%M%S";
break;
case 2:
format = "%Y/%m/%d %a %H:%M:%S." + std::string(cMillis);
format = "%Y/%m/%d %a %H:%M:%S.";
format += cMillis;
break;
case 3:
default:

View File

@@ -5,9 +5,16 @@
#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()) > 0;
struct strICaseComp
{
bool operator() (const std::string &lhs, const std::string &rhs) const
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end(),
[](unsigned char c1, unsigned char c2)
{
return ::tolower(c1) < ::tolower(c2);
});
}
};

View File

@@ -3,88 +3,38 @@
#include <sstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <cstdlib>
#include <ctime>
#include <random>
#include "string.h"
#include "map_extra.h"
std::vector<std::string> split(const std::string &s, const std::string &separator)
{
string_size bpos = 0, epos = s.find(separator);
std::vector<std::string> result;
string_size i = 0;
while(i != s.size())
while(bpos < s.size())
{
int flag = 0;
while(i != s.size() && flag == 0)
{
flag = 1;
for(char x : separator)
if(s[i] == x)
{
++i;
flag = 0;
break;
}
}
flag = 0;
string_size j = i;
while(j != s.size() && flag == 0)
{
for(char x : separator)
if(s[j] == x)
{
flag = 1;
break;
}
if(flag == 0)
++j;
}
if(i != j)
{
result.push_back(s.substr(i, j-i));
i = j;
}
if(epos == std::string::npos)
epos = s.size();
result.push_back(s.substr(bpos, epos - bpos));
bpos = epos + separator.size();
epos = s.find(separator, bpos);
}
return result;
}
void split(std::vector<std::string_view> &result, std::string_view s, char separator)
{
string_size i = 0;
while (i != s.size())
string_size bpos = 0, epos = s.find(separator);
while(bpos < s.size())
{
int flag = 0;
while(i != s.size() && flag == 0)
{
flag = 1;
if(s[i] == separator)
{
++i;
flag = 0;
break;
}
}
flag = 0;
string_size j = i;
while(j != s.size() && flag == 0)
{
if(s[j] == separator)
{
flag = 1;
break;
}
++j;
}
if (i != j)
{
result.push_back(s.substr(i, j-i));
i = j;
}
if(epos == std::string_view::npos)
epos = s.size();
result.push_back(s.substr(bpos, epos - bpos));
bpos = epos + 1;
epos = s.find(separator, bpos);
}
}
@@ -141,7 +91,7 @@ std::string toUpper(const std::string &str)
void processEscapeChar(std::string &str)
{
string_size pos = str.find('\\');
while(pos != str.npos)
while(pos != std::string::npos)
{
if(pos == str.size())
break;
@@ -191,7 +141,7 @@ void processEscapeCharReverse(std::string &str)
int parseCommaKeyValue(const std::string &input, const std::string &separator, string_pair_array &result)
{
string_size bpos = 0, epos = input.find(',');
string_size bpos = 0, epos = input.find(separator);
std::string kv;
while(bpos < input.size())
{
@@ -200,9 +150,9 @@ int parseCommaKeyValue(const std::string &input, const std::string &separator, s
else if(epos && input[epos - 1] == '\\')
{
kv += input.substr(bpos, epos - bpos - 1);
kv += ',';
kv += separator;
bpos = epos + 1;
epos = input.find(',', bpos);
epos = input.find(separator, bpos);
continue;
}
kv += input.substr(bpos, epos - bpos);
@@ -213,9 +163,9 @@ int parseCommaKeyValue(const std::string &input, const std::string &separator, s
result.emplace_back(kv.substr(0, eqpos), kv.substr(eqpos + 1));
kv.clear();
bpos = epos + 1;
epos = input.find(',', bpos);
epos = input.find(separator, bpos);
}
if(kv.size())
if(!kv.empty())
{
string_size eqpos = kv.find('=');
if(eqpos == std::string::npos)
@@ -328,12 +278,12 @@ std::string getUrlArg(const std::string &url, const std::string &request)
while(pos)
{
pos = url.rfind(pattern, pos);
if(pos != url.npos)
if(pos != std::string::npos)
{
if(pos == 0 || url[pos - 1] == '&' || url[pos - 1] == '?')
{
pos += pattern.size();
return url.substr(pos, url.find("&", pos) - pos);
return url.substr(pos, url.find('&', pos) - pos);
}
}
else
@@ -410,23 +360,24 @@ bool isStrUTF8(const std::string &data)
std::string randomStr(int len)
{
std::string retData;
srand(time(NULL));
int cnt = 0;
while(cnt < len)
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 61);
for(int i = 0; i < len; i++)
{
switch((rand() % 3))
int r = dis(gen);
if (r < 26)
{
case 1:
retData += ('A' + rand() % 26);
break;
case 2:
retData += ('a' + rand() % 26);
break;
default:
retData += ('0' + rand() % 10);
break;
retData.push_back('a' + r);
}
else if (r < 52)
{
retData.push_back('A' + r - 26);
}
else
{
retData.push_back('0' + r - 52);
}
cnt++;
}
return retData;
}
@@ -451,7 +402,7 @@ int to_int(const std::string &str, int def_value)
std::string join(const string_array &arr, const std::string &delimiter)
{
if(arr.size() == 0)
if(arr.empty())
return "";
if(arr.size() == 1)
return arr[0];

View File

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