Compare commits

..

63 Commits

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

* Fix build error

* Remove deleted rules repository

---------

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

* Add surge smart group support

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

* Fix duplicate break statement in binding.h
2024-09-30 06:39:23 +08:00
asdlokj1qpi23
a1f919eafb update version and docs. 2024-08-30 10:28:16 +08:00
TioaChan
644b9040b9 Add timezone env to Docker image (#776) 2024-08-27 17:34:01 +08:00
ak1ra
3f2281e284 Add clash.external_controller option in config file (#772) 2024-08-27 17:33:17 +08:00
SpadeLushen
0c11565cc9 Use Proxy.Host as alternative tls.server_name in sing-box to support Trojan's sni (#777)
Co-authored-by: Spade Lushen <7971040+SpadeLushen@users.noreply.github.com>
2024-08-27 17:33:02 +08:00
TAKO
6974910734 Update Flag category (#744)
* Update emoji.toml

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

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

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

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

---------

Co-authored-by: Tindy X <49061470+tindy2013@users.noreply.github.com>
2024-04-02 18:34:33 +08:00
Tindy X
eef5328506 Enhancements
Refine libcurl logs.
Do not retry web request on API mode.
Optimize codes.
2023-12-22 14:46:52 +08:00
38 changed files with 1105 additions and 849 deletions

View File

@@ -1,11 +1,11 @@
name: Publish Docker Image
on:
on:
push:
branches: [ master ]
tags:
- '**'
concurrency:
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true

6
.gitignore vendored
View File

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

View File

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

View File

@@ -6,7 +6,7 @@ original git: https://github.com/asdlokj1qpi23/subconverter
[![Build Status](https://github.com/asdlokj1qpi233/subconverter/actions/workflows/docker.yml/badge.svg)](https://github.com/asdlokj1qpi233/subconverter/actions)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/asdlokj1qpi233/subconverter.svg)](https://github.com/asdlokj1qpi23/subconverter/tags)
[![GitHub release](https://img.shields.io/github/release/asdlokj1qpi233/subconverter.svg)](https://github.com/asdlokj1qpi23/subconverter/releases)
[![GitHub release](https://img.shields.io/github/release/asdlokj1qpi233/subconverter.svg)](https://github.com/asdlokj1qpi233/subconverter/releases)
[![GitHub license](https://img.shields.io/github/license/asdlokj1qpi233/subconverter.svg)](https://github.com/tindy2013/subconverter/blob/master/LICENSE)
[Docker README](https://github.com/asdlokj1qpi23/subconverter/blob/master/README-docker.md)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,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 && \
@@ -53,6 +53,10 @@ RUN apk add --no-cache --virtual subconverter-deps pcre2 libcurl yaml-cpp
COPY --from=builder /subconverter/subconverter /usr/bin/
COPY --from=builder /subconverter/base /base/
ENV TZ=Africa/Abidjan
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime
RUN echo $TZ > /etc/timezone
# set entry
WORKDIR /base
CMD subconverter

View File

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

View File

@@ -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
@@ -63,4 +63,4 @@ chmod +r ./*
cd ..
mv base subconverter
set +xe
set +xe

View File

@@ -1,33 +1,9 @@
#!/bin/bash
set -xe
# 获取系统架构
ARCH=$(uname -m)
if [ "$ARCH" == "x86_64" ]; then
TOOLCHAIN="mingw-w64-x86_64"
else
TOOLCHAIN="mingw-w64-i686"
fi
pacman -S --needed --noconfirm base-devel ${TOOLCHAIN}-toolchain ${TOOLCHAIN}-cmake ${TOOLCHAIN}-nghttp2 ${TOOLCHAIN}-openssl
git clone https://github.com/curl/curl --depth=1 --branch curl-8_8_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 \
-DCURL_STATICLIB=ON \
-DCURL_DISABLE_SOCKETPAIR=ON \
-DCURL_DISABLE_NONBLOCKING=ON .
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
cd ..
@@ -40,8 +16,26 @@ cd ..
git clone https://github.com/ftk/quickjspp --depth=1
cd quickjspp
patch quickjs/quickjs-libc.c -i ../scripts/patches/0001-quickjs-libc-add-realpath-for-Windows.patch
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_FLAGS="-D__MINGW_FENV_DEFINED" .
make quickjs -j4
# 如果是 32 位编译,则处理 libquickjs.a去掉重复定义的符号
# 注意:此处通过检测目标架构环境变量,你也可以根据实际情况加个判断
echo "处理 32 位 libquickjs.a去除重复定义的符号..."
mkdir -p tmp_lib
cd tmp_lib
# 解包静态库
ar x ../quickjs/libquickjs.a
# 对每个目标文件,删除这几个符号
for obj in *.o; do
objcopy --strip-symbol=__mingw_fe_pc53_env --strip-symbol=__mingw_fe_pc64_env --strip-symbol=__mingw_fe_dfl_env "$obj"
done
# 重新打包为新的静态库
ar rcs ../quickjs/libquickjs_fixed.a *.o
cd ..
# 用处理后的库覆盖原库(或直接安装新库)
mv quickjs/libquickjs_fixed.a quickjs/libquickjs.a
install -d "$MINGW_PREFIX/lib/quickjs/"
install -m644 quickjs/libquickjs.a "$MINGW_PREFIX/lib/quickjs/"
install -d "$MINGW_PREFIX/include/quickjs"
@@ -62,7 +56,7 @@ cmake -DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF -DRAPIDJSON_BUILD
make install -j4
cd ..
git clone https://github.com/ToruNiina/toml11 --branch="v3.7.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
@@ -78,4 +72,4 @@ make -j4
rm subconverter.exe
# shellcheck disable=SC2046
g++ $(find CMakeFiles/subconverter.dir/src -name "*.obj") curl/lib/libcurl.a -o base/subconverter.exe -static -lbcrypt -lpcre2-8 -l:quickjs/libquickjs.a -llibcron -lyaml-cpp -liphlpapi -lcrypt32 -lws2_32 -lwsock32 -lz -s
mv base subconverter
mv base subconverter

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,12 +25,18 @@
extern string_array ss_ciphers, ssr_ciphers;
const string_array clashr_protocols = {"origin", "auth_sha1_v4", "auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a",
"auth_chain_b"};
const string_array clashr_obfs = {"plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth",
"tls1.2_ticket_fastauth"};
const string_array clash_ssr_ciphers = {"rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "chacha20-ietf", "xchacha20", "none"};
const string_array clashr_protocols = {
"origin", "auth_sha1_v4", "auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a",
"auth_chain_b"
};
const string_array clashr_obfs = {
"plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth",
"tls1.2_ticket_fastauth"
};
const string_array clash_ssr_ciphers = {
"rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "chacha20-ietf", "xchacha20", "none"
};
std::string
vmessLinkConstruct(const std::string &remarks, const std::string &add, const std::string &port, const std::string &type,
@@ -70,7 +76,8 @@ bool matchRange(const std::string &range, int target) {
bool match = false;
std::string range_begin_str, range_end_str;
int range_begin, range_end;
static const std::string reg_num = "-?\\d+", reg_range = "(\\d+)-(\\d+)", reg_not = "\\!-?(\\d+)", reg_not_range = "\\!(\\d+)-(\\d+)", reg_less = "(\\d+)-", reg_more = "(\\d+)\\+";
static const std::string reg_num = "-?\\d+", reg_range = "(\\d+)-(\\d+)", reg_not = "\\!-?(\\d+)", reg_not_range =
"\\!(\\d+)-(\\d+)", reg_less = "(\\d+)-", reg_more = "(\\d+)\\+";
for (std::string &x: vArray) {
if (regMatch(x, reg_num)) {
if (to_int(x, INT_MAX) == target)
@@ -105,20 +112,24 @@ bool matchRange(const std::string &range, int target) {
bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &node) {
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<ProxyType, const char *> 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::VLESS, "VLESS"},
{ProxyType::Hysteria, "HYSTERIA"},
{ProxyType::Hysteria2, "HYSTERIA2"}};
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<ProxyType, const char *> 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::VLESS, "VLESS"},
{ProxyType::Hysteria, "HYSTERIA"},
{ProxyType::Hysteria2, "HYSTERIA2"}
};
if (startsWith(rule, "!!GROUP=")) {
regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
@@ -149,7 +160,7 @@ bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &
void processRemark(std::string &remark, const string_array &remarks_list, bool proc_comma = true) {
// Replace every '=' with '-' in the remark string to avoid parse errors from the clients.
// Surge is tested to yield an error when handling '=' in the remark string,
// Surge is tested to yield an error when handling '=' in the remark string,
// not sure if other clients have the same problem.
std::replace(remark.begin(), remark.end(), '=', '-');
@@ -184,8 +195,7 @@ groupGenerate(const std::string &rule, std::vector<Proxy> &nodelist, string_arra
auto filter = (std::function<std::string(const std::vector<Proxy> &)>) ctx.eval("filter");
std::string result_list = filter(nodelist);
filtered_nodelist = split(regTrim(result_list), "\n");
}
catch (qjs::exception) {
} catch (qjs::exception) {
script_print_stack(ctx);
}
}, global.scriptCleanContext);
@@ -207,16 +217,28 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
std::vector<Proxy> 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;
}
@@ -333,8 +355,9 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
case ProxyType::ShadowsocksR:
//ignoring all nodes with unsupported obfs, protocols and encryption
if (ext.filter_deprecated) {
if (!clashR && std::find(clash_ssr_ciphers.cbegin(), clash_ssr_ciphers.cend(), x.EncryptMethod) ==
clash_ssr_ciphers.cend())
if (!clashR &&
std::find(clash_ssr_ciphers.cbegin(), clash_ssr_ciphers.cend(), x.EncryptMethod) ==
clash_ssr_ciphers.cend())
continue;
if (std::find(clashr_protocols.cbegin(), clashr_protocols.cend(), x.Protocol) ==
clashr_protocols.cend())
@@ -541,7 +564,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singleproxy["tfo"] = tfo.get();
if (xudp && udp)
singleproxy["xudp"] = true;
if(!x.PacketEncoding.empty()){
if (!x.PacketEncoding.empty()) {
singleproxy["packet-encoding"] = x.PacketEncoding;
}
if (!x.Flow.empty())
@@ -614,7 +637,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
// sees in https://dreamacro.github.io/clash/configuration/outbound.html#snell
if (udp && x.Type != ProxyType::Snell && x.Type != ProxyType::TUIC)
singleproxy["udp"] = true;
if (block)
if(proxy_block)
singleproxy.SetStyle(YAML::EmitterStyle::Block);
else
singleproxy.SetStyle(YAML::EmitterStyle::Flow);
@@ -623,7 +646,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
nodelist.emplace_back(x);
}
if (compact)
if(proxy_compact)
proxies.SetStyle(YAML::EmitterStyle::Flow);
if (ext.nodelist) {
@@ -639,68 +662,84 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
yamlnode["Proxy"] = proxies;
for (const ProxyGroupConfig &x: extra_proxy_group) {
for(const ProxyGroupConfig &x : extra_proxy_group)
{
YAML::Node singlegroup;
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) {
case ProxyGroupType::Select:
case ProxyGroupType::Relay:
break;
case ProxyGroupType::LoadBalance:
singlegroup["strategy"] = x.StrategyStr();
[[fallthrough]];
case ProxyGroupType::URLTest:
if (!x.Lazy.is_undef())
singlegroup["lazy"] = x.Lazy.get();
[[fallthrough]];
case ProxyGroupType::Fallback:
singlegroup["url"] = x.Url;
if (x.Interval > 0)
singlegroup["interval"] = x.Interval;
if (x.Tolerance > 0)
singlegroup["tolerance"] = x.Tolerance;
break;
default:
continue;
switch(x.Type)
{
case ProxyGroupType::Select:
case ProxyGroupType::Relay:
break;
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();
[[fallthrough]];
case ProxyGroupType::Fallback:
singlegroup["url"] = x.Url;
if(x.Interval > 0)
singlegroup["interval"] = x.Interval;
if(x.Tolerance > 0)
singlegroup["tolerance"] = x.Tolerance;
break;
default:
continue;
}
if (!x.DisableUdp.is_undef())
if(!x.DisableUdp.is_undef())
singlegroup["disable-udp"] = x.DisableUdp.get();
for (const auto &y: x.Proxies)
for(const auto& y : x.Proxies)
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
if (!x.UsingProvider.empty())
if(!x.UsingProvider.empty())
singlegroup["use"] = x.UsingProvider;
else {
if (filtered_nodelist.empty())
else
{
if(filtered_nodelist.empty())
filtered_nodelist.emplace_back("DIRECT");
}
if (!filtered_nodelist.empty())
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) {
if (original_group["name"].as<std::string>() == x.Name) {
for(auto && original_group : original_groups)
{
if(original_group["name"].as<std::string>() == x.Name)
{
original_group.reset(singlegroup);
replace_flag = true;
break;
}
}
if (!replace_flag)
if(!replace_flag)
original_groups.push_back(singlegroup);
}
if(group_compact)
original_groups.SetStyle(YAML::EmitterStyle::Flow);
if (ext.clash_new_field_name)
if(ext.clash_new_field_name)
yamlnode["proxy-groups"] = original_groups;
else
yamlnode["Proxy Group"] = original_groups;
}
void formatterShortId(std::string &input) {
std::string target = "short-id:";
size_t startPos = input.find(target);
@@ -726,18 +765,17 @@ void formatterShortId(std::string &input) {
// 继续查找下一个实例
startPos = input.find(target, startPos + 1);
}
}
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf,
std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group,
bool clashR, extra_settings &ext) {
YAML::Node yamlnode;
try {
yamlnode = YAML::Load(base_conf);
}
catch (std::exception &e) {
} catch (std::exception &e) {
writeLog(0, std::string("Clash base loader failed with error: ") + e.what(), LOG_LEVEL_ERROR);
return "";
}
@@ -805,7 +843,8 @@ std::string generatePeer(Proxy &node, bool client_id_as_reserved = false) {
}
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf,
std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group,
int surge_ver, extra_settings &ext) {
INIReader ini;
std::string output_nodelist;
@@ -840,8 +879,11 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
processRemark(x.Remark, remarks_list);
std::string &hostname = x.Hostname, &sni = x.ServerName, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption;
std::string port = std::to_string(x.Port);
std::string &hostname = x.Hostname, &sni = x.ServerName, &username = x.Username, &password = x.Password, &method
= x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &edge = x.Edge, &
path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.
OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption, &underlying_proxy = x.UnderlyingProxy;
std::string port = std::to_string(x.Port);;
bool &tlssecure = x.TLSSecure;
tribool udp = ext.udp, tfo = ext.tfo, scv = ext.skip_cert_verify, tls13 = ext.tls13;
@@ -856,7 +898,8 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
switch (x.Type) {
case ProxyType::Shadowsocks:
if (surge_ver >= 3 || surge_ver == -3) {
proxy = "ss, " + hostname + ", " + port + ", encrypt-method=" + method + ", password=" + password;
proxy = "ss, " + hostname + ", " + port + ", encrypt-method=" + method + ", password=" +
password;
} else {
proxy = "custom, " + hostname + ", " + port + ", " + method + ", " + password +
", https://github.com/pobizhe/SSEncrypt/raw/master/SSEncrypt.module";
@@ -905,8 +948,10 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
if (ext.surge_ssr_path.empty() || surge_ver < 2)
continue;
proxy = "external, exec=\"" + ext.surge_ssr_path + "\", args=\"";
args = {"-l", std::to_string(local_port), "-s", hostname, "-p", port, "-m", method, "-k", password,
"-o", obfs, "-O", protocol};
args = {
"-l", std::to_string(local_port), "-s", hostname, "-p", port, "-m", method, "-k", password,
"-o", obfs, "-O", protocol
};
if (!obfsparam.empty()) {
args.emplace_back("-g");
args.emplace_back(std::move(obfsparam));
@@ -975,11 +1020,18 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
proxy += ", version=" + std::to_string(x.SnellVersion);
break;
case ProxyType::Hysteria2:
if (surge_ver < 4 && surge_ver != -3)
if (surge_ver < 4)
continue;
proxy = "hysteria2, " + hostname + ", " + port + ", password=" + password;
proxy = "hysteria, " + hostname + ", " + port + ", password=" + password;
if (x.DownSpeed)
proxy += ", download-bandwidth=" + x.DownSpeed;
if (!scv.is_undef())
proxy += ", skip-cert-verify=" + scv.get_str();
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;
case ProxyType::WireGuard:
if (surge_ver < 4 && surge_ver != -3)
@@ -1011,7 +1063,8 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
proxy += ", tfo=" + tfo.get_str();
if (!udp.is_undef())
proxy += ", udp-relay=" + udp.get_str();
if (underlying_proxy != "")
proxy += ", underlying-proxy=" + underlying_proxy;
if (ext.nodelist)
output_nodelist += x.Remark + " = " + proxy + "\n";
else {
@@ -1032,6 +1085,7 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
switch (x.Type) {
case ProxyGroupType::Select:
case ProxyGroupType::Smart:
case ProxyGroupType::URLTest:
case ProxyGroupType::Fallback:
break;
@@ -1084,7 +1138,8 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
}
if (ext.enable_rule_generator)
rulesetToSurge(ini, ruleset_content_array, surge_ver, ext.overwrite_original_rules, ext.managed_config_prefix);
rulesetToSurge(ini, ruleset_content_array, surge_ver, ext.overwrite_original_rules,
ext.managed_config_prefix);
return ini.to_string();
}
@@ -1096,7 +1151,12 @@ std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &
for (Proxy &x: nodes) {
std::string remark = x.Remark;
std::string &hostname = x.Hostname, &sni = x.ServerName, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &faketype = x.FakeType;
std::string &hostname = x.Hostname, &sni = x.ServerName, &password = x.Password, &method = x.EncryptMethod, &
plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &protoparam = x.
ProtocolParam,
&obfs = x.OBFS, &obfsparam = x.OBFSParam, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.
Host, &
path = x.Path, &faketype = x.FakeType;
bool &tlssecure = x.TLSSecure;
std::string port = std::to_string(x.Port);
std::string aid = std::to_string(x.AlterId);
@@ -1113,23 +1173,28 @@ std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &
if (std::find(ssr_ciphers.begin(), ssr_ciphers.end(), method) != ssr_ciphers.end() &&
plugin.empty())
proxyStr = "ssr://" + urlSafeBase64Encode(
hostname + ":" + port + ":origin:" + method + ":plain:" + urlSafeBase64Encode(password) \
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(remark));
hostname + ":" + port + ":origin:" + method + ":plain:" +
urlSafeBase64Encode(password)
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(
remark));
} else
continue;
break;
case ProxyType::ShadowsocksR:
if (ssr) {
proxyStr = "ssr://" + urlSafeBase64Encode(
hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" +
urlSafeBase64Encode(password) \
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(remark) \
+ "&obfsparam=" + urlSafeBase64Encode(obfsparam) + "&protoparam=" + urlSafeBase64Encode(protoparam));
hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" +
urlSafeBase64Encode(password)
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(
remark)
+ "&obfsparam=" + urlSafeBase64Encode(obfsparam) + "&protoparam=" +
urlSafeBase64Encode(protoparam));
} else if (ss) {
if (std::find(ss_ciphers.begin(), ss_ciphers.end(), method) != ss_ciphers.end() &&
protocol == "origin" && obfs == "plain")
proxyStr =
"ss://" + urlSafeBase64Encode(method + ":" + password) + "@" + hostname + ":" + port +
"ss://" + urlSafeBase64Encode(method + ":" + password) + "@" + hostname + ":" +
port +
"#" + urlEncode(remark);
} else
continue;
@@ -1138,8 +1203,8 @@ std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &
if (!vmess)
continue;
proxyStr = "vmess://" + base64Encode(
vmessLinkConstruct(remark, hostname, port, faketype, id, aid, transproto, path, host,
tlssecure ? "tls" : ""));
vmessLinkConstruct(remark, hostname, port, faketype, id, aid, transproto, path, host,
tlssecure ? "tls" : ""));
break;
case ProxyType::Trojan:
if (!trojan)
@@ -1181,7 +1246,8 @@ std::string proxyToSSSub(std::string base_conf, std::vector<Proxy> &nodes, extra
base_conf = "{}";
rapidjson::ParseResult result = base.Parse(base_conf.data());
if (!result)
writeLog(0, std::string("SIP008 base loader failed with error: ") + rapidjson::GetParseError_En(result.Code()) +
writeLog(0, std::string("SIP008 base loader failed with error: ") +
rapidjson::GetParseError_En(result.Code()) +
" (" + std::to_string(result.Offset()) + ")", LOG_LEVEL_ERROR);
rapidjson::Value proxies(rapidjson::kArrayType);
@@ -1210,20 +1276,21 @@ std::string proxyToSSSub(std::string base_conf, std::vector<Proxy> &nodes, extra
}
rapidjson::Value proxy(rapidjson::kObjectType);
proxy.CopyFrom(base, alloc)
| AddMemberOrReplace("remarks", rapidjson::Value(remark.c_str(), remark.size()), alloc)
| AddMemberOrReplace("server", rapidjson::Value(hostname.c_str(), hostname.size()), alloc)
| AddMemberOrReplace("server_port", rapidjson::Value(x.Port), alloc)
| AddMemberOrReplace("method", rapidjson::Value(method.c_str(), method.size()), alloc)
| AddMemberOrReplace("password", rapidjson::Value(password.c_str(), password.size()), alloc)
| AddMemberOrReplace("plugin", rapidjson::Value(plugin.c_str(), plugin.size()), alloc)
| AddMemberOrReplace("plugin_opts", rapidjson::Value(pluginopts.c_str(), pluginopts.size()), alloc);
| AddMemberOrReplace("remarks", rapidjson::Value(remark.c_str(), remark.size()), alloc)
| AddMemberOrReplace("server", rapidjson::Value(hostname.c_str(), hostname.size()), alloc)
| AddMemberOrReplace("server_port", rapidjson::Value(x.Port), alloc)
| AddMemberOrReplace("method", rapidjson::Value(method.c_str(), method.size()), alloc)
| AddMemberOrReplace("password", rapidjson::Value(password.c_str(), password.size()), alloc)
| AddMemberOrReplace("plugin", rapidjson::Value(plugin.c_str(), plugin.size()), alloc)
| AddMemberOrReplace("plugin_opts", rapidjson::Value(pluginopts.c_str(), pluginopts.size()), alloc);
proxies.PushBack(proxy, alloc);
}
return proxies | SerializeObject();
}
std::string
proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array,
proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) {
INIReader ini;
ini.store_any_line = true;
@@ -1261,7 +1328,12 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
processRemark(x.Remark, remarks_list);
std::string &hostname = x.Hostname, &method = x.EncryptMethod, &password = x.Password, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &edge = x.Edge, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts = x.PluginOption, &username = x.Username;
std::string &hostname = x.Hostname, &method = x.EncryptMethod, &password = x.Password, &id = x.UserId, &
transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &edge = x.Edge, &protocol = x.
Protocol,
&protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &plugin = x.Plugin, &pluginopts
= x.
PluginOption, &username = x.Username;
std::string port = std::to_string(x.Port);
bool &tlssecure = x.TLSSecure;
tribool scv;
@@ -1274,7 +1346,8 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
if (method == "auto")
method = "chacha20-ietf-poly1305";
proxyStr =
x.Remark + " = vmess, " + hostname + ", " + port + ", " + method + ", \"" + id + "\", group=" +
x.Remark + " = vmess, " + hostname + ", " + port + ", " + method + ", \"" + id +
"\", group=" +
x.Group;
if (tlssecure) {
proxyStr += ", over-tls=true, tls-host=" + host;
@@ -1294,10 +1367,12 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
case ProxyType::ShadowsocksR:
if (ext.nodelist) {
proxyStr = "ssr://" + urlSafeBase64Encode(
hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" +
urlSafeBase64Encode(password) \
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(x.Remark) \
+ "&obfsparam=" + urlSafeBase64Encode(obfsparam) + "&protoparam=" + urlSafeBase64Encode(protoparam));
hostname + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" +
urlSafeBase64Encode(password)
+ "/?group=" + urlSafeBase64Encode(x.Group) + "&remarks=" + urlSafeBase64Encode(
x.Remark)
+ "&obfsparam=" + urlSafeBase64Encode(obfsparam) + "&protoparam=" +
urlSafeBase64Encode(protoparam));
} else {
proxyStr = x.Remark + " = shadowsocksr, " + hostname + ", " + port + ", " + method + ", \"" +
password + "\", group=" + x.Group + ", protocol=" + protocol + ", obfs=" + obfs;
@@ -1316,7 +1391,8 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
proxyStr += "&group=" + urlSafeBase64Encode(x.Group) + "#" + urlEncode(x.Remark);
} else {
proxyStr =
x.Remark + " = shadowsocks, " + hostname + ", " + port + ", " + method + ", \"" + password +
x.Remark + " = shadowsocks, " + hostname + ", " + port + ", " + method + ", \"" +
password +
"\", group=" + x.Group;
if (plugin == "obfs-local" && !pluginopts.empty()) {
proxyStr += ", " + replaceAllDistinct(pluginopts, ";", ", ");
@@ -1325,11 +1401,12 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
break;
case ProxyType::HTTP:
case ProxyType::HTTPS:
proxyStr = x.Remark + " = http, upstream-proxy-address=" + hostname + ", upstream-proxy-port=" + port +
", group=" + x.Group;
proxyStr =
x.Remark + " = http, upstream-proxy-address=" + hostname + ", upstream-proxy-port=" + port +
", group=" + x.Group;
if (!username.empty() && !password.empty())
proxyStr += ", upstream-proxy-auth=true, upstream-proxy-username=" + username +
", upstream-proxy-password=" + password;
", upstream-proxy-password=" + password;
else
proxyStr += ", upstream-proxy-auth=false";
@@ -1345,11 +1422,12 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
proxyStr = "http://" + urlSafeBase64Encode(proxyStr);
break;
case ProxyType::SOCKS5:
proxyStr = x.Remark + " = socks, upstream-proxy-address=" + hostname + ", upstream-proxy-port=" + port +
proxyStr = x.Remark + " = socks, upstream-proxy-address=" + hostname + ", upstream-proxy-port=" +
port +
", group=" + x.Group;
if (!username.empty() && !password.empty())
proxyStr += ", upstream-proxy-auth=true, upstream-proxy-username=" + username +
", upstream-proxy-password=" + password;
", upstream-proxy-password=" + password;
else
proxyStr += ", upstream-proxy-auth=false";
@@ -1439,7 +1517,8 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetC
}
std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf,
std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group,
extra_settings &ext) {
INIReader ini;
ini.store_any_line = true;
@@ -1485,7 +1564,10 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
processRemark(x.Remark, remarks_list);
std::string &hostname = x.Hostname, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &password = x.Password, &plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &username = x.Username;
std::string &hostname = x.Hostname, &method = x.EncryptMethod, &id = x.UserId, &transproto = x.TransferProtocol,
&host = x.Host, &path = x.Path, &password = x.Password, &plugin = x.Plugin, &pluginopts = x.PluginOption
, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam, &
username = x.Username;
std::string port = std::to_string(x.Port);
bool &tlssecure = x.TLSSecure;
@@ -1536,7 +1618,8 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
proxyStr += ", obfs=over-tls, obfs-host=" + host;
break;
case ProxyType::Shadowsocks:
proxyStr = "shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password;
proxyStr =
"shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password;
if (!plugin.empty()) {
switch (hash_(plugin)) {
case "simple-obfs"_hash:
@@ -1568,8 +1651,9 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
break;
case ProxyType::ShadowsocksR:
proxyStr = "shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password +
", ssr-protocol=" + protocol;
proxyStr =
"shadowsocks = " + hostname + ":" + port + ", method=" + method + ", password=" + password +
", ssr-protocol=" + protocol;
if (!protoparam.empty())
proxyStr += ", ssr-protocol-param=" + protoparam;
proxyStr += ", obfs=" + obfs;
@@ -1578,8 +1662,9 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
break;
case ProxyType::HTTP:
case ProxyType::HTTPS:
proxyStr = "http = " + hostname + ":" + port + ", username=" + (username.empty() ? "none" : username) +
", password=" + (password.empty() ? "none" : password);
proxyStr =
"http = " + hostname + ":" + port + ", username=" + (username.empty() ? "none" : username) +
", password=" + (password.empty() ? "none" : password);
if (tlssecure) {
proxyStr += ", over-tls=true";
if (!tls13.is_undef())
@@ -1693,7 +1778,7 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
std::string proxies = join(filtered_nodelist, ", ");
std::string singlegroup = type + "=" + x.Name + ", " + proxies;
if (type != "static") {
if (x.Type != ProxyGroupType::Select && x.Type != ProxyGroupType::SSID) {
singlegroup += ", check-interval=" + std::to_string(x.Interval);
if (x.Tolerance > 0)
singlegroup += ", tolerance=" + std::to_string(x.Tolerance);
@@ -1724,9 +1809,10 @@ std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::strin
writer.String("password");
if (!userinfo.empty()) {
std::string data = replaceAllDistinct(userinfo, "; ", "&");
std::string upload = getUrlArg(data, "upload"), download = getUrlArg(data, "download"), total = getUrlArg(data,
"total"), expiry = getUrlArg(
data, "expire");
std::string upload = getUrlArg(data, "upload"), download = getUrlArg(data, "download"), total = getUrlArg(
data,
"total"), expiry = getUrlArg(
data, "expire");
double used = (to_number(upload, 0.0) + to_number(download, 0.0)) / std::pow(1024, 3) * 1.0, tot =
to_number(total, 0.0) / std::pow(1024, 3) * 1.0;
writer.Key("traffic_used");
@@ -1746,7 +1832,8 @@ std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::strin
writer.StartArray();
for (Proxy &x: nodes) {
std::string &hostname = x.Hostname, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &pluginopts = x.PluginOption, &protocol = x.Protocol, &obfs = x.OBFS;
std::string &hostname = x.Hostname, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &
pluginopts = x.PluginOption, &protocol = x.Protocol, &obfs = x.OBFS;
switch (x.Type) {
case ProxyType::Shadowsocks:
@@ -1848,7 +1935,8 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Rulese
case ProxyType::Shadowsocks:
if (!x.Plugin.empty())
continue;
proxy = x.Remark + ", ss, ss://" + urlSafeBase64Encode(method + ":" + password) + "@" + hostname + ":" +
proxy = x.Remark + ", ss, ss://" + urlSafeBase64Encode(method + ":" + password) + "@" + hostname +
":" +
port;
break;
case ProxyType::VMess:
@@ -1883,11 +1971,13 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Rulese
proxy += "&sockopt.tcpfastopen=" + tfo.get_str();
break;
case ProxyType::SOCKS5:
proxy = x.Remark + ", builtin, socks, address=" + hostname + ", port=" + port + ", user=" + username +
proxy = x.Remark + ", builtin, socks, address=" + hostname + ", port=" + port + ", user=" +
username +
", pass=" + password;
break;
case ProxyType::HTTP:
proxy = x.Remark + ", builtin, http, address=" + hostname + ", port=" + port + ", user=" + username +
proxy = x.Remark + ", builtin, http, address=" + hostname + ", port=" + port + ", user=" +
username +
", pass=" + password;
break;
default:
@@ -1952,7 +2042,8 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Rulese
}
std::string
proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array,
proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) {
INIReader ini;
std::string output_nodelist;
@@ -1977,7 +2068,10 @@ proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector
}
processRemark(x.Remark, remarks_list);
std::string &hostname = x.Hostname, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &plugin = x.Plugin, &pluginopts = x.PluginOption, &id = x.UserId, &transproto = x.TransferProtocol, &host = x.Host, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &obfsparam = x.OBFSParam;
std::string &hostname = x.Hostname, &username = x.Username, &password = x.Password, &method = x.EncryptMethod, &
plugin = x.Plugin, &pluginopts = x.PluginOption, &id = x.UserId, &transproto = x.TransferProtocol, &host
= x.Host, &path = x.Path, &protocol = x.Protocol, &protoparam = x.ProtocolParam, &obfs = x.OBFS, &
obfsparam = x.OBFSParam;
std::string port = std::to_string(x.Port), aid = std::to_string(x.AlterId);
bool &tlssecure = x.TLSSecure;
@@ -1992,7 +2086,8 @@ proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector
if (plugin == "simple-obfs" || plugin == "obfs-local") {
if (!pluginopts.empty())
proxy += "," +
replaceAllDistinct(replaceAllDistinct(pluginopts, ";obfs-host=", ","), "obfs=", "");
replaceAllDistinct(replaceAllDistinct(pluginopts, ";obfs-host=", ","), "obfs=",
"");
} else if (!plugin.empty())
continue;
break;
@@ -2177,7 +2272,8 @@ proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector
if (x.Type != ProxyGroupType::Select) {
group += ",url=" + x.Url + ",interval=" + std::to_string(x.Interval);
if (x.Type == ProxyGroupType::LoadBalance) {
group += ",algorithm=" + std::string(x.Strategy == BalanceStrategy::RoundRobin ? "round-robin" : "pcc");
group += ",algorithm=" +
std::string(x.Strategy == BalanceStrategy::RoundRobin ? "round-robin" : "pcc");
if (x.Timeout > 0)
group += ",max-timeout=" + std::to_string(x.Timeout);
}
@@ -2294,7 +2390,8 @@ bool isNumeric(const std::string &str) {
}
void
proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector<RulesetContent> &ruleset_content_array,
proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json,
std::vector<RulesetContent> &ruleset_content_array,
const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) {
using namespace rapidjson_ext;
rapidjson::Document::AllocatorType &allocator = json.GetAllocator();
@@ -2342,16 +2439,16 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
}
break;
}
// case ProxyType::ShadowsocksR: {
// addSingBoxCommonMembers(proxy, x, "shadowsocksr", allocator);
// proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
// proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
// proxy.AddMember("protocol", rapidjson::StringRef(x.Protocol.c_str()), allocator);
// proxy.AddMember("protocol_param", rapidjson::StringRef(x.ProtocolParam.c_str()), allocator);
// proxy.AddMember("obfs", rapidjson::StringRef(x.OBFS.c_str()), allocator);
// proxy.AddMember("obfs_param", rapidjson::StringRef(x.OBFSParam.c_str()), allocator);
// break;
// }
// case ProxyType::ShadowsocksR: {
// addSingBoxCommonMembers(proxy, x, "shadowsocksr", allocator);
// proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
// proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
// proxy.AddMember("protocol", rapidjson::StringRef(x.Protocol.c_str()), allocator);
// proxy.AddMember("protocol_param", rapidjson::StringRef(x.ProtocolParam.c_str()), allocator);
// proxy.AddMember("obfs", rapidjson::StringRef(x.OBFS.c_str()), allocator);
// proxy.AddMember("obfs_param", rapidjson::StringRef(x.OBFSParam.c_str()), allocator);
// break;
// }
case ProxyType::VMess: {
addSingBoxCommonMembers(proxy, x, "vmess", allocator);
proxy.AddMember("uuid", rapidjson::StringRef(x.UserId.c_str()), allocator);
@@ -2370,7 +2467,7 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
proxy.AddMember("packet_encoding", rapidjson::StringRef("xudp"), allocator);
if (!x.Flow.empty())
proxy.AddMember("flow", rapidjson::StringRef(x.Flow.c_str()), allocator);
if(!x.PacketEncoding.empty()){
if (!x.PacketEncoding.empty()) {
proxy.AddMember("packet_encoding", rapidjson::StringRef(x.PacketEncoding.c_str()), allocator);
}
rapidjson::Value vlesstransport(rapidjson::kObjectType);
@@ -2431,8 +2528,8 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
proxy.AddMember("inet4_bind_address", rapidjson::StringRef(x.SelfIP.c_str()), allocator);
rapidjson::Value addresses(rapidjson::kArrayType);
addresses.PushBack(rapidjson::StringRef(x.SelfIP.append("/32").c_str()), allocator);
// if (!x.SelfIPv6.empty())
// addresses.PushBack(rapidjson::StringRef(x.SelfIPv6.c_str()), allocator);
// if (!x.SelfIPv6.empty())
// addresses.PushBack(rapidjson::StringRef(x.SelfIPv6.c_str()), allocator);
proxy.AddMember("local_address", addresses, allocator);
if (!x.SelfIPv6.empty())
proxy.AddMember("inet6_bind_address", rapidjson::StringRef(x.SelfIPv6.c_str()), allocator);
@@ -2520,7 +2617,6 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
addSingBoxCommonMembers(proxy, x, "hysteria2", allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
if (!x.TLSSecure) {
rapidjson::Value tls(rapidjson::kObjectType);
tls.AddMember("enabled", true, allocator);
if (!x.ServerName.empty())
@@ -2560,7 +2656,6 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
obfs.AddMember("password", rapidjson::StringRef(x.OBFSPassword.c_str()), allocator);
}
proxy.AddMember("obfs", obfs, allocator);
}
break;
}
@@ -2586,7 +2681,8 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
proxy.AddMember("tls", tls, allocator);
}
if (!x.CongestionControl.empty()) {
proxy.AddMember("congestion_control", rapidjson::StringRef(x.CongestionControl.c_str()), allocator);
proxy.AddMember("congestion_control", rapidjson::StringRef(x.CongestionControl.c_str()),
allocator);
}
if (!x.UdpRelayMode.empty()) {
proxy.AddMember("udp_relay_mode", rapidjson::StringRef(x.UdpRelayMode.c_str()), allocator);
@@ -2623,7 +2719,7 @@ proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector
if (!x.PublicKey.empty()) {
reality.AddMember("public_key", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
}
// auto shortIds = stringArrayToJsonArray(x.ShortId, ",", allocator);
// auto shortIds = stringArrayToJsonArray(x.ShortId, ",", allocator);
if (!x.ShortId.empty()) {
reality.AddMember("short_id", rapidjson::StringRef(x.ShortId.c_str()), allocator);
} else {

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -564,14 +564,14 @@ void readYAMLConf(YAML::Node &node)
writeLog(0, "Load preference settings in YAML format completed.", LOG_LEVEL_INFO);
}
//template <class T, class... U>
//void find_if_exist(const toml::value &v, const toml::key &k, T& target, U&&... args)
//{
// if(v.contains(k)) target = toml::find<T>(v, k);
// if constexpr (sizeof...(args) > 0) find_if_exist(v, std::forward<U>(args)...);
//}
template <class T, class... U>
void find_if_exist(const toml::value &v, const toml::value::key_type &k, T& target, U&&... args)
{
if(v.contains(k)) target = toml::find<T>(v, k);
if constexpr (sizeof...(args) > 0) find_if_exist(v, std::forward<U>(args)...);
}
void operate_toml_kv_table(const std::vector<toml::table> &arr, const toml::key &key_name, const toml::key &value_name, std::function<void (const toml::value&, const toml::value&)> binary_op)
void operate_toml_kv_table(const std::vector<toml::table> &arr, const toml::value::key_type &key_name, const toml::value::key_type &value_name, std::function<void (const toml::value&, const toml::value&)> binary_op)
{
for(const toml::table &table : arr)
{
@@ -800,7 +800,7 @@ void readConf()
return readYAMLConf(yaml);
}
toml::value conf = parseToml(prefdata, global.prefPath);
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
if(!conf.is_empty() && toml::find_or<int>(conf, "version", 0))
return readTOMLConf(conf);
}
catch (YAML::Exception &e)
@@ -1209,7 +1209,7 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
if(yaml.size() && yaml["custom"].IsDefined())
return loadExternalYAML(yaml, ext);
toml::value conf = parseToml(base_content, path);
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
if(!conf.is_empty() && toml::find_or<int>(conf, "version", 0))
return loadExternalTOML(conf, ext);
}
catch (YAML::Exception &e)

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,8 @@
using String = std::string;
using StringArray = std::vector<String>;
enum class ProxyType {
enum class ProxyType
{
Unknown,
Shadowsocks,
ShadowsocksR,
@@ -126,10 +127,14 @@ struct Proxy {
String Flow;
bool FlowShow = false;
tribool DisableSni;
uint32_t UpSpeed;
uint32_t DownSpeed;
String SNI;
tribool ReduceRtt;
String UdpRelayMode = "native";
uint16_t RequestTimeout = 15000;
String token;
String UnderlyingProxy;
std::vector<String> AlpnList;
String PacketEncoding;
};

View File

@@ -36,7 +36,7 @@ std::string modSSMD5 = "f7653207090ce3389115e9c88541afe0";
void commonConstruct(Proxy &node, ProxyType type, const std::string &group, const std::string &remarks,
const std::string &server, const std::string &port, const tribool &udp, const tribool &tfo,
const tribool &scv, const tribool &tls13) {
const tribool &scv, const tribool &tls13,const std::string& underlying_proxy) {
node.Type = type;
node.Group = group;
node.Remark = remarks;
@@ -46,6 +46,7 @@ void commonConstruct(Proxy &node, ProxyType type, const std::string &group, cons
node.TCPFastOpen = tfo;
node.AllowInsecure = scv;
node.TLS13 = tls13;
node.UnderlyingProxy = underlying_proxy;
}
void vmessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
@@ -53,8 +54,8 @@ void vmessConstruct(Proxy &node, const std::string &group, const std::string &re
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,
const std::vector<std::string> &alpnList, tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::VMess, group, remarks, add, port, udp, tfo, scv, tls13);
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::VMess, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.UserId = id.empty() ? "00000000-0000-0000-0000-000000000000" : id;
node.AlterId = to_int(aid);
node.EncryptMethod = cipher;
@@ -76,8 +77,8 @@ void vmessConstruct(Proxy &node, const std::string &group, const std::string &re
void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &protocol, const std::string &method,
const std::string &obfs, const std::string &password, const std::string &obfsparam,
const std::string &protoparam, tribool udp, tribool tfo, tribool scv) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool());
const std::string &protoparam, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.EncryptMethod = method;
node.Protocol = protocol;
@@ -89,8 +90,8 @@ void ssrConstruct(Proxy &node, const std::string &group, const std::string &rema
void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &method,
const std::string &plugin, const std::string &pluginopts, tribool udp, tribool tfo, tribool scv,
tribool tls13) {
commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13);
tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Shadowsocks, group, remarks, server, port, udp, tfo, scv, tls13,underlying_proxy);
node.Password = password;
node.EncryptMethod = method;
node.Plugin = plugin;
@@ -99,17 +100,17 @@ void ssConstruct(Proxy &node, const std::string &group, const std::string &remar
void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password, tribool udp,
tribool tfo, tribool scv) {
commonConstruct(node, ProxyType::SOCKS5, group, remarks, server, port, udp, tfo, scv, tribool());
tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::SOCKS5, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Username = username;
node.Password = password;
}
void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password, bool tls,
tribool tfo, tribool scv, tribool tls13) {
tribool tfo, tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, tls ? ProxyType::HTTPS : ProxyType::HTTP, group, remarks, server, port, tribool(), tfo, scv,
tls13);
tls13,underlying_proxy);
node.Username = username;
node.Password = password;
node.TLSSecure = tls;
@@ -121,8 +122,8 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
const std::vector<std::string> &alpnList,
bool tlssecure,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13);
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13,underlying_proxy);
node.Password = password;
node.Host = host;
node.TLSSecure = tlssecure;
@@ -135,8 +136,8 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &obfs,
const std::string &host, uint16_t version, tribool udp, tribool tfo, tribool scv) {
commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool());
const std::string &host, uint16_t version, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.OBFS = obfs;
node.Host = host;
@@ -147,8 +148,8 @@ void wireguardConstruct(Proxy &node, const std::string &group, const std::string
const std::string &port, const std::string &selfIp, const std::string &selfIpv6,
const std::string &privKey, const std::string &pubKey, const std::string &psk,
const string_array &dns, const std::string &mtu, const std::string &keepalive,
const std::string &testUrl, const std::string &clientId, const tribool &udp) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool());
const std::string &testUrl, const std::string &clientId, const tribool &udp,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool(),underlying_proxy);
node.SelfIP = selfIp;
node.SelfIPv6 = selfIpv6;
node.PrivateKey = privKey;
@@ -168,8 +169,8 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
const std::string &obfsParam, const std::string &insecure, const std::string &ports,
const std::string &sni, tribool udp,
tribool tfo, tribool scv,
tribool tls13) {
commonConstruct(node, ProxyType::Hysteria, group, remarks, add, port, udp, tfo, scv, tls13);
tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Hysteria, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.Auth = auth;
node.Host = (host.empty() && !isIPv4(add) && !isIPv6(add)) ? add.data() : trim(host);
node.UpMbps = up;
@@ -191,8 +192,8 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
const std::string &pbk, const std::string &sid, const std::string &fp, const std::string &sni,
const std::vector<std::string> &alpnList,const std::string &packet_encoding,
tribool udp, tribool tfo,
tribool scv, tribool tls13) {
commonConstruct(node, ProxyType::VLESS, group, remarks, add, port, udp, tfo, scv, tls13);
tribool scv, tribool tls13,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::VLESS, group, remarks, add, port, udp, tfo, scv, tls13,underlying_proxy);
node.UserId = id.empty() ? "00000000-0000-0000-0000-000000000000" : id;
node.AlterId = to_int(aid);
node.EncryptMethod = cipher;
@@ -231,8 +232,8 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
const std::string &obfsParam, const std::string &obfsPassword, const std::string &sni,
const std::string &publicKey, const std::string &ports,
tribool udp, tribool tfo,
tribool scv) {
commonConstruct(node, ProxyType::Hysteria2, group, remarks, add, port, udp, tfo, scv, tribool());
tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::Hysteria2, group, remarks, add, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.Host = (host.empty() && !isIPv4(add) && !isIPv6(add)) ? add.data() : trim(host);
node.UpMbps = up;
@@ -251,8 +252,8 @@ void tuicConstruct(Proxy &node, const std::string &group, const std::string &rem
const std::string &sni, const std::string &uuid, const std::string &udpRelayMode,
const std::string &token,
tribool udp, tribool tfo,
tribool scv, tribool reduceRtt, tribool disableSni, uint16_t request_timeout) {
commonConstruct(node, ProxyType::TUIC, group, remarks, add, port, udp, tfo, scv, tribool());
tribool scv, tribool reduceRtt, tribool disableSni, uint16_t request_timeout,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::TUIC, group, remarks, add, port, udp, tfo, scv, tribool(),underlying_proxy);
node.Password = password;
node.Alpn = alpn;
node.ServerName = sni;
@@ -1309,7 +1310,7 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["ipv6"] >>= ipv6;
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp);
dns_server, mtu, "0", "", "", udp,"");
break;
case "vless"_hash:
group = XRAY_DEFAULT_GROUP;
@@ -1582,7 +1583,7 @@ void explodeStdVless(std::string vless, Proxy &node) {
remarks = urlDecode(vless.substr(pos + 1));
vless.erase(pos);
}
const std::string stdvless_matcher = R"(^([\da-f]{4}(?:[\da-f]{4}-){4}[\da-f]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
const std::string stdvless_matcher = R"(^([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
if (regGetMatch(vless, stdvless_matcher, 5, 0, &id, &add, &port, &addition))
return;
@@ -2160,7 +2161,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
}
wireguardConstruct(node, WG_DEFAULT_GROUP, remarks, "", "0", ip, ipv6, private_key, "", "", dns_servers,
mtu, keepalive, test_url, "", udp);
mtu, keepalive, test_url, "", udp,"");
parsePeers(node, peer);
break;
default:
@@ -2823,7 +2824,7 @@ void explodeSingbox(rapidjson::Value &outbounds, std::vector<Proxy> &nodes) {
password = GetMember(singboxNode, "pre_shared_key");
dns_server = {"8.8.8.8"};
wireguardConstruct(node, group, ps, server, port, ip, ipv6, private_key, public_key, password,
dns_server, mtu, "0", "", "", udp);
dns_server, mtu, "0", "", "", udp,"");
break;
case "socks"_hash:
group = SOCKS_DEFAULT_GROUP;

View File

@@ -25,7 +25,7 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
const std::string &down, const std::string &alpn, const std::string &obfsParam,
const std::string &insecure, const std::string &ports, const std::string &sni,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
void hysteria2Construct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &password, const std::string &host,
@@ -33,7 +33,7 @@ void hysteria2Construct(Proxy &node, const std::string &group, const std::string
const std::string &obfsParam, const std::string &obfsPassword, const std::string &sni,
const std::string &publicKey, const std::string &ports,
tribool udp, tribool tfo,
tribool scv);
tribool scv,const std::string& underlying_proxy="");
void vlessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
@@ -42,45 +42,45 @@ void vlessConstruct(Proxy &node, const std::string &group, const std::string &re
const std::string &pkd, const std::string &sid, const std::string &fp, const std::string &sni,
const std::vector<std::string> &alpnList,const std::string &packet_encoding,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
void vmessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
const std::string &net, const std::string &cipher, const std::string &path, const std::string &host,
const std::string &edge, const std::string &tls, const std::string &sni,
const std::vector<std::string> &alpnList, tribool udp = tribool(),
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &protocol, const std::string &method,
const std::string &obfs, const std::string &password, const std::string &obfsparam,
const std::string &protoparam, tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool());
tribool scv = tribool(),const std::string& underlying_proxy="");
void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &method,
const std::string &plugin, const std::string &pluginopts, tribool udp = tribool(),
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password,
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),const std::string& underlying_proxy="");
void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &username, const std::string &password, bool tls,
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool(),const std::string& underlying_proxy="");
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &network,
const std::string &host, const std::string &path, const std::string &fp, const std::string &sni,
const std::vector<std::string> &alpnList,
bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool());
tribool tls13 = tribool(),const std::string& underlying_proxy="");
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &obfs,
const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool());
tribool scv = tribool(),const std::string& underlying_proxy="");
void tuicConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &password, const std::string &congestion_control,
@@ -89,7 +89,7 @@ void tuicConstruct(Proxy &node, const std::string &group, const std::string &rem
const std::string &token,
tribool udp = tribool(), tribool tfo = tribool(),
tribool scv = tribool(), tribool reduceRtt = tribool(), tribool disableSni = tribool(),
uint16_t request_timeout = 15000);
uint16_t request_timeout = 15000,const std::string& underlying_proxy="");
void explodeVmess(std::string vmess, Proxy &node);

View File

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

View File

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

View File

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

View File

@@ -5,9 +5,16 @@
#include <map>
#include <string.h>
struct strICaseComp {
bool operator()(const std::string &lhs, const std::string &rhs) const {
return strcasecmp(lhs.c_str(), rhs.c_str()) > 0;
struct strICaseComp
{
bool operator() (const std::string &lhs, const std::string &rhs) const
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end(),
[](unsigned char c1, unsigned char c2)
{
return ::tolower(c1) < ::tolower(c2);
});
}
};

View File

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

View File

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