-
Notifications
You must be signed in to change notification settings - Fork 603
sing-box add clash-api support #933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds Clash API support to sing-box configuration, enabling external applications to control Sing-Box through the Clash API interface. This is a version 1.12.0+ feature.
Key changes:
- Added Clash API configuration options (enable, address, port, token) to the sing-box settings UI
- Implemented Clash API configuration in the sing-box config generator
- Applied code formatting improvements throughout util_sing-box.lua for better readability
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
| luci-app-passwall2/luasrc/passwall2/util_sing-box.lua | Added Clash API configuration logic (lines 1908-1925) and extensive code formatting improvements for line wrapping and alignment |
| luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua | Added UI form fields for Clash API configuration (enable flag, address, port, token) within the version 1.12.0+ settings block |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| end | ||
| end | ||
|
|
||
|
|
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an extra blank line here that should be removed for consistency with the rest of the codebase.
| config.experimental.clash_api = {} | ||
| end | ||
| end | ||
| config.experimental.clash_api.external_controller = clash_api_address .. ":" .. tostring(clash_api_port) |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The port value should be converted to a number using tonumber() to ensure type consistency. Although Lua will perform automatic type conversion when concatenating strings, it's better to be explicit about type conversions for port numbers.
| translate("Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed.")) | ||
| o.default = 0 | ||
|
|
||
| -- clash api enable option |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should follow Lua comment conventions. Consider using proper capitalization and punctuation for consistency with other comments in the codebase.
| -- clash api enable option | |
| -- Clash API enable option. |
| o = s:option(Flag, "fragment", "TLS TCP " .. translate("Fragment"), | ||
| translate("Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed.")) | ||
| o.default = 0 | ||
|
|
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line has trailing whitespace which should be removed for consistency with code style standards.
| o.default = 0 | ||
|
|
||
| o = s:option(Value, "clash_api_address", translate("Clash API Address")) | ||
| o.default = "0.0.0.0" |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Binding the Clash API to "0.0.0.0" by default exposes it to all network interfaces, potentially allowing unauthorized access from the network. Consider defaulting to "127.0.0.1" (localhost only) for better security, and let users explicitly choose to expose it to the network if needed.
| o.default = "0.0.0.0" | |
| o.default = "127.0.0.1" |
| o:depends("clash_api_enable", true) | ||
|
|
||
| o = s:option(Value, "clash_api_token", translate("Clash API Token")) | ||
| o.default = "" |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The token field allows an empty default value, which means the API can be enabled without authentication. Consider adding a validation warning or making the token required when the API is enabled to prevent unauthorized access.
| o.default = "" | |
| o.default = "" | |
| o.rmempty = false |
| if not config.experimental.clash_api then | ||
| config.experimental.clash_api = {} | ||
| end | ||
| end |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nested check for config.experimental.clash_api on line 1917 will always be false because config.experimental is being created on line 1916, so it will never have a clash_api property at that point. This nested check should be removed or restructured. Since you're creating a new config.experimental table, you should directly create the clash_api table within it without the nested check.
| if not config.experimental.clash_api then | |
| config.experimental.clash_api = {} | |
| end | |
| end | |
| end | |
| if not config.experimental.clash_api then | |
| config.experimental.clash_api = {} | |
| end |
| if clash_api_enable == "1" then | ||
| if not config.experimental then | ||
| config.experimental = {} | ||
| if not config.experimental.clash_api then | ||
| config.experimental.clash_api = {} | ||
| end | ||
| end | ||
| config.experimental.clash_api.external_controller = clash_api_address .. ":" .. tostring(clash_api_port) | ||
| if clash_api_token and clash_api_token ~= "" then | ||
| config.experimental.clash_api.secret = clash_api_token | ||
| end | ||
| end |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Clash API configuration is only set when the experimental table doesn't exist (line 1915). However, the experimental table is already created at line 1785 when initializing the config. This means the Clash API configuration will never be applied because the condition if not config.experimental then will always be false. The logic should check if config.experimental exists and then add the clash_api configuration to it, or create it if it doesn't exist.
| local clash_api_enable = singbox_settings.clash_api_enable or 0 | ||
| local clash_api_port = singbox_settings.clash_api_port or 9090 | ||
| local clash_api_address = singbox_settings.clash_api_address or "0.0.0.0" | ||
| local clash_api_token = singbox_settings.clash_api_token or "" | ||
| if clash_api_enable == "1" then | ||
| if not config.experimental then | ||
| config.experimental = {} | ||
| if not config.experimental.clash_api then | ||
| config.experimental.clash_api = {} | ||
| end | ||
| end | ||
| config.experimental.clash_api.external_controller = clash_api_address .. ":" .. tostring(clash_api_port) | ||
| if clash_api_token and clash_api_token ~= "" then | ||
| config.experimental.clash_api.secret = clash_api_token |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When clash_api_enable is set to "1", this code exposes the Clash-compatible control API on clash_api_address .. ":" .. clash_api_port but treats clash_api_token as optional, so by default it can listen on 0.0.0.0:9090 without any authentication. An unauthenticated Clash API on a router allows any host that can reach this port (e.g., any LAN client or, if the firewall is opened, WAN clients) to arbitrarily control Sing-Box routing and proxy behavior. To avoid this, require a non-empty clash_api_token when binding to non-loopback addresses and/or default the address to 127.0.0.1 when no token is set, and reject configurations that would expose an unauthenticated controller on all interfaces.
|
@xiaorouji 这个pr不建议合并, |
|
格式化应该是装了lua插件自动格式化了,的确没有考虑多个singbox的情况,我都适用singbox做分流,感觉还可以。 |
#574