From eef532850633b8d8266240ddb611a14397b2fff7 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:46:52 +0800 Subject: [PATCH 01/43] Enhancements Refine libcurl logs. Do not retry web request on API mode. Optimize codes. --- src/handler/webget.cpp | 13 +++++++------ src/script/script_quickjs.cpp | 9 +++++---- src/utils/logger.cpp | 3 ++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/handler/webget.cpp b/src/handler/webget.cpp index 736aaa5..4433536 100644 --- a/src/handler/webget.cpp +++ b/src/handler/webget.cpp @@ -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++; diff --git a/src/script/script_quickjs.cpp b/src/script/script_quickjs.cpp index b745b8f..ebf230b 100644 --- a/src/script/script_quickjs.cpp +++ b/src/script/script_quickjs.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #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) )", "", JS_EVAL_TYPE_MODULE); return 0; } - catch(qjs::exception) + catch(qjs::exception&) { script_print_stack(context); return 1; diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp index a7694d5..ec6353b 100644 --- a/src/utils/logger.cpp +++ b/src/utils/logger.cpp @@ -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: From be2de493603353627b668c6eb8a720afd2b938e5 Mon Sep 17 00:00:00 2001 From: aylz10 Date: Tue, 2 Apr 2024 18:34:33 +0800 Subject: [PATCH 02/43] 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> --- src/server/webserver_httplib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/webserver_httplib.cpp b/src/server/webserver_httplib.cpp index 16dd9cc..2bf5590 100644 --- a/src/server/webserver_httplib.cpp +++ b/src/server/webserver_httplib.cpp @@ -47,7 +47,7 @@ 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") From 623ffbb23fc4dd50010f144df55583fd56c21c43 Mon Sep 17 00:00:00 2001 From: moexiami <1927254+Xiami2012@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:34:50 +0800 Subject: [PATCH 03/43] 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 --- base/pref.example.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/pref.example.toml b/base/pref.example.toml index b78a007..4e0c563 100644 --- a/base/pref.example.toml +++ b/base/pref.example.toml @@ -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. From 37c4e1307139501c6691ba312870691778ae77a3 Mon Sep 17 00:00:00 2001 From: SummonHIM <2239760702@qq.com> Date: Tue, 2 Apr 2024 18:37:09 +0800 Subject: [PATCH 04/43] Add UA of Clash Verge to auto target (#713) --- src/handler/interfaces.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index d364398..6f138cd 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -65,6 +65,7 @@ const std::vector UAMatchList = { {"ClashForAndroid","","","clash",false}, {"ClashforWindows","\\/([0-9.]+)","0.11","clash",true}, {"ClashforWindows","","","clash",false}, + {"clash-verge","","","clash",true}, {"ClashX Pro","","","clash",true}, {"ClashX","\\/([0-9.]+)","0.13","clash",true}, {"Clash","","","clash",true}, From fb2aca323738f54e8c87d17b9bea411af0c1079b Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:51:20 +0800 Subject: [PATCH 05/43] * Fix Docker build --- .github/workflows/docker.yml | 327 ++++++++++++----------------------- 1 file changed, 113 insertions(+), 214 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f624e39..0c5e922 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,327 +9,226 @@ concurrency: group: ${{ github.ref }}-${{ github.workflow }} cancel-in-progress: true +env: + REGISTRY_IMAGE: tindy2013/subconverter + jobs: - amd64_build: - name: Build AMD64 Image + gh_builds: runs-on: ubuntu-latest + strategy: + matrix: + platform: [linux/amd64, linux/386] 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 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + 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@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Get commit SHA + if: github.ref == 'refs/heads/master' 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 + uses: docker/build-push-action@v5 with: - platforms: linux/amd64 + platforms: ${{ matrix.platform }} context: scripts/ - tags: tindy2013/subconverter:latest + labels: ${{ steps.meta.outputs.labels }} build-args: | SHA=${{ steps.vars.outputs.sha_short }} - outputs: type=image,push=true + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,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: tindy2013/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: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 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: tindy2013/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/ - tags: tindy2013/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 + name: digest-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 armv7_build: name: Build ARMv7 Image runs-on: [self-hosted, linux, ARM] steps: - name: Checkout base - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + 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@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Get commit SHA + if: github.ref == 'refs/heads/master' 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 + uses: docker/build-push-action@v5 with: platforms: linux/arm/v7 context: scripts/ - tags: tindy2013/subconverter:latest + labels: ${{ steps.meta.outputs.labels }} 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: tindy2013/subconverter:${{steps.version.outputs.result}} - build-args: | - THREADS=4 - outputs: type=image,push=true - - - name: Save digest - if: github.ref == 'refs/heads/master' - run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt - - - name: Save release digest - if: startsWith(github.ref, 'refs/tags/') - run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: digest_armv7 - path: /tmp/digest.txt + name: digest-arm-v7 + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 arm64_build: name: Build ARM64 Image runs-on: [self-hosted, linux, ARM64] steps: - name: Checkout base - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + 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@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Get commit SHA + if: github.ref == 'refs/heads/master' 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 + uses: docker/build-push-action@v5 with: platforms: linux/arm64 context: scripts/ - tags: tindy2013/subconverter:latest + labels: ${{ steps.meta.outputs.labels }} 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: tindy2013/subconverter:${{steps.version.outputs.result}} - build-args: | - THREADS=4 - outputs: type=image,push=true - - - name: Save digest - if: github.ref == 'refs/heads/master' - run: echo ${{ steps.build.outputs.digest }} > /tmp/digest.txt - - - name: Save release digest - if: startsWith(github.ref, 'refs/tags/') - run: echo ${{ steps.build_rel.outputs.digest }} > /tmp/digest.txt + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: digest_arm64 - path: /tmp/digest.txt + name: digest-arm64 + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 build: name: Build - needs: [amd64_build, x86_build, armv7_build, arm64_build] + needs: [gh_builds, armv7_build, arm64_build] runs-on: ubuntu-latest steps: - - name: Checkout base - uses: actions/checkout@v3 + - name: Download digests + uses: actions/download-artifact@v4 with: - fetch-depth: 0 + path: /tmp/digests + pattern: digests-* + merge-multiple: true - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - # 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 - if: github.ref == 'refs/heads/master' - run: python scripts/merge_manifest.py - - - name: Merge and push manifest on release - if: startsWith(github.ref, 'refs/tags/') - run: python scripts/merge_manifest.py ${{steps.version.outputs.result}} + - 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 }} From 0cb4053f8dab40da5ba79624d726fd12018b7a85 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:01:59 +0800 Subject: [PATCH 06/43] Fix build error --- .github/workflows/docker.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0c5e922..47f99b3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,6 +18,7 @@ jobs: strategy: matrix: platform: [linux/amd64, linux/386] + name: Build ${{ matrix.platform }} Image steps: - name: Prepare run: | @@ -119,7 +120,7 @@ jobs: build-args: | SHA=${{ steps.vars.outputs.sha_short }} THREADS=4 - outputs: type=image,push=true + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | @@ -177,7 +178,7 @@ jobs: build-args: | SHA=${{ steps.vars.outputs.sha_short }} THREADS=4 - outputs: type=image,push=true + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | From 88635b6ed81411816aed49c99cd99a473c8a70d3 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:08:19 +0800 Subject: [PATCH 07/43] Fix build error --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 47f99b3..705796b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -203,7 +203,7 @@ jobs: uses: actions/download-artifact@v4 with: path: /tmp/digests - pattern: digests-* + pattern: digest-* merge-multiple: true - name: Set up Docker Buildx From c711f1ad057cadb836310a240ea93aef2bd86a31 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:24:31 +0800 Subject: [PATCH 08/43] Update Docker build workflow --- .github/workflows/docker.yml | 136 ++++------------------------------- 1 file changed, 14 insertions(+), 122 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 705796b..438a0c2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -13,11 +13,19 @@ env: REGISTRY_IMAGE: tindy2013/subconverter jobs: - gh_builds: - runs-on: ubuntu-latest + build: strategy: matrix: - platform: [linux/amd64, linux/386] + include: + - platform: linux/amd64 + os: ubuntu-latest + - platform: linux/386 + os: ubuntu-latest + - platform: linux/arm/v7 + os: [self-hosted, linux, ARM] + - platform: linux/arm64 + os: [self-hosted, linux, ARM64] + runs-on: ${{ matrix.os }} name: Build ${{ matrix.platform }} Image steps: - name: Prepare @@ -78,125 +86,9 @@ jobs: if-no-files-found: error retention-days: 1 - armv7_build: - name: Build ARMv7 Image - runs-on: [self-hosted, linux, ARM] - steps: - - name: Checkout base - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - 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: Get commit SHA - if: github.ref == 'refs/heads/master' - id: vars - run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - - - name: Build and export - id: build - uses: docker/build-push-action@v5 - with: - platforms: linux/arm/v7 - context: scripts/ - labels: ${{ steps.meta.outputs.labels }} - build-args: | - SHA=${{ steps.vars.outputs.sha_short }} - THREADS=4 - outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - - - name: Export digest - run: | - 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-arm-v7 - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - arm64_build: - name: Build ARM64 Image - runs-on: [self-hosted, linux, ARM64] - steps: - - name: Checkout base - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - 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: Get commit SHA - if: github.ref == 'refs/heads/master' - id: vars - run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - - - name: Build and export - id: build - uses: docker/build-push-action@v5 - with: - platforms: linux/arm64 - context: scripts/ - labels: ${{ steps.meta.outputs.labels }} - build-args: | - SHA=${{ steps.vars.outputs.sha_short }} - THREADS=4 - outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - - - name: Export digest - run: | - 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-arm64 - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - build: - name: Build - needs: [gh_builds, armv7_build, arm64_build] + merge: + name: Merge + needs: build runs-on: ubuntu-latest steps: - name: Download digests From 624f5cd120b2224a073c249c3dd355b520153e22 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:40:41 +0800 Subject: [PATCH 09/43] Clean up digests before creating new image digest --- .github/workflows/docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 438a0c2..a3d3350 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -74,6 +74,7 @@ jobs: - name: Export digest run: | + rm -r /tmp/digests mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" From 9e66b0725120b72a2b413afcd9af1b9582e27f5a Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:45:05 +0800 Subject: [PATCH 10/43] Force delete --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a3d3350..f1efb77 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -74,7 +74,7 @@ jobs: - name: Export digest run: | - rm -r /tmp/digests + rm -rf /tmp/digests mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" From 0f2cefd53787cee6377771788c80860640882557 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:09:21 +0800 Subject: [PATCH 11/43] 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. --- src/handler/settings.cpp | 2 +- src/server/webserver_httplib.cpp | 5 ++++- src/utils/map_extra.h | 9 +++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/handler/settings.cpp b/src/handler/settings.cpp index 655f5fd..e41400c 100644 --- a/src/handler/settings.cpp +++ b/src/handler/settings.cpp @@ -1167,7 +1167,7 @@ int loadExternalTOML(toml::value &root, ExternalConfig &ext) "exclude_remarks", ext.exclude ); - if(ext.tpl_args != nullptr) operate_toml_kv_table(toml::find_or>(section, "template_args", {}), "key", "value", + if(ext.tpl_args != nullptr) operate_toml_kv_table(toml::find_or>(root, "template_args", {}), "key", "value", [&](const toml::value &key, const toml::value &value) { std::string val = toml::format(value); diff --git a/src/server/webserver_httplib.cpp b/src/server/webserver_httplib.cpp index 2bf5590..6a7bfc1 100644 --- a/src/server/webserver_httplib.cpp +++ b/src/server/webserver_httplib.cpp @@ -187,7 +187,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 +212,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([&]() diff --git a/src/utils/map_extra.h b/src/utils/map_extra.h index 71af656..1fec977 100644 --- a/src/utils/map_extra.h +++ b/src/utils/map_extra.h @@ -3,13 +3,18 @@ #include #include -#include +#include struct strICaseComp { bool operator() (const std::string &lhs, const std::string &rhs) const { - return strcasecmp(lhs.c_str(), rhs.c_str()); + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), + rhs.end(), + [](unsigned char c1, unsigned char c2) + { + return ::tolower(c1) < ::tolower(c2); + }); } }; From cb15d568c05a356b69e54842dc31e131609e0458 Mon Sep 17 00:00:00 2001 From: Chi Zhang Date: Wed, 3 Apr 2024 20:15:35 +1100 Subject: [PATCH 12/43] Fix missing classical rulesets when exporting Clash configs with expand=false (#715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 尝试修正缺少RULE-SET问题 --- src/generator/template/templates.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/generator/template/templates.cpp b/src/generator/template/templates.cpp index 7bbea8d..75ed31a 100644 --- a/src/generator/template/templates.cpp +++ b/src/generator/template/templates.cpp @@ -474,6 +474,8 @@ int renderClashScript(YAML::Node &base_rule, std::vector &rulese else rules.emplace_back("RULE-SET," + rule_name + "_ipcidr," + 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); } From 4864a6b13cd09a1eff28b4d3d4ac0f76379d980d Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:06:32 +0800 Subject: [PATCH 13/43] Support setting output style for proxy groups in Clash configs (#734) --- base/pref.example.ini | 3 ++- base/pref.example.toml | 3 ++- base/pref.example.yml | 1 + src/generator/config/subexport.cpp | 30 ++++++++++++++++++++++++------ src/generator/config/subexport.h | 1 + src/handler/interfaces.cpp | 2 ++ src/handler/settings.cpp | 3 +++ src/handler/settings.h | 2 +- 8 files changed, 36 insertions(+), 9 deletions(-) diff --git a/base/pref.example.ini b/base/pref.example.ini index fe1688f..49fe301 100644 --- a/base/pref.example.ini +++ b/base/pref.example.ini @@ -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 diff --git a/base/pref.example.toml b/base/pref.example.toml index 4e0c563..f7e4f85 100644 --- a/base/pref.example.toml +++ b/base/pref.example.toml @@ -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 diff --git a/base/pref.example.yml b/base/pref.example.yml index f532994..336a025 100644 --- a/base/pref.example.yml +++ b/base/pref.example.yml @@ -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"} diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index c8eb16a..1acc79f 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -230,19 +230,31 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr std::vector nodelist; string_array remarks_list; /// proxies style - bool block = false, compact = false; + bool proxy_block = false, proxy_compact = false, group_block = false, group_compact = false; switch(hash_(ext.clash_proxies_style)) { case "block"_hash: - block = true; + proxy_block = true; break; default: case "flow"_hash: break; case "compact"_hash: - compact = true; + proxy_compact = true; break; } + switch(hash_(ext.clash_proxy_groups_style)) + { + case "block"_hash: + group_block = true; + break; + default: + case "flow"_hash: + break; + case "compact"_hash: + group_compact = true; + break; + } for(Proxy &x : nodes) { @@ -474,7 +486,7 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr // sees in https://dreamacro.github.io/clash/configuration/outbound.html#snell if(udp && x.Type != ProxyType::Snell) singleproxy["udp"] = true; - if(block) + if(proxy_block) singleproxy.SetStyle(YAML::EmitterStyle::Block); else singleproxy.SetStyle(YAML::EmitterStyle::Flow); @@ -483,7 +495,7 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr nodelist.emplace_back(x); } - if(compact) + if(proxy_compact) proxies.SetStyle(YAML::EmitterStyle::Flow); if(ext.nodelist) @@ -545,7 +557,10 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr } if(!filtered_nodelist.empty()) singlegroup["proxies"] = filtered_nodelist; - //singlegroup.SetStyle(YAML::EmitterStyle::Flow); + if(group_block) + singlegroup.SetStyle(YAML::EmitterStyle::Block); + else + singlegroup.SetStyle(YAML::EmitterStyle::Flow); bool replace_flag = false; for(auto && original_group : original_groups) @@ -561,6 +576,9 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr original_groups.push_back(singlegroup); } + if(group_compact) + original_groups.SetStyle(YAML::EmitterStyle::Flow); + if(ext.clash_new_field_name) yamlnode["proxy-groups"] = original_groups; else diff --git a/src/generator/config/subexport.h b/src/generator/config/subexport.h index 241dc7c..fd77055 100644 --- a/src/generator/config/subexport.h +++ b/src/generator/config/subexport.h @@ -39,6 +39,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; diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index 6f138cd..fdb119c 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -415,6 +415,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS) argExpandRulesets.define(true); ext.clash_proxies_style = global.clashProxiesStyle; + ext.clash_proxy_groups_style = global.clashProxyGroupsStyle; /// read preference from argument, assign global var if not in argument ext.tfo.define(argTFO).define(global.TFOFlag); @@ -1073,6 +1074,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS) ext.skip_cert_verify = global.skipCertVerify; ext.tls13 = global.TLS13Flag; ext.clash_proxies_style = global.clashProxiesStyle; + ext.clash_proxy_groups_style = global.clashProxyGroupsStyle; ProxyGroupConfigs dummy_groups; proxyToClash(nodes, clash, dummy_groups, false, ext); diff --git a/src/handler/settings.cpp b/src/handler/settings.cpp index e41400c..86e399e 100644 --- a/src/handler/settings.cpp +++ b/src/handler/settings.cpp @@ -377,6 +377,7 @@ void readYAMLConf(YAML::Node &node) section["append_sub_userinfo"] >> global.appendUserinfo; section["clash_use_new_field_name"] >> global.clashUseNewField; section["clash_proxies_style"] >> global.clashProxiesStyle; + section["clash_proxy_groups_style"] >> global.clashProxyGroupsStyle; section["singbox_add_clash_modes"] >> global.singBoxAddClashModes; } @@ -638,6 +639,7 @@ void readTOMLConf(toml::value &root) "append_sub_userinfo", global.appendUserinfo, "clash_use_new_field_name", global.clashUseNewField, "clash_proxies_style", global.clashProxiesStyle, + "clash_proxy_groups_style", global.clashProxyGroupsStyle, "singbox_add_clash_modes", global.singBoxAddClashModes ); @@ -883,6 +885,7 @@ void readConf() ini.get_bool_if_exist("append_sub_userinfo", global.appendUserinfo); ini.get_bool_if_exist("clash_use_new_field_name", global.clashUseNewField); ini.get_if_exist("clash_proxies_style", global.clashProxiesStyle); + ini.get_if_exist("clash_proxy_groups_style", global.clashProxyGroupsStyle); ini.get_bool_if_exist("singbox_add_clash_modes", global.singBoxAddClashModes); if(ini.item_prefix_exist("rename_node")) { diff --git a/src/handler/settings.h b/src/handler/settings.h index 495adab..18c7973 100644 --- a/src/handler/settings.h +++ b/src/handler/settings.h @@ -48,7 +48,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; From 670544cfb12ced16d67261c8456c6adebc8ff862 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:50:35 +0800 Subject: [PATCH 14/43] Add macOS ARM build --- .github/workflows/build.yml | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a4fd15..50db6c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,9 +112,9 @@ jobs: files: subconverter_aarch64.tar.gz draft: true - macos_build: - name: macOS Build - runs-on: macos-latest + macos_x86_build: + name: macOS x86 Build + runs-on: macos-13 steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -140,6 +140,34 @@ jobs: files: subconverter_darwin64.tar.gz draft: true + macos_arm_build: + name: macOS ARM Build + runs-on: macos-14 + 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_darwinarm + path: subconverter/ + - name: Package Release + if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} + run: tar czf subconverter_darwinarm.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_darwinarm.tar.gz + draft: true + windows64_build: name: Windows x86_64 Build runs-on: windows-latest From 73da1a87ad74a9a953c544aaf7dafcc6e5d0cdcc Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:57:30 +0800 Subject: [PATCH 15/43] Run with sudo when building for macOS --- scripts/build.macos.release.sh | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/scripts/build.macos.release.sh b/scripts/build.macos.release.sh index 833418b..39d07e2 100644 --- a/scripts/build.macos.release.sh +++ b/scripts/build.macos.release.sh @@ -14,49 +14,50 @@ 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 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 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 From eeffa0f5449535223cd2fae54a776ab6dd35be35 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:13:12 +0800 Subject: [PATCH 16/43] Use brew provided path for libraries on macOS --- scripts/build.macos.release.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/build.macos.release.sh b/scripts/build.macos.release.sh index 39d07e2..12b800d 100644 --- a/scripts/build.macos.release.sh +++ b/scripts/build.macos.release.sh @@ -47,14 +47,11 @@ cmake -DCMAKE_CXX_STANDARD=11 . 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 -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" -lcurl -O3 python -m ensurepip sudo python -m pip install gitpython From 6c38710312cc8323033aa713aa4d111e8a4d5d88 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:16:13 +0800 Subject: [PATCH 17/43] Add missing libraries --- scripts/build.macos.release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build.macos.release.sh b/scripts/build.macos.release.sh index 12b800d..529f7c1 100644 --- a/scripts/build.macos.release.sh +++ b/scripts/build.macos.release.sh @@ -51,7 +51,7 @@ cmake -DCMAKE_BUILD_TYPE=Release . 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") "$(brew --prefix zlib)/lib/libz.a" "$(brew --prefix pcre2)/lib/libpcre2-8.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 sudo python -m pip install gitpython From 7fdba81f2cacfdde24fb5e403bb515a25646ae1f Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:43:33 +0800 Subject: [PATCH 18/43] Fix implementation of getting random string (#726) --- src/utils/string.cpp | 61 +++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/src/utils/string.cpp b/src/utils/string.cpp index f270d5c..f452fc7 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -3,8 +3,9 @@ #include #include #include -#include -#include +#include +#include +#include #include "string.h" #include "map_extra.h" @@ -57,25 +58,20 @@ void split(std::vector &result, std::string_view s, char separ while (i != s.size()) { - int flag = 0; - while(i != s.size() && flag == 0) + while(i != s.size()) { - flag = 1; if(s[i] == separator) { ++i; - flag = 0; break; } } - flag = 0; string_size j = i; - while(j != s.size() && flag == 0) + while(j != s.size()) { if(s[j] == separator) { - flag = 1; break; } ++j; @@ -141,7 +137,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 +187,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 +196,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 +209,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 +324,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 +406,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 +448,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]; From 535d1d01e1761edb035db9c9174a5658a8933c3c Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:55:38 +0800 Subject: [PATCH 19/43] Fix "Profile not found" when generating artifact (#719) --- src/handler/interfaces.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index fdb119c..ecd6530 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include "config/binding.h" @@ -11,7 +10,6 @@ #include "generator/config/ruleconvert.h" #include "generator/config/subexport.h" #include "generator/template/templates.h" -#include "script/cron.h" #include "script/script_quickjs.h" #include "server/webserver.h" #include "utils/base64/base64.h" @@ -24,9 +22,7 @@ #include "utils/string.h" #include "utils/string_hash.h" #include "utils/system.h" -#include "utils/system.h" #include "utils/urlencode.h" -#include "utils/yamlcpp_extra.h" #include "interfaces.h" #include "multithread.h" #include "settings.h" @@ -931,7 +927,7 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS) return "Please insert your subscription link instead of clicking the default link."; } request.argument.emplace("target", "clashr"); - request.argument.emplace("url", urlEncode(url)); + request.argument.emplace("url", url); return subconverter(request, response); } @@ -1385,7 +1381,7 @@ int simpleGenerator() if(ini.item_exist("profile")) { profile = ini.get("profile"); - request.argument.emplace("name", urlEncode(profile)); + request.argument.emplace("name", profile); request.argument.emplace("token", global.accessToken); request.argument.emplace("expand", "true"); content = getProfile(request, response); From 55e765e7f9b60b7f8a69efba2dcbf04692149a36 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:55:24 +0800 Subject: [PATCH 20/43] Fix broken string split (#736 #737 #738) --- src/utils/string.cpp | 74 +++++++++----------------------------------- 1 file changed, 14 insertions(+), 60 deletions(-) diff --git a/src/utils/string.cpp b/src/utils/string.cpp index f452fc7..35cf3bf 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -12,75 +12,29 @@ std::vector split(const std::string &s, const std::string &separator) { + string_size bpos = 0, epos = s.find(separator); std::vector 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 &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()) { - while(i != s.size()) - { - if(s[i] == separator) - { - ++i; - break; - } - } - - string_size j = i; - while(j != s.size()) - { - if(s[j] == separator) - { - 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); } } From b228255d3b9d4c58ce78af8cfd3b6f80da900672 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:46:04 +0800 Subject: [PATCH 21/43] Update build script --- .github/workflows/build.yml | 247 +++++++++++------------------------- 1 file changed, 71 insertions(+), 176 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50db6c3..f5924d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,112 +12,60 @@ concurrency: cancel-in-progress: true jobs: - linux32_build: - name: Linux x86 Build + linux_build: + strategy: + matrix: + include: + - arch: x86 + artifact: subconverter_linux32 + - arch: amd64 + artifact: subconverter_linux64 + - arch: armv7 + artifact: subconverter_armv7 + - arch: aarch64 + artifact: subconverter_aarch64 runs-on: ubuntu-latest + name: Linux ${{ matrix.arch }} Build steps: - - uses: actions/checkout@v3 + - name: Checkout base + uses: actions/checkout@v4 - 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" + 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@v3 + uses: actions/upload-artifact@v4 with: - name: subconverter_linux32 + name: ${{ matrix.artifact }} path: subconverter/ - name: Package Release if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: tar czf subconverter_linux32.tar.gz subconverter + run: tar czf ${{ matrix.artifact }}.tar.gz subconverter - name: Draft Release - uses: softprops/action-gh-release@v1 if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} + uses: softprops/action-gh-release@v2 with: - files: subconverter_linux32.tar.gz + files: ${{ matrix.artifact }}.tar.gz draft: true - linux64_build: - name: Linux x86_64 Build - runs-on: ubuntu-latest + macos_build: + 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 - - 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: [self-hosted, linux, ARM] - steps: - - uses: actions/checkout@v3 - - name: Add commit id into version - if: ${{ !startsWith(github.ref, 'refs/tags/') }} - run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h - - name: Build - run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:armv7-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh" - - name: Upload - uses: actions/upload-artifact@v3 - with: - name: subconverter_armv7 - path: subconverter/ - - name: Package Release - if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: tar czf subconverter_armv7.tar.gz subconverter - - name: Draft Release - uses: softprops/action-gh-release@v1 - if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - with: - files: subconverter_armv7.tar.gz - draft: true - - aarch64_build: - name: Linux aarch64 Build - runs-on: [self-hosted, linux, ARM64] - steps: - - uses: actions/checkout@v3 - - name: Add commit id into version - if: ${{ !startsWith(github.ref, 'refs/tags/') }} - run: SHA=$(git rev-parse --short HEAD) && sed -i 's/\(v[0-9]\.[0-9]\.[0-9]\)/\1-'"$SHA"'/' src/version.h - - name: Build - run: docker run --rm -v $GITHUB_WORKSPACE:/root/workdir multiarch/alpine:aarch64-latest-stable /bin/sh -c "apk add bash git nodejs npm && cd /root/workdir && chmod +x scripts/build.alpine.release.sh && bash scripts/build.alpine.release.sh" - - name: Upload - uses: actions/upload-artifact@v3 - with: - name: subconverter_aarch64 - path: subconverter/ - - name: Package Release - if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: tar czf subconverter_aarch64.tar.gz subconverter - - name: Draft Release - uses: softprops/action-gh-release@v1 - if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - with: - files: subconverter_aarch64.tar.gz - draft: true - - macos_x86_build: - name: macOS x86 Build - runs-on: macos-13 - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - 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 @@ -126,67 +74,54 @@ jobs: - name: Build run: bash scripts/build.macos.release.sh - name: Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: subconverter_darwin64 + name: ${{ matrix.artifact }} path: subconverter/ - name: Package Release if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: tar czf subconverter_darwin64.tar.gz subconverter + run: tar czf ${{ matrix.artifact }}.tar.gz subconverter - name: Draft Release - uses: softprops/action-gh-release@v1 if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} + uses: softprops/action-gh-release@v2 with: - files: subconverter_darwin64.tar.gz + files: ${{ matrix.artifact }}.tar.gz draft: true - - macos_arm_build: - name: macOS ARM Build - runs-on: macos-14 - 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_darwinarm - path: subconverter/ - - name: Package Release - if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: tar czf subconverter_darwinarm.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_darwinarm.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 + - name: Checkout base + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 with: python-version: '3.11' - - uses: actions/setup-node@v3 + - name: Setup Node.js + uses: actions/setup-node@v4 with: node-version: '16' - - uses: msys2/setup-msys2@v2 + - name: Setup MSYS2 + 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 + 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/') }} @@ -194,56 +129,16 @@ jobs: - name: Build run: bash scripts/build.windows.release.sh - name: Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: subconverter_win64 + name: ${{ matrix.artifact }} path: subconverter/ - name: Package Release if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} - run: 7z a subconverter_win64.7z subconverter/ + run: 7z a ${{ matrix.artifact }}.7z subconverter/ - name: Draft Release - uses: softprops/action-gh-release@v1 if: ${{ github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') }} + uses: softprops/action-gh-release@v2 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 + files: ${{ matrix.artifact }}.7z draft: true From 1f57413025a7a62a762e36dcc7c21ba46095d6f1 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:48:03 +0800 Subject: [PATCH 22/43] Fix Linux self-hosted build --- .github/workflows/build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5924d0..9241ec3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,13 +18,17 @@ jobs: include: - arch: x86 artifact: subconverter_linux32 + os: ubuntu-latest - arch: amd64 artifact: subconverter_linux64 + os: ubuntu-latest - arch: armv7 artifact: subconverter_armv7 + os: [self-hosted, linux, ARM] - arch: aarch64 artifact: subconverter_aarch64 - runs-on: ubuntu-latest + os: [self-hosted, linux, ARM64] + runs-on: ${{ matrix.os }} name: Linux ${{ matrix.arch }} Build steps: - name: Checkout base From 40ba3fd9700f798f645f66ae798b7ee4bcec77f9 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Sat, 6 Apr 2024 18:56:52 +0800 Subject: [PATCH 23/43] Update rules updater script --- scripts/rules_config.conf | 8 ++++---- scripts/update_rules.py | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/scripts/rules_config.conf b/scripts/rules_config.conf index 31b5fdd..5efcdbe 100644 --- a/scripts/rules_config.conf +++ b/scripts/rules_config.conf @@ -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 +commit=f4d75f7d48a3f42129e030bef751d4d22bca02da match=Surge/Ruleset/** [NobyDa] url=https://github.com/NobyDa/Script -checkout=ae4c12f23de8078e02c373c9969b19af28257fcb +branch=master match=Surge/*.list diff --git a/scripts/update_rules.py b/scripts/update_rules.py index 7633c76..dbf27c2 100644 --- a/scripts/update_rules.py +++ b/scripts/update_rules.py @@ -22,7 +22,7 @@ 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) @@ -51,12 +51,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 +68,17 @@ def main(): else: logging.info(f"repo {repo_path} exists") - r.git.checkout(commit) - update_rules(repo_path, save_path, commit, matches, keep_tree) + 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.branches[branch].checkout() + else: + logging.info(f"checking out to default branch") + r.active_branch.checkout() + + update_rules(repo_path, save_path, matches, keep_tree) shutil.rmtree("./tmp", ignore_errors=True) From b82d49200d48814cff3b0f07ebef8a4524412b4f Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:04:51 +0800 Subject: [PATCH 24/43] Fix update_rules checkout branch --- scripts/update_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_rules.py b/scripts/update_rules.py index dbf27c2..eaa236a 100644 --- a/scripts/update_rules.py +++ b/scripts/update_rules.py @@ -73,7 +73,7 @@ def main(): r.git.checkout(commit) elif branch is not None: logging.info(f"checking out to branch {branch}") - r.branches[branch].checkout() + r.git.checkout(branch) else: logging.info(f"checking out to default branch") r.active_branch.checkout() From fb6a830d7b84cfc765904de5a57cf583888fca8d Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Sat, 6 Apr 2024 19:21:00 +0800 Subject: [PATCH 25/43] Add lhie1 rules to auto update config --- scripts/rules_config.conf | 5 +++++ scripts/update_rules.py | 25 ++++++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/scripts/rules_config.conf b/scripts/rules_config.conf index 5efcdbe..7cc6770 100644 --- a/scripts/rules_config.conf +++ b/scripts/rules_config.conf @@ -21,3 +21,8 @@ match=Surge/Ruleset/** url=https://github.com/NobyDa/Script branch=master match=Surge/*.list + +[lhie1] +url=https://github.com/dler-io/Rules +branch=main +match=Surge/Surge 3/Provider/** diff --git a/scripts/update_rules.py b/scripts/update_rules.py index eaa236a..f6b4a99 100644 --- a/scripts/update_rules.py +++ b/scripts/update_rules.py @@ -26,6 +26,9 @@ def update_rules(repo_path: str, save_path: str, matches: list[str], keep_tree: 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 @@ -68,15 +71,19 @@ def main(): else: logging.info(f"repo {repo_path} exists") - 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() + 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) From 6af2c56fc825e19625c68dae13ece012cf4a661c Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:30:10 +0800 Subject: [PATCH 26/43] Do not add check-interval and tolerance to SSID groups in QuanX configs --- src/config/proxygroup.h | 4 ++-- src/config/ruleset.h | 2 +- src/generator/config/subexport.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config/proxygroup.h b/src/config/proxygroup.h index 4300e29..d0ffab0 100644 --- a/src/config/proxygroup.h +++ b/src/config/proxygroup.h @@ -3,7 +3,7 @@ #include "def.h" -enum ProxyGroupType +enum class ProxyGroupType { Select, URLTest, @@ -13,7 +13,7 @@ enum ProxyGroupType SSID }; -enum BalanceStrategy +enum class BalanceStrategy { ConsistentHashing, RoundRobin diff --git a/src/config/ruleset.h b/src/config/ruleset.h index 4a29a54..c9551eb 100644 --- a/src/config/ruleset.h +++ b/src/config/ruleset.h @@ -3,7 +3,7 @@ #include "def.h" -enum RulesetType +enum class RulesetType { SurgeRuleset, QuantumultX, diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index 1acc79f..d1ced9b 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -1559,7 +1559,7 @@ void proxyToQuanX(std::vector &nodes, INIReader &ini, std::vector 0) From 04ac98725cceea28068aebc830c101eaf90888f7 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:21:29 +0800 Subject: [PATCH 27/43] Add clash_api to default sing-box config base --- base/base/all_base.tpl | 11 ++++++++++- base/base/singbox.json | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/base/base/all_base.tpl b/base/base/all_base.tpl index 933e8ca..2fa2548 100644 --- a/base/base/all_base.tpl +++ b/base/base/all_base.tpl @@ -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": "127.0.0.1:9090", + "external_ui": "dashboard" + } + } } {% endif %} diff --git a/base/base/singbox.json b/base/base/singbox.json index 4263bd5..252bf5e 100644 --- a/base/base/singbox.json +++ b/base/base/singbox.json @@ -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" + } + } } From b9ad0c2ee2b959e2b10195e928bf8f30f55a6a78 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:31:25 +0800 Subject: [PATCH 28/43] Bump version to v0.9.0 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 1188570..f55ebbe 100644 --- a/src/version.h +++ b/src/version.h @@ -1,6 +1,6 @@ #ifndef VERSION_H_INCLUDED #define VERSION_H_INCLUDED -#define VERSION "v0.8.1" +#define VERSION "v0.9.0" #endif // VERSION_H_INCLUDED From 0c8574755a8bce44dfb7ef8a2d9678a82273988c Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Tue, 9 Apr 2024 01:11:29 +0800 Subject: [PATCH 29/43] Enhancements Fix not properly handling data from multipart-form POST (#739). Fix not cleaning up request parameters when generating profiles (#741). --- src/handler/interfaces.cpp | 4 ++-- src/main.cpp | 6 +++--- src/server/webserver_httplib.cpp | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index ecd6530..38b1197 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -1362,10 +1362,10 @@ int simpleGenerator() string_multimap allItems; std::string proxy = parseProxy(global.proxySubscription); - Request request; - Response response; for(std::string &x : sections) { + Request request; + Response response; response.status_code = 200; //std::cerr<<"Generating artifact '"<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; From 69749107340f4b0e46e0f30525c7142f70f50e55 Mon Sep 17 00:00:00 2001 From: TAKO <20227709+HynoR@users.noreply.github.com> Date: Thu, 18 Apr 2024 15:47:39 +0800 Subject: [PATCH 30/43] Update Flag category (#744) * Update emoji.toml * Update emoji.txt --- base/snippets/emoji.toml | 13 ++++++++++++- base/snippets/emoji.txt | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/base/snippets/emoji.toml b/base/snippets/emoji.toml index a277aeb..7a423d0 100644 --- a/base/snippets/emoji.toml +++ b/base/snippets/emoji.toml @@ -42,6 +42,10 @@ emoji = "🇦🇪" match = "(阿尔巴尼亚|Albania)" emoji = "🇦🇱" +[[emoji]] +match = "(南极|Antarctica)" +emoji = "🇦🇶" + [[emoji]] match = "(Argentina|阿根廷)" 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 = "🇲🇳" @@ -327,6 +334,10 @@ emoji = "🇹🇷" match = "(乌拉圭|Uruguay)" emoji = "🇺🇾" +[[emoji]] +match = "(梵蒂冈|Vatican)" +emoji = "🇻🇦" + [[emoji]] match = "(Vietnam|越南)" emoji = "🇻🇳" diff --git a/base/snippets/emoji.txt b/base/snippets/emoji.txt index 236de31..7195228 100644 --- a/base/snippets/emoji.txt +++ b/base/snippets/emoji.txt @@ -9,6 +9,7 @@ (Ascension|阿森松),🇦🇨 (?i:\bUAE\b|Dubai|阿联酋|迪拜),🇦🇪 (阿尔巴尼亚|Albania),🇦🇱 +(南极|Antarctica),🇦🇶 (Argentina|阿根廷),🇦🇷 (Austria|Vienna|奥地利|维也纳),🇦🇹 (?i:\bAU[S]?\b|Australia|Sydney|澳大利亚|澳洲|悉尼),🇦🇺 @@ -56,6 +57,7 @@ (拉脱维亚|Latvia),🇱🇻 (Moldova|摩尔多瓦),🇲🇩 (北马其顿|Macedonia),🇲🇰 +(缅甸|Myanmar),🇲🇲 (蒙古|Монголулс|Mongolia),🇲🇳 (Macao|澳门|\bCTM\b),🇲🇴 (墨西哥|Mexico),🇲🇽 @@ -80,6 +82,7 @@ (突尼斯|Tunisia),🇹🇳 (Turkey|土耳其|伊斯坦布尔),🇹🇷 (乌拉圭|Uruguay),🇺🇾 +(梵蒂冈|Vatican),🇻🇦 (Vietnam|越南),🇻🇳 (Africa|南非),🇿🇦 (Ukraine|UA|乌克兰),🇺🇦 From 0c11565cc97ef54dde0e43bc0a91efa962958a2d Mon Sep 17 00:00:00 2001 From: SpadeLushen Date: Tue, 27 Aug 2024 17:33:02 +0800 Subject: [PATCH 31/43] 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> --- src/generator/config/subexport.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index d1ced9b..f4f8f40 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -2268,6 +2268,8 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v tls.AddMember("enabled", true, allocator); if (!x.ServerName.empty()) tls.AddMember("server_name", rapidjson::StringRef(x.ServerName.c_str()), allocator); + else if (!x.Host.empty()) + tls.AddMember("server_name", rapidjson::StringRef(x.Host.c_str()), allocator); tls.AddMember("insecure", buildBooleanValue(scv), allocator); proxy.AddMember("tls", tls, allocator); } From 3f2281e284d47940e2ed3b3041854e80997ec735 Mon Sep 17 00:00:00 2001 From: ak1ra <3954104+ak1ra-komj@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:33:17 +0800 Subject: [PATCH 32/43] Add clash.external_controller option in config file (#772) --- base/base/all_base.tpl | 4 ++-- base/pref.example.ini | 1 + base/pref.example.toml | 4 ++++ base/pref.example.yml | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/base/base/all_base.tpl b/base/base/all_base.tpl index 2fa2548..e67e350 100644 --- a/base/base/all_base.tpl +++ b/base/base/all_base.tpl @@ -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 @@ -384,7 +384,7 @@ enhanced-mode-by-rule = true "store_fakeip": true }, "clash_api": { - "external_controller": "127.0.0.1:9090", + "external_controller": "{{ default(global.clash.external_controller, "127.0.0.1:9090") }}", "external_ui": "dashboard" } } diff --git a/base/pref.example.ini b/base/pref.example.ini index 49fe301..1b1b55c 100644 --- a/base/pref.example.ini +++ b/base/pref.example.ini @@ -233,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 diff --git a/base/pref.example.toml b/base/pref.example.toml index f7e4f85..6448eb9 100644 --- a/base/pref.example.toml +++ b/base/pref.example.toml @@ -244,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" diff --git a/base/pref.example.yml b/base/pref.example.yml index 336a025..5e27275 100644 --- a/base/pref.example.yml +++ b/base/pref.example.yml @@ -109,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"} From 644b9040b91e1f44843409f7686790219119284d Mon Sep 17 00:00:00 2001 From: TioaChan <8370450+TioaChan@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:34:01 +0800 Subject: [PATCH 33/43] Add timezone env to Docker image (#776) --- scripts/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Dockerfile b/scripts/Dockerfile index 37d1016..a9c2a32 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -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 From 79a7e888b11c343d18a064f08065e7962f1a1f49 Mon Sep 17 00:00:00 2001 From: star Date: Mon, 30 Sep 2024 06:39:23 +0800 Subject: [PATCH 34/43] 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 --- .gitignore | 1 + src/config/binding.h | 13 +++++++ src/config/proxygroup.h | 4 ++- src/generator/config/subexport.cpp | 22 +++++++++--- src/parser/config/proxy.h | 2 ++ src/parser/subparser.cpp | 57 ++++++++++++++++-------------- src/parser/subparser.h | 14 ++++---- 7 files changed, 73 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index 567b776..ffbc647 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ subconverter.exe cmake-build-debug .idea base/cache +build \ No newline at end of file diff --git a/src/config/binding.h b/src/config/binding.h index 7741108..c6e3c07 100644 --- a/src/config/binding.h +++ b/src/config/binding.h @@ -64,6 +64,16 @@ namespace toml case "ssid"_hash: conf.Type = ProxyGroupType::SSID; break; + case "smart"_hash: + conf.Type = ProxyGroupType::Smart; + conf.Url = toml::find(v, "url"); + conf.Interval = toml::find(v, "interval"); + conf.Tolerance = toml::find_or(v, "tolerance", 0); + if(v.contains("lazy")) + conf.Lazy = toml::find_or(v, "lazy", false); + if(v.contains("evaluate-before-use")) + conf.EvaluateBeforeUse = toml::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()); } @@ -220,6 +230,9 @@ namespace INIBinding case "ssid"_hash: conf.Type = ProxyGroupType::SSID; break; + case "smart"_hash: + conf.Type = ProxyGroupType::Smart; + break; default: continue; } diff --git a/src/config/proxygroup.h b/src/config/proxygroup.h index d0ffab0..07dbddc 100644 --- a/src/config/proxygroup.h +++ b/src/config/proxygroup.h @@ -10,7 +10,8 @@ enum class ProxyGroupType Fallback, LoadBalance, Relay, - SSID + SSID, + Smart }; enum class BalanceStrategy @@ -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 ""; } diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index f4f8f40..e1854f8 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -518,7 +518,10 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr string_array filtered_nodelist; singlegroup["name"] = x.Name; - singlegroup["type"] = x.TypeStr(); + if (x.Type == ProxyGroupType::Smart) + singlegroup["type"] = "url-test"; + else + singlegroup["type"] = x.TypeStr(); switch(x.Type) { @@ -528,6 +531,8 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr case ProxyGroupType::LoadBalance: singlegroup["strategy"] = x.StrategyStr(); [[fallthrough]]; + case ProxyGroupType::Smart: + [[fallthrough]]; case ProxyGroupType::URLTest: if(!x.Lazy.is_undef()) singlegroup["lazy"] = x.Lazy.get(); @@ -691,7 +696,7 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf processRemark(x.Remark, remarks_list); - std::string &hostname = x.Hostname, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption; + std::string &hostname = x.Hostname, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption, &underlying_proxy = x.UnderlyingProxy; std::string port = std::to_string(x.Port); bool &tlssecure = x.TLSSecure; @@ -704,7 +709,9 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf std::string proxy, section, real_section; string_array args, headers; - switch(x.Type) + std::stringstream ss; + + switch (x.Type) { case ProxyType::Shadowsocks: if(surge_ver >= 3 || surge_ver == -3) @@ -833,7 +840,8 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf case ProxyType::WireGuard: if(surge_ver < 4 && surge_ver != -3) continue; - section = randomStr(5); + ss << std::hex << hash_(x.Remark); + section = ss.str().substr(0, 5); real_section = "WireGuard " + section; proxy = "wireguard, section-name=" + section; if(!x.TestUrl.empty()) @@ -861,7 +869,10 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf if(!udp.is_undef()) proxy += ", udp-relay=" + udp.get_str(); - if(ext.nodelist) + if (underlying_proxy != "") + proxy += ", underlying-proxy=" + underlying_proxy; + + if (ext.nodelist) output_nodelist += x.Remark + " = " + proxy + "\n"; else { @@ -884,6 +895,7 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf switch(x.Type) { case ProxyGroupType::Select: + case ProxyGroupType::Smart: case ProxyGroupType::URLTest: case ProxyGroupType::Fallback: break; diff --git a/src/parser/config/proxy.h b/src/parser/config/proxy.h index fd0f94f..724a9a6 100644 --- a/src/parser/config/proxy.h +++ b/src/parser/config/proxy.h @@ -85,6 +85,8 @@ struct Proxy tribool AllowInsecure; tribool TLS13; + String UnderlyingProxy; + uint16_t SnellVersion = 0; String ServerName; diff --git a/src/parser/subparser.cpp b/src/parser/subparser.cpp index 9f85692..e0370b2 100644 --- a/src/parser/subparser.cpp +++ b/src/parser/subparser.cpp @@ -25,12 +25,13 @@ std::string modSSMD5 = "f7653207090ce3389115e9c88541afe0"; //remake from speedtestutil -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) +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 std::string& underlying_proxy) { node.Type = type; node.Group = group; node.Remark = remarks; node.Hostname = server; + node.UnderlyingProxy = underlying_proxy; node.Port = to_int(port); node.UDP = udp; node.TCPFastOpen = tfo; @@ -38,9 +39,9 @@ void commonConstruct(Proxy &node, ProxyType type, const std::string &group, cons node.TLS13 = tls13; } -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) +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, const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::VMess, group, remarks, add, port, udp, tfo, scv, tls13); + 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; @@ -62,9 +63,9 @@ void vmessConstruct(Proxy &node, const std::string &group, const std::string &re node.TLSSecure = tls == "tls"; } -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) +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,const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool()); + commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool(), underlying_proxy); node.Password = password; node.EncryptMethod = method; node.Protocol = protocol; @@ -73,33 +74,33 @@ void ssrConstruct(Proxy &node, const std::string &group, const std::string &rema node.OBFSParam = obfsparam; } -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) +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, const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13); + commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13, underlying_proxy); node.Password = password; node.EncryptMethod = method; node.Plugin = plugin; node.PluginOption = pluginopts; } -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) +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, const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::SOCKS5, group, remarks, server, port, udp, tfo, scv, tribool()); + 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) +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,const std::string& underlying_proxy) { - commonConstruct(node, tls ? ProxyType::HTTPS : ProxyType::HTTP, group, remarks, server, port, tribool(), tfo, scv, tls13); + commonConstruct(node, tls ? ProxyType::HTTPS : ProxyType::HTTP, group, remarks, server, port, tribool(), tfo, scv, tls13, underlying_proxy); node.Username = username; node.Password = password; node.TLSSecure = tls; } -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, bool tlssecure, tribool udp, tribool tfo, tribool scv, tribool tls13) +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, bool tlssecure, tribool udp, tribool tfo, tribool scv, tribool tls13, const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13); + commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13, underlying_proxy); node.Password = password; node.Host = host; node.TLSSecure = tlssecure; @@ -107,17 +108,18 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r node.Path = path; } -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) +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, const std::string& underlying_proxy) { - commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool()); + commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool(), underlying_proxy); node.Password = password; node.OBFS = obfs; node.Host = host; node.SnellVersion = version; } -void wireguardConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, 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()); +void wireguardConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, 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, 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; @@ -973,7 +975,7 @@ void explodeNetch(std::string netch, Proxy &node) void explodeClash(Node yamlnode, std::vector &nodes) { - std::string proxytype, ps, server, port, cipher, group, password; //common + std::string proxytype, ps, server, port, cipher, group, password, underlying_proxy; //common std::string type = "none", id, aid = "0", net = "tcp", path, host, edge, tls, sni; //vmess std::string plugin, pluginopts, pluginopts_mode, pluginopts_host, pluginopts_mux; //ss std::string protocol, protoparam, obfs, obfsparam; //ssr @@ -992,6 +994,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) singleproxy["name"] >>= ps; singleproxy["server"] >>= server; singleproxy["port"] >>= port; + singleproxy["underlying-proxy"] >>= underlying_proxy; if(port.empty() || port == "0") continue; udp = safe_as(singleproxy["udp"]); @@ -1040,7 +1043,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) } tls = safe_as(singleproxy["tls"]) == "true" ? "tls" : ""; - vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni, udp, tfo, scv); + vmessConstruct(node, group, ps, server, port, "", id, aid, net, cipher, path, host, edge, tls, sni, udp, tfo, scv, tribool(), underlying_proxy); break; case "ss"_hash: group = SS_DEFAULT_GROUP; @@ -1110,7 +1113,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) std::transform(cipher.begin(), cipher.end(), cipher.begin(), ::tolower); } - ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv); + ssConstruct(node, group, ps, server, port, password, cipher, plugin, pluginopts, udp, tfo, scv, tribool(), underlying_proxy); break; case "socks5"_hash: group = SOCKS_DEFAULT_GROUP; @@ -1118,7 +1121,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) singleproxy["username"] >>= user; singleproxy["password"] >>= password; - socksConstruct(node, group, ps, server, port, user, password); + socksConstruct(node, group, ps, server, port, user, password, tribool(), tribool(), tribool(), underlying_proxy); break; case "ssr"_hash: group = SSR_DEFAULT_GROUP; @@ -1137,7 +1140,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) else singleproxy["obfsparam"] >>= obfsparam; - ssrConstruct(node, group, ps, server, port, protocol, cipher, obfs, password, obfsparam, protoparam, udp, tfo, scv); + ssrConstruct(node, group, ps, server, port, protocol, cipher, obfs, password, obfsparam, protoparam, udp, tfo, scv, underlying_proxy); break; case "http"_hash: group = HTTP_DEFAULT_GROUP; @@ -1146,7 +1149,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) singleproxy["password"] >>= password; singleproxy["tls"] >>= tls; - httpConstruct(node, group, ps, server, port, user, password, tls == "true", tfo, scv); + httpConstruct(node, group, ps, server, port, user, password, tls == "true", tfo, scv, tribool(), underlying_proxy); break; case "trojan"_hash: group = TROJAN_DEFAULT_GROUP; @@ -1167,7 +1170,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) break; } - trojanConstruct(node, group, ps, server, port, password, net, host, path, true, udp, tfo, scv); + trojanConstruct(node, group, ps, server, port, password, net, host, path, true, udp, tfo, scv, tribool(), underlying_proxy); break; case "snell"_hash: group = SNELL_DEFAULT_GROUP; @@ -1176,7 +1179,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) singleproxy["obfs-opts"]["host"] >>= host; singleproxy["version"] >>= aid; - snellConstruct(node, group, ps, server, port, password, obfs, host, to_int(aid, 0), udp, tfo, scv); + snellConstruct(node, group, ps, server, port, password, obfs, host, to_int(aid, 0), udp, tfo, scv, underlying_proxy); break; case "wireguard"_hash: group = WG_DEFAULT_GROUP; @@ -1188,7 +1191,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) singleproxy["ip"] >>= ip; singleproxy["ipv6"] >>= ipv6; - wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password, dns_server, mtu, "0", "", "", udp); + wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password, dns_server, mtu, "0", "", "", udp, underlying_proxy); break; default: continue; @@ -1790,7 +1793,7 @@ bool explodeSurge(std::string surge, std::vector &nodes) } } - wireguardConstruct(node, WG_DEFAULT_GROUP, remarks, "", "0", ip, ipv6, private_key, "", "", dns_servers, mtu, keepalive, test_url, "", udp); + wireguardConstruct(node, WG_DEFAULT_GROUP, remarks, "", "0", ip, ipv6, private_key, "", "", dns_servers, mtu, keepalive, test_url, "", udp, ""); parsePeers(node, peer); break; default: diff --git a/src/parser/subparser.h b/src/parser/subparser.h index 5d236a9..627ff40 100644 --- a/src/parser/subparser.h +++ b/src/parser/subparser.h @@ -20,13 +20,13 @@ enum class ConfType Local }; -void vmessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add, const std::string &port, const std::string &type, const std::string &id, const std::string &aid, const std::string &net, const std::string &cipher, const std::string &path, const std::string &host, const std::string &edge, const std::string &tls, const std::string &sni, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool()); -void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &protocol, const std::string &method, const std::string &obfs, const std::string &password, const std::string &obfsparam, const std::string &protoparam, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool()); -void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &method, const std::string &plugin, const std::string &pluginopts, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool()); -void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool()); -void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool()); -void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &network, const std::string &host, const std::string &path, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool()); -void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &obfs, const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool()); +void 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 &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(), 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(), 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(), 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(), 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, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = 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(), const std::string &underlying_proxy = ""); void explodeVmess(std::string vmess, Proxy &node); void explodeSSR(std::string ssr, Proxy &node); void explodeSS(std::string ss, Proxy &node); From c207bfc1f03185114467b50a4ce97f2d0394c782 Mon Sep 17 00:00:00 2001 From: Lai Zn Date: Fri, 29 Nov 2024 01:00:26 +0800 Subject: [PATCH 35/43] 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> --- scripts/build.alpine.release.sh | 2 +- scripts/build.macos.release.sh | 2 +- scripts/build.windows.release.sh | 4 +- scripts/rules_config.conf | 5 - src/generator/config/subexport.cpp | 194 ++++++++++++++++++++++++-- src/parser/config/proxy.h | 30 +++- src/parser/subparser.cpp | 215 +++++++++++++++++++++++++++++ src/parser/subparser.h | 35 +++++ 8 files changed, 467 insertions(+), 20 deletions(-) diff --git a/scripts/build.alpine.release.sh b/scripts/build.alpine.release.sh index c159737..2dba424 100644 --- a/scripts/build.alpine.release.sh +++ b/scripts/build.alpine.release.sh @@ -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 diff --git a/scripts/build.macos.release.sh b/scripts/build.macos.release.sh index 529f7c1..e554c99 100644 --- a/scripts/build.macos.release.sh +++ b/scripts/build.macos.release.sh @@ -41,7 +41,7 @@ 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="v3.7.1" --depth=1 cd toml11 cmake -DCMAKE_CXX_STANDARD=11 . sudo make install -j6 > /dev/null diff --git a/scripts/build.windows.release.sh b/scripts/build.windows.release.sh index 5de4c8d..2b3e49b 100644 --- a/scripts/build.windows.release.sh +++ b/scripts/build.windows.release.sh @@ -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 @@ -38,7 +38,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 v3.8.1 --depth=1 cd toml11 cmake -DCMAKE_INSTALL_PREFIX="$MINGW_PREFIX" -G "Unix Makefiles" -DCMAKE_CXX_STANDARD=11 . make install -j4 diff --git a/scripts/rules_config.conf b/scripts/rules_config.conf index 7cc6770..65a3b0d 100644 --- a/scripts/rules_config.conf +++ b/scripts/rules_config.conf @@ -12,11 +12,6 @@ match=Clash/config/** dest=base/config/ keep_tree=false -[DivineEngine] -url=https://github.com/DivineEngine/Profiles -commit=f4d75f7d48a3f42129e030bef751d4d22bca02da -match=Surge/Ruleset/** - [NobyDa] url=https://github.com/NobyDa/Script branch=master diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index e1854f8..eacb22a 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -116,15 +116,19 @@ bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy & std::string target, ret_real_rule; static const std::string groupid_regex = R"(^!!(?:GROUPID|INSERT)=([\d\-+!,]+)(?:!!(.*))?$)", group_regex = R"(^!!(?:GROUP)=(.+?)(?:!!(.*))?$)"; static const std::string type_regex = R"(^!!(?:TYPE)=(.+?)(?:!!(.*))?$)", port_regex = R"(^!!(?:PORT)=(.+?)(?:!!(.*))?$)", server_regex = R"(^!!(?:SERVER)=(.+?)(?:!!(.*))?$)"; - static const std::map types = {{ProxyType::Shadowsocks, "SS"}, - {ProxyType::ShadowsocksR, "SSR"}, - {ProxyType::VMess, "VMESS"}, - {ProxyType::Trojan, "TROJAN"}, - {ProxyType::Snell, "SNELL"}, - {ProxyType::HTTP, "HTTP"}, - {ProxyType::HTTPS, "HTTPS"}, - {ProxyType::SOCKS5, "SOCKS5"}, - {ProxyType::WireGuard, "WIREGUARD"}}; + static const std::map types = { + {ProxyType::Shadowsocks, "SS"}, + {ProxyType::ShadowsocksR, "SSR"}, + {ProxyType::VMess, "VMESS"}, + {ProxyType::Trojan, "TROJAN"}, + {ProxyType::Snell, "SNELL"}, + {ProxyType::HTTP, "HTTP"}, + {ProxyType::HTTPS, "HTTPS"}, + {ProxyType::SOCKS5, "SOCKS5"}, + {ProxyType::WireGuard, "WIREGUARD"}, + {ProxyType::Hysteria, "HYSTERIA"}, + {ProxyType::Hysteria2, "HYSTERIA2"} + }; if(startsWith(rule, "!!GROUP=")) { regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule); @@ -478,6 +482,77 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr if(x.Mtu > 0) singleproxy["mtu"] = x.Mtu; break; + case ProxyType::Hysteria: + singleproxy["type"] = "hysteria"; + if (!x.Ports.empty()) + singleproxy["ports"] = x.Ports; + if (!x.Protocol.empty()) + singleproxy["protocol"] = x.Protocol; + if (!x.OBFSParam.empty()) + singleproxy["obfs-protocol"] = x.OBFSParam; + if (!x.Up.empty()) + singleproxy["up"] = x.Up; + if (x.UpSpeed) + singleproxy["up-speed"] = x.UpSpeed; + if (!x.Down.empty()) + singleproxy["down"] = x.Down; + if (x.DownSpeed) + singleproxy["down-speed"] = x.DownSpeed; + if (!x.AuthStr.empty()) + { + singleproxy["auth-str"] = x.AuthStr; + singleproxy["auth"] = base64Encode(x.AuthStr); + } + if (!x.OBFS.empty()) + singleproxy["obfs"] = x.OBFS; + if (!x.SNI.empty()) + singleproxy["sni"] = x.SNI; + if (!scv.is_undef()) + singleproxy["skip-cert-verify"] = scv.get(); + if (!x.Fingerprint.empty()) + singleproxy["fingerprint"] = x.Fingerprint; + if (!x.Alpn.empty()) + singleproxy["alpn"] = x.Alpn; + if (!x.Ca.empty()) + singleproxy["ca"] = x.Ca; + if (!x.CaStr.empty()) + singleproxy["ca-str"] = x.CaStr; + if (x.RecvWindowConn) + singleproxy["recv-window-conn"] = x.RecvWindowConn; + if (x.RecvWindow) + singleproxy["recv-window"] = x.RecvWindow; + if (!x.DisableMtuDiscovery.is_undef()) + singleproxy["disable-mtu-discovery"] = x.DisableMtuDiscovery.get(); + if (!x.TCPFastOpen.is_undef()) + singleproxy["fast-open"] = x.TCPFastOpen.get(); + if (x.HopInterval) + singleproxy["hop-interval"] = x.HopInterval; + break; + case ProxyType::Hysteria2: + singleproxy["type"] = "hysteria2"; + if (!x.Up.empty()) + singleproxy["up"] = x.UpSpeed; + if (!x.Down.empty()) + singleproxy["down"] = x.DownSpeed; + if (!x.Password.empty()) + singleproxy["password"] = x.Password; + if (!x.OBFS.empty()) + singleproxy["obfs"] = x.OBFS; + if (!x.OBFSParam.empty()) + singleproxy["obfs-password"] = x.OBFSParam; + if (!x.SNI.empty()) + singleproxy["sni"] = x.SNI; + if (!scv.is_undef()) + singleproxy["skip-cert-verify"] = scv.get(); + if (!x.Alpn.empty()) + singleproxy["alpn"] = x.Alpn; + if (!x.Ca.empty()) + singleproxy["ca"] = x.Ca; + if (!x.CaStr.empty()) + singleproxy["ca-str"] = x.CaStr; + if (x.CWND) + singleproxy["cwnd"] = x.CWND; + break; default: continue; } @@ -860,6 +935,20 @@ std::string proxyToSurge(std::vector &nodes, const std::string &base_conf ini.set(real_section, "keepalive", std::to_string(x.KeepAlive)); ini.set(real_section, "peer", "(" + generatePeer(x) + ")"); break; + case ProxyType::Hysteria2: + if(surge_ver < 4) + continue; + proxy = "hysteria, " + hostname + ", " + port + ", password=" + password; + if(x.DownSpeed) + proxy += ", download-bandwidth=" + x.DownSpeed; + + if(!scv.is_undef()) + proxy += ",skip-cert-verify=" + std::string(scv.get() ? "true" : "false"); + if(!x.Fingerprint.empty()) + proxy += ",server-cert-fingerprint-sha256=" + x.Fingerprint; + if(!x.SNI.empty()) + proxy += ",sni=" + x.SNI; + break; default: continue; } @@ -2168,7 +2257,6 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v udp.define(x.UDP); tfo.define(x.TCPFastOpen); scv.define(x.AllowInsecure); - rapidjson::Value proxy(rapidjson::kObjectType); switch (x.Type) { @@ -2255,6 +2343,92 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v proxy.AddMember("mtu", x.Mtu, allocator); break; } + case ProxyType::Hysteria: + { + addSingBoxCommonMembers(proxy, x, "hysteria", allocator); + if (!x.Up.empty()) + proxy.AddMember("up_mbps", x.UpSpeed, allocator); + if (!x.Down.empty()) + proxy.AddMember("down_mbps", x.DownSpeed, allocator); + if (!x.OBFS.empty()) + { + proxy.AddMember("obfs", rapidjson::StringRef(x.OBFS.c_str()), allocator); + } + + if (!x.AuthStr.empty()) + { + proxy.AddMember("auth_str", rapidjson::StringRef(x.AuthStr.c_str()), allocator); + rapidjson::Value auth_str; + auth_str.SetString(base64Encode(x.AuthStr).c_str(), allocator); + proxy.AddMember("auth", auth_str, allocator); + } + if (x.RecvWindowConn) + proxy.AddMember("recv_window_conn", x.RecvWindowConn, allocator); + if (x.RecvWindow) + proxy.AddMember("recv_window", x.RecvWindow, allocator); + if (!x.DisableMtuDiscovery.is_undef()) + proxy.AddMember("disable_mtu_discovery", x.DisableMtuDiscovery.get(), allocator); + + rapidjson::Value tls(rapidjson::kObjectType); + tls.AddMember("enabled", true, allocator); + if (!scv.is_undef()) + tls.AddMember("insecure", scv.get(), allocator); + if (!x.Alpn.empty()) + { + rapidjson::Value alpn(rapidjson::kArrayType); + alpn.PushBack(rapidjson::StringRef(x.Alpn[0].c_str()), allocator); + tls.AddMember("alpn", alpn, allocator); + } + if (!x.Ca.empty()) + { + rapidjson::Value ca_str; + ca_str.SetString(x.Ca.c_str(), allocator); + tls.AddMember("certificate", ca_str, allocator); + } + if (!x.CaStr.empty()) + tls.AddMember("certificate", rapidjson::StringRef(x.CaStr.c_str()), allocator); + proxy.AddMember("tls", tls, allocator); + break; + } + case ProxyType::Hysteria2: + { + addSingBoxCommonMembers(proxy, x, "hysteria2", allocator); + if (!x.Up.empty()) + proxy.AddMember("up_mbps", x.UpSpeed, allocator); + if (!x.Down.empty()) + proxy.AddMember("down_mbps", x.DownSpeed, allocator); + if (!x.OBFS.empty()) + { + rapidjson::Value obfs(rapidjson::kObjectType); + obfs.AddMember("type", rapidjson::StringRef(x.OBFS.c_str()), allocator); + if (!x.OBFSParam.empty()) + obfs.AddMember("password", rapidjson::StringRef(x.OBFSParam.c_str()), allocator); + proxy.AddMember("obfs", obfs, allocator); + } + if (!x.Password.empty()) + proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator); + + rapidjson::Value tls(rapidjson::kObjectType); + tls.AddMember("enabled", true, allocator); + if (!scv.is_undef()) + tls.AddMember("insecure", scv.get(), allocator); + if (!x.Alpn.empty()) + { + rapidjson::Value alpn(rapidjson::kArrayType); + alpn.PushBack(rapidjson::StringRef(x.Alpn[0].c_str()), allocator); + tls.AddMember("alpn", alpn, allocator); + } + if (!x.Ca.empty()) + { + rapidjson::Value ca_str(rapidjson::kStringType); + ca_str.SetString(x.Ca.c_str(), allocator); + tls.AddMember("certificate", ca_str, allocator); + } + if (!x.CaStr.empty()) + tls.AddMember("certificate", rapidjson::StringRef(x.CaStr.c_str()), allocator); + proxy.AddMember("tls", tls, allocator); + break; + } case ProxyType::HTTP: case ProxyType::HTTPS: { diff --git a/src/parser/config/proxy.h b/src/parser/config/proxy.h index 724a9a6..80b2ee0 100644 --- a/src/parser/config/proxy.h +++ b/src/parser/config/proxy.h @@ -20,7 +20,9 @@ enum class ProxyType HTTP, HTTPS, SOCKS5, - WireGuard + WireGuard, + Hysteria, + Hysteria2 }; inline String getProxyTypeName(ProxyType type) @@ -43,6 +45,12 @@ inline String getProxyTypeName(ProxyType type) return "HTTPS"; case ProxyType::SOCKS5: return "SOCKS5"; + case ProxyType::WireGuard: + return "WireGuard"; + case ProxyType::Hysteria: + return "Hysteria"; + case ProxyType::Hysteria2: + return "Hysteria2"; default: return "Unknown"; } @@ -101,6 +109,24 @@ struct Proxy uint16_t KeepAlive = 0; String TestUrl; String ClientId; + + String Ports; + String Up; + uint32_t UpSpeed; + String Down; + uint32_t DownSpeed; + String AuthStr; + String SNI; + String Fingerprint; + String Ca; + String CaStr; + uint32_t RecvWindowConn; + uint32_t RecvWindow; + tribool DisableMtuDiscovery; + uint32_t HopInterval; + StringArray Alpn; + + uint32_t CWND = 0; }; #define SS_DEFAULT_GROUP "SSProvider" @@ -111,5 +137,7 @@ struct Proxy #define TROJAN_DEFAULT_GROUP "TrojanProvider" #define SNELL_DEFAULT_GROUP "SnellProvider" #define WG_DEFAULT_GROUP "WireGuardProvider" +#define HYSTERIA_DEFAULT_GROUP "HysteriaProvider" +#define HYSTERIA2_DEFAULT_GROUP "Hysteria2Provider" #endif // PROXY_H_INCLUDED diff --git a/src/parser/subparser.cpp b/src/parser/subparser.cpp index e0370b2..ca29ece 100644 --- a/src/parser/subparser.cpp +++ b/src/parser/subparser.cpp @@ -132,6 +132,101 @@ void wireguardConstruct(Proxy &node, const std::string &group, const std::string node.ClientId = clientId; } +void hysteriaConstruct( + Proxy &node, + const std::string &group, + const std::string &remarks, + const std::string &server, + const std::string &port, + const std::string &ports, + const std::string &protocol, + const std::string &obfs_protocol, + const std::string &up, + const std::string &up_speed, + const std::string &down, + const std::string &down_speed, + const std::string &auth, + const std::string &auth_str, + const std::string &obfs, + const std::string &sni, + const std::string &fingerprint, + const std::string &ca, + const std::string &ca_str, + const std::string &recv_window_conn, + const std::string &recv_window, + const std::string &disable_mtu_discovery, + const std::string &hop_interval, + const std::string &alpn, + tribool tfo, + tribool scv, + const std::string &underlying_proxy = "" +) { + commonConstruct(node, ProxyType::Hysteria, group, remarks, server, port, tribool(), tfo, scv, tribool(), underlying_proxy); + node.Ports = ports; + node.Protocol = protocol; + node.OBFSParam = obfs_protocol; + if (!up.empty()) + { + if (up.length() > 4 && up.find("bps") == up.length() - 3) + + node.Up = up; + else if (to_int(up)) + { + node.UpSpeed = to_int(up); + node.Up = up + " Mbps"; + } + } + if (!up_speed.empty()) + node.UpSpeed = to_int(up_speed); + if (!down.empty()) + { + if (down.length() > 4 && down.find("bps") == down.length() - 3) + node.Down = down; + else if (to_int(down)) + { + node.DownSpeed = to_int(down); + node.Down = down + " Mbps"; + } + } + if (!down_speed.empty()) + node.DownSpeed = to_int(down_speed); + node.AuthStr = auth_str; + if (!auth.empty()) + node.AuthStr = base64Decode(auth); + node.OBFS = obfs; + node.SNI = sni; + node.Fingerprint = fingerprint; + node.Ca = ca; + node.CaStr = ca_str; + node.RecvWindowConn = to_int(recv_window_conn); + node.RecvWindow = to_int(recv_window); + node.DisableMtuDiscovery = disable_mtu_discovery; + node.HopInterval = to_int(hop_interval); + if (!alpn.empty()) + { + node.Alpn = StringArray {alpn}; + } +} + +void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port,const std::string &up, const std::string &down, const std::string &password, const std::string &obfs, const std::string &obfs_password, const std::string &sni, const std::string &fingerprint, const std::string &alpn, const std::string &ca, const std::string &ca_str, const std::string &cwnd, tribool tfo, tribool scv, const std::string &underlying_proxy) { + commonConstruct(node, ProxyType::Hysteria2, group, remarks, server, port, tribool(), tfo, scv, tribool(), underlying_proxy); + node.UpSpeed = to_int(up); + node.DownSpeed = to_int(down); + node.Password = password; + node.OBFS = obfs; + node.OBFSParam = obfs_password; + node.SNI = sni; + node.Fingerprint = fingerprint; + if (!alpn.empty()) + { + node.Alpn = StringArray {alpn}; + } + node.Ca = ca; + node.CaStr = ca_str; + node.CWND = to_int(cwnd); + +} + void explodeVmess(std::string vmess, Proxy &node) { std::string version, ps, add, port, type, id, aid, net, path, host, tls, sni; @@ -981,6 +1076,8 @@ void explodeClash(Node yamlnode, std::vector &nodes) std::string protocol, protoparam, obfs, obfsparam; //ssr std::string user; //socks std::string ip, ipv6, private_key, public_key, mtu; //wireguard + std::string ports, obfs_protocol, up, up_speed, down, down_speed, auth, auth_str,/* obfs, sni,*/ fingerprint, ca, ca_str, recv_window_conn, recv_window, disable_mtu_discovery, hop_interval, alpn; //hysteria + std::string obfs_password, cwnd; //hysteria2 string_array dns_server; tribool udp, tfo, scv; Node singleproxy; @@ -998,6 +1095,7 @@ void explodeClash(Node yamlnode, std::vector &nodes) if(port.empty() || port == "0") continue; udp = safe_as(singleproxy["udp"]); + tfo = safe_as(singleproxy["fast-open"]); scv = safe_as(singleproxy["skip-cert-verify"]); switch(hash_(proxytype)) { @@ -1193,6 +1291,59 @@ void explodeClash(Node yamlnode, std::vector &nodes) wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password, dns_server, mtu, "0", "", "", udp, underlying_proxy); break; + case "hysteria"_hash: + group = HYSTERIA_DEFAULT_GROUP; + singleproxy["ports"] >>= ports; + singleproxy["protocol"] >>= protocol; + singleproxy["obfs-protocol"] >>= obfs_protocol; + singleproxy["up"] >>= up; + singleproxy["up-speed"] >>= up_speed; + singleproxy["down"] >>= down; + singleproxy["down-speed"] >>= down_speed; + singleproxy["auth"] >>= auth; + singleproxy["auth-str"] >>= auth_str; + if (auth_str.empty()) + singleproxy["auth_str"] >>= auth_str; + singleproxy["obfs"] >>= obfs; + singleproxy["sni"] >>= sni; + singleproxy["fingerprint"] >>= fingerprint; + if (singleproxy["alpn"].IsSequence()) + singleproxy["alpn"][0] >>= alpn; + else + singleproxy["alpn"] >>= alpn; + singleproxy["ca"] >>= ca; + singleproxy["ca-str"] >>= ca_str; + singleproxy["recv-window-conn"] >>= recv_window_conn; + singleproxy["recv-window"] >>= recv_window; + singleproxy["disable-mtu-discovery"] >>= disable_mtu_discovery; + if (disable_mtu_discovery.empty()) + singleproxy["disable_mtu_discovery"] >>= disable_mtu_discovery; + singleproxy["hop-interval"] >>= hop_interval; + + hysteriaConstruct(node, group, ps, server, port, ports, protocol, obfs_protocol, up, up_speed, down, down_speed, auth, auth_str, obfs, sni, fingerprint, ca, ca_str, recv_window_conn, recv_window, disable_mtu_discovery, hop_interval, alpn, tfo, scv, underlying_proxy); + break; + case "hysteria2"_hash: + group = HYSTERIA2_DEFAULT_GROUP; + singleproxy["up"] >>= up; + singleproxy["down"] >>= down; + singleproxy["password"] >>= password; + if (password.empty()) + singleproxy["auth"] >>= password; + singleproxy["obfs"] >>= obfs; + singleproxy["obfs-password"] >>= obfs_password; + singleproxy["sni"] >>= sni; + singleproxy["fingerprint"] >>= fingerprint; + if (singleproxy["alpn"].IsSequence()) + singleproxy["alpn"][0] >>= alpn; + else + singleproxy["alpn"] >>= alpn; + singleproxy["ca"] >>= ca; + singleproxy["ca-str"] >>= ca_str; + singleproxy["cwnd"] >>= cwnd; + + hysteria2Construct(node, group, ps, server, port, up, down, password, obfs, obfs_password, sni, fingerprint, alpn, ca, ca_str, cwnd, tfo, scv, underlying_proxy); + break; + default: continue; } @@ -1328,6 +1479,68 @@ void explodeKitsunebi(std::string kit, Proxy &node) vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, ""); } + +void explodeStdHysteria2(std::string hysteria2, Proxy &node) { + std::string add, port, password, host, insecure, up, down, alpn, obfs, obfs_password, remarks, sni, fingerprint; + std::string addition; + tribool scv; + hysteria2 = hysteria2.substr(12); + string_size pos; + + pos = hysteria2.rfind("#"); + if (pos != hysteria2.npos) { + remarks = urlDecode(hysteria2.substr(pos + 1)); + hysteria2.erase(pos); + } + + pos = hysteria2.rfind("?"); + if (pos != hysteria2.npos) { + addition = hysteria2.substr(pos + 1); + hysteria2.erase(pos); + } + + if (strFind(hysteria2, "@")) { + if (regGetMatch(hysteria2, R"(^(.*?)@(.*)[:](\d+)$)", 4, 0, &password, &add, &port)) + return; + } else { + password = getUrlArg(addition, "password"); + if (password.empty()) + return; + + if (!strFind(hysteria2, ":")) + return; + + if (regGetMatch(hysteria2, R"(^(.*)[:](\d+)$)", 3, 0, &add, &port)) + return; + } + + scv = getUrlArg(addition, "insecure"); + up = getUrlArg(addition, "up"); + down = getUrlArg(addition, "down"); + // the alpn is not supported officially yet + alpn = getUrlArg(addition, "alpn"); + obfs = getUrlArg(addition, "obfs"); + obfs_password = getUrlArg(addition, "obfs-password"); + sni = getUrlArg(addition, "sni"); + fingerprint = getUrlArg(addition, "pinSHA256"); + if (remarks.empty()) + remarks = add + ":" + port; + + hysteria2Construct(node, HYSTERIA2_DEFAULT_GROUP, remarks, add, port, up, down, password, obfs, obfs_password, sni, fingerprint, "", "", "", "", tribool(), scv, ""); + return; +} + +void explodeHysteria2(std::string hysteria2, Proxy &node) { + hysteria2 = regReplace(hysteria2, "(hysteria2|hy2)://", "hysteria2://"); + + // replace /? with ? + hysteria2 = regReplace(hysteria2, "/\\?", "?", true, false); + if (regMatch(hysteria2, "hysteria2://(.*?)[:](.*)")) { + explodeStdHysteria2(hysteria2, node); + return; + } +} + // 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) void parsePeers(Proxy &node, const std::string &data) { @@ -2223,6 +2436,8 @@ void explode(const std::string &link, Proxy &node) explodeNetch(link, node); else if(startsWith(link, "trojan://")) explodeTrojan(link, node); + else if (strFind(link, "hysteria2://") || strFind(link, "hy2://")) + explodeHysteria2(link, node); else if(isLink(link)) explodeHTTPSub(link, node); } diff --git a/src/parser/subparser.h b/src/parser/subparser.h index 627ff40..53e1d6c 100644 --- a/src/parser/subparser.h +++ b/src/parser/subparser.h @@ -27,6 +27,39 @@ void socksConstruct(Proxy &node, const std::string &group, const std::string &re 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(), 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, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = 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(), const std::string &underlying_proxy = ""); + +void hysteriaConstruct( + Proxy &node, + const std::string &group, + const std::string &remarks, + const std::string &server, + const std::string &port, + const std::string &ports, + const std::string &protocol, + const std::string &obfs_protocol, + const std::string &up, + const std::string &up_speed, + const std::string &down, + const std::string &down_speed, + const std::string &auth, + const std::string &auth_str, + const std::string &obfs, + const std::string &sni, + const std::string &fingerprint, + const std::string &ca, + const std::string &ca_str, + const std::string &recv_window_conn, + const std::string &recv_window, + const std::string &disable_mtu_discovery, + const std::string &hop_interval, + const string_array &alpn, + tribool tfo, + tribool scv, + const std::string &underlying_proxy = "" +); + +void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port,const std::string &up, const std::string &down, const std::string &password, const std::string &obfs, const std::string &obfs_password, const std::string &sni, const std::string &fingerprint, const string_array &alpn, const std::string &ca, const std::string &caStr, const std::string &cwnd, tribool tfo, tribool scv, const std::string &underlying_proxy = ""); + void explodeVmess(std::string vmess, Proxy &node); void explodeSSR(std::string ssr, Proxy &node); void explodeSS(std::string ss, Proxy &node); @@ -35,6 +68,8 @@ void explodeQuan(const std::string &quan, Proxy &node); void explodeStdVMess(std::string vmess, Proxy &node); void explodeShadowrocket(std::string kit, Proxy &node); void explodeKitsunebi(std::string kit, Proxy &node); +void explodeHysteria2(std::string hysteria2, Proxy &node); + /// Parse a link void explode(const std::string &link, Proxy &node); void explodeSSD(std::string link, std::vector &nodes); From 1d56f44696db920330e828e198f77fbded157418 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Sun, 8 Dec 2024 22:27:01 +0800 Subject: [PATCH 36/43] Add TCP Fast Open option to Clash configs --- src/generator/config/subexport.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index eacb22a..c77e21b 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -271,9 +271,9 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr processRemark(x.Remark, remarks_list, false); - tribool udp = ext.udp; - tribool scv = ext.skip_cert_verify; + tribool udp = ext.udp, tfo = ext.tfo, scv = ext.skip_cert_verify; udp.define(x.UDP); + tfo.define(x.TCPFastOpen); scv.define(x.AllowInsecure); singleproxy["name"] = x.Remark; @@ -561,6 +561,8 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr // sees in https://dreamacro.github.io/clash/configuration/outbound.html#snell if(udp && x.Type != ProxyType::Snell) singleproxy["udp"] = true; + if(!tfo.is_undef()) + singleproxy["tfo"] = tfo.get(); if(proxy_block) singleproxy.SetStyle(YAML::EmitterStyle::Block); else From 05910ac5ddbdb50dc66894e3fd86eb5687fb72de Mon Sep 17 00:00:00 2001 From: Fanx Date: Tue, 31 Dec 2024 15:37:24 +0800 Subject: [PATCH 37/43] Update Flag category (#810) --- base/snippets/emoji.toml | 38 +++++++++++++++++++------------------- base/snippets/emoji.txt | 38 +++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/base/snippets/emoji.toml b/base/snippets/emoji.toml index 7a423d0..2455f41 100644 --- a/base/snippets/emoji.toml +++ b/base/snippets/emoji.toml @@ -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:(? Date: Tue, 31 Dec 2024 15:38:56 +0800 Subject: [PATCH 38/43] Add CORS header to httplib webserver --- src/server/webserver_httplib.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/webserver_httplib.cpp b/src/server/webserver_httplib.cpp index 7bb836f..627f510 100644 --- a/src/server/webserver_httplib.cpp +++ b/src/server/webserver_httplib.cpp @@ -170,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) From 05959b09b4c589faf1c155685805e8d03ea5ed6c Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:11:45 +0800 Subject: [PATCH 39/43] Url-decode file name before adding as Clash rule provider (#815) --- src/generator/template/templates.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/generator/template/templates.cpp b/src/generator/template/templates.cpp index 75ed31a..0f53adc 100644 --- a/src/generator/template/templates.cpp +++ b/src/generator/template/templates.cpp @@ -386,10 +386,10 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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 &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 &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,13 +466,13 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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); @@ -490,14 +490,14 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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; } @@ -505,14 +505,14 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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; } @@ -525,7 +525,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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; } From 691193731fbedc4a36004d45351cc7a121b71982 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:26:52 +0800 Subject: [PATCH 40/43] Update toml11 to v4.3.0 --- scripts/build.alpine.release.sh | 2 +- scripts/build.macos.release.sh | 2 +- scripts/build.windows.release.sh | 2 +- src/config/binding.h | 76 ++++++++++++++++---------------- src/handler/settings.cpp | 8 ++-- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/scripts/build.alpine.release.sh b/scripts/build.alpine.release.sh index 2dba424..304492d 100644 --- a/scripts/build.alpine.release.sh +++ b/scripts/build.alpine.release.sh @@ -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 diff --git a/scripts/build.macos.release.sh b/scripts/build.macos.release.sh index e554c99..96ef522 100644 --- a/scripts/build.macos.release.sh +++ b/scripts/build.macos.release.sh @@ -41,7 +41,7 @@ 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 --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 . sudo make install -j6 > /dev/null diff --git a/scripts/build.windows.release.sh b/scripts/build.windows.release.sh index 2b3e49b..c085989 100644 --- a/scripts/build.windows.release.sh +++ b/scripts/build.windows.release.sh @@ -38,7 +38,7 @@ cmake -DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF -DRAPIDJSON_BUILD make install -j4 cd .. -git clone https://github.com/ToruNiina/toml11 --branch v3.8.1 --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 diff --git a/src/config/binding.h b/src/config/binding.h index c6e3c07..e069869 100644 --- a/src/config/binding.h +++ b/src/config/binding.h @@ -17,9 +17,9 @@ namespace toml static ProxyGroupConfig from_toml(const value& v) { ProxyGroupConfig conf; - conf.Name = toml::find(v, "name"); - String type = toml::find(v, "type"); - String strategy = toml::find_or(v, "strategy", ""); + conf.Name = find(v, "name"); + String type = find(v, "type"); + String strategy = find_or(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(v, "url"); - conf.Interval = toml::find(v, "interval"); - conf.Tolerance = toml::find_or(v, "tolerance", 0); + conf.Url = find(v, "url"); + conf.Interval = find(v, "interval"); + conf.Tolerance = find_or(v, "tolerance", 0); if(v.contains("lazy")) - conf.Lazy = toml::find_or(v, "lazy", false); + conf.Lazy = find_or(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(v, "url"); - conf.Interval = toml::find(v, "interval"); + conf.Url = find(v, "url"); + conf.Interval = find(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(v, "url"); - conf.Interval = toml::find(v, "interval"); + conf.Url = find(v, "url"); + conf.Interval = find(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; @@ -66,24 +66,24 @@ namespace toml break; case "smart"_hash: conf.Type = ProxyGroupType::Smart; - conf.Url = toml::find(v, "url"); - conf.Interval = toml::find(v, "interval"); - conf.Tolerance = toml::find_or(v, "tolerance", 0); + conf.Url = find(v, "url"); + conf.Interval = find(v, "interval"); + conf.Tolerance = find_or(v, "tolerance", 0); if(v.contains("lazy")) - conf.Lazy = toml::find_or(v, "lazy", false); + conf.Lazy = find_or(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; 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(v, "rule", {}); - conf.UsingProvider = toml::find_or(v, "use", {}); + conf.Timeout = find_or(v, "timeout", 5); + conf.Proxies = find_or(v, "rule", {}); + conf.UsingProvider = find_or(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; } }; @@ -94,8 +94,8 @@ namespace toml static RulesetConfig from_toml(const value& v) { RulesetConfig conf; - conf.Group = toml::find(v, "group"); - String type = toml::find_or(v, "type", "surge-ruleset"); + conf.Group = find(v, "group"); + String type = find_or(v, "type", "surge-ruleset"); switch(hash_(type)) { /* @@ -132,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(v, "ruleset"); - conf.Interval = toml::find_or(v, "interval", 86400); + conf.Url += find(v, "ruleset"); + conf.Interval = find_or(v, "interval", 86400); return conf; } }; @@ -148,14 +148,14 @@ namespace toml RegexMatchConfig conf; if(v.contains("script")) { - conf.Script = toml::find(v, "script"); + conf.Script = find(v, "script"); return conf; } - conf.Match = toml::find(v, "match"); + conf.Match = find(v, "match"); if(v.contains("emoji")) - conf.Replace = toml::find(v, "emoji"); + conf.Replace = find(v, "emoji"); else - conf.Replace = toml::find(v, "replace"); + conf.Replace = find(v, "replace"); return conf; } }; @@ -166,10 +166,10 @@ namespace toml static CronTaskConfig from_toml(const value& v) { CronTaskConfig conf; - conf.Name = toml::find(v, "name"); - conf.CronExp = toml::find(v, "cronexp"); - conf.Path = toml::find(v, "path"); - conf.Timeout = toml::find_or(v, "timeout", 0); + conf.Name = find(v, "name"); + conf.CronExp = find(v, "cronexp"); + conf.Path = find(v, "path"); + conf.Timeout = find_or(v, "timeout", 0); return conf; } }; diff --git a/src/handler/settings.cpp b/src/handler/settings.cpp index 86e399e..a90bec7 100644 --- a/src/handler/settings.cpp +++ b/src/handler/settings.cpp @@ -567,13 +567,13 @@ void readYAMLConf(YAML::Node &node) } template -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(v, k); if constexpr (sizeof...(args) > 0) find_if_exist(v, std::forward(args)...); } -void operate_toml_kv_table(const std::vector &arr, const toml::key &key_name, const toml::key &value_name, std::function binary_op) +void operate_toml_kv_table(const std::vector &arr, const toml::value::key_type &key_name, const toml::value::key_type &value_name, std::function binary_op) { for(const toml::table &table : arr) { @@ -803,7 +803,7 @@ void readConf() return readYAMLConf(yaml); } toml::value conf = parseToml(prefdata, global.prefPath); - if(!conf.is_uninitialized() && toml::find_or(conf, "version", 0)) + if(!conf.is_empty() && toml::find_or(conf, "version", 0)) return readTOMLConf(conf); } catch (YAML::Exception &e) @@ -1213,7 +1213,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(conf, "version", 0)) + if(!conf.is_empty() && toml::find_or(conf, "version", 0)) return loadExternalTOML(conf, ext); } catch (YAML::Exception &e) From 223d75a10adc2afdcbc06b6c96192f8bf3fd589d Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:29:46 +0800 Subject: [PATCH 41/43] Fix Clash rule provider did not trim domains and ip-cidrs --- src/handler/interfaces.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index 38b1197..61b0945 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -224,7 +224,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS) output_content += " - '"; if(strLine[posb - 2] == 'X') output_content += "+."; - output_content += strLine.substr(posb, pose); + output_content += trim(strLine.substr(posb, pose)); output_content += "'\n"; continue; case 4: @@ -233,7 +233,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS) if(filterLine()) continue; output_content += " - '"; - output_content += strLine.substr(posb, pose); + output_content += trim(strLine.substr(posb, pose)); output_content += "'\n"; continue; case 5: @@ -243,7 +243,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS) continue; if(strLine[posb - 2] == 'X') output_content += '.'; - output_content += strLine.substr(posb, pose); + output_content += trim(strLine.substr(posb, pose)); output_content += '\n'; continue; case 6: From b39de30db99f7619fefe593f3a8f16dc789e1541 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:31:30 +0800 Subject: [PATCH 42/43] Update toml11 to v4.3.0 in Dockerfile --- scripts/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Dockerfile b/scripts/Dockerfile index a9c2a32..048956c 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -30,7 +30,7 @@ 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 && \ From 92f66bf5b58be5b3e605bb481db5f5ffd6b2aa78 Mon Sep 17 00:00:00 2001 From: Tindy X <49061470+tindy2013@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:08:34 +0800 Subject: [PATCH 43/43] Fix Clash classical rule provider not renaming properly --- src/generator/template/templates.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generator/template/templates.cpp b/src/generator/template/templates.cpp index 0f53adc..f9917e3 100644 --- a/src/generator/template/templates.cpp +++ b/src/generator/template/templates.cpp @@ -357,10 +357,10 @@ int renderClashScript(YAML::Node &base_rule, std::vector &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;