🐤 Sync 2026-08-14 17:37:24

This commit is contained in:
github-actions[bot] committed 2026-08-14 17:37:24 +08:00
1 parent 706ba9bda3
commit badefb504c
85 files changed
+2298 -2242

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.14.7
PKG_RELEASE:=39
PKG_RELEASE:=40
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -213,7 +213,7 @@ function convertAnytls(node) {
setIf(params, 'alpn', arrayValue(node.alpn));
setIf(params, 'client-fingerprint', node['client-fingerprint'] || node.fingerprint);
if (node['skip-cert-verify'])
params.set('allowInsecure', '1');
params.set('insecure', '1');
if (node.udp)
params.set('udp', '1');
return 'anytls://' + encodeURIComponent(node.password) + '@' + endpoint(node.server, node.port) +
@@ -597,6 +597,11 @@ return view.extend({
so.modalonly = true;
/* AnyTLS fields */
so = ss.taboption('field_general', form.Value, 'anytls_client_metadata', _('Client metadata'),
_('The client metadata sent to the server.'));
so.depends('type', 'anytls');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'anytls_idle_session_check_interval', _('Idle session check interval'),
_('In seconds.'));
so.placeholder = '30';
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -572,6 +572,7 @@ uci.foreach(uciconf, ucinode, (cfg) => {
} : null,
/* AnyTLS */
"client-metadata": cfg.anytls_client_metadata,
"idle-session-check-interval": durationToSecond(cfg.anytls_idle_session_check_interval),
"idle-session-timeout": durationToSecond(cfg.anytls_idle_session_timeout),
"min-idle-session": strToInt(cfg.anytls_min_idle_session),
+32 -13
View File
@@ -1,14 +1,14 @@
msgid ""
msgstr ""
"PO-Revision-Date: 2026-03-02 22:45+0000\n"
"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n"
"PO-Revision-Date: 2026-08-13 09:16+0000\n"
"Last-Translator: Jonatan Nyberg <nickwick@users.noreply.hosted.weblate.org>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/openwrt/"
"luciapplicationsfrpc/sv/>\n"
"Language: sv\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.17-dev\n"
"X-Generator: Weblate 2026.9.dev0\n"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1454
msgid "Add new proxy or visitor..."
@@ -32,7 +32,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:174
msgid "Additional configs"
msgstr "Extra konfigurationer"
msgstr "Ytterligare konfigurationer"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1060
msgid "Additional proxy metadata. Use key=value."
@@ -45,6 +45,8 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:187
msgid "Address of the frps server."
msgstr ""
"AdminAddr anger adressen som administrationsservern binds till.<br />Som "
"standard är värdet ”0.0.0.0”."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1430
msgid "Advanced"
@@ -53,14 +55,20 @@ msgstr "Avancerat"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:839
msgid "Allow users"
msgstr ""
"AdminPort anger porten som administrationsservern ska lyssna på. Om värdet "
"är 0 startas inte administrationsservern.<br />Som standard är värdet 0."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1069
msgid "Annotations"
msgstr ""
"AdminPwd anger lösenordet som administrationsservern använder för "
"inloggning.<br />Som standard är värdet ”admin”."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1070
msgid "Annotations displayed on frps dashboard. Use key=value."
msgstr ""
"AdminUser anger användarnamnet som administrationsservern använder för "
"inloggning.<br />Som standard är värdet ”admin”."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:464
msgid "Assets dir"
@@ -409,7 +417,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1460
msgid "General Settings"
msgstr "Generella inställningar"
msgstr "Allmänna inställningar"
#: applications/luci-app-frpc/root/usr/share/rpcd/acl.d/luci-app-frpc.json:3
msgid "Grant access to LuCI app frpc"
@@ -495,7 +503,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:530
msgid "Heartbeat interval"
msgstr "Hjärtslagsintervall"
msgstr "Heartbeat-intervall"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:531
msgid "Heartbeat interval in seconds."
@@ -554,7 +562,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:659
msgid "Local IP"
msgstr "Lokal IP"
msgstr "Lokal IP-adress"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:523
msgid ""
@@ -583,6 +591,8 @@ msgstr "Lokal port"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:660
msgid "Local service IP or host."
msgstr ""
"LocalIp anger IP-adressen eller värdnamnet som proxyn ska vidarebefordra "
"till."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:664
msgid "Local service port."
@@ -598,7 +608,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:387
msgid "Log level"
msgstr "Logg-nivå"
msgstr "Loggnivå"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:391
msgid "Log max days"
@@ -647,6 +657,9 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:197
msgid "NAT hole STUN server"
msgstr ""
"LoginFailExit styr om klienten ska avslutas efter ett misslyckat "
"inloggningsförsök. Om värdet är false försöker klienten igen tills en "
"inloggning lyckas.<br />Som standard är värdet true."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1390
msgid "NOT RUNNING"
@@ -749,7 +762,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:909
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1463
msgid "Plugin"
msgstr "Insticksprogram"
msgstr "Insticksmodul"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:1015
msgid "Plugin HTTP/2"
@@ -901,11 +914,11 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:153
msgid "Run daemon as group"
msgstr "Kör daemon som grupp"
msgstr "Kör demonen som grupp"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:152
msgid "Run daemon as user"
msgstr "Kör daemon som användare"
msgstr "Kör demonen som användare"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:943
msgid "SOCKS5 password"
@@ -933,7 +946,7 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:186
msgid "Server address"
msgstr "Server-adress"
msgstr "Serveradress"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:847
msgid "Server name"
@@ -1054,14 +1067,20 @@ msgstr ""
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:560
msgid "TLS trusted CA path"
msgstr ""
"TcpMux aktiverar eller inaktiverar multiplexering av TCP-strömmar. Det gör "
"att flera begäranden från en klient kan dela en enda TCP-anslutning. Om "
"värdet är true måste även servern ha TCP-multiplexering aktiverad.<br />Som "
"standard är värdet true."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:483
msgid "Timeout in seconds for connecting to frps."
msgstr ""
"Den här listan kan användas för att ange ytterligare parametrar som inte har "
"tagits med i LuCI."
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:235
msgid "Token"
msgstr "Tecken"
msgstr "Token"
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:244
#: applications/luci-app-frpc/htdocs/luci-static/resources/view/frpc.js:264
+35 -8
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"PO-Revision-Date: 2026-03-22 17:09+0000\n"
"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n"
"PO-Revision-Date: 2026-08-13 09:16+0000\n"
"Last-Translator: Jonatan Nyberg <nickwick@users.noreply.hosted.weblate.org>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/openwrt/"
"luciapplicationsfrps/sv/>\n"
"Language: sv\n"
@@ -24,7 +24,7 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:144
msgid "Additional configs"
msgstr "Extra konfigurationer"
msgstr "Ytterligare konfigurationer"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:257
msgid "Additional scopes to include authentication information."
@@ -72,7 +72,7 @@ msgstr "Bindningsadress"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:157
msgid "Bind port"
msgstr "Bind port"
msgstr "Bindningsport"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:969
msgid "Collecting data ..."
@@ -81,12 +81,16 @@ msgstr "Samlar in data ..."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:323
msgid "Command arguments passed to token source exec."
msgstr ""
"BindAddr anger adressen som servern binds till.<br />Som standard är värdet ”"
"0.0.0.0”."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:300
msgid ""
"Command used to obtain the token. The init script adds --allow-"
"unsafe=TokenSourceExec when this source type is used."
msgstr ""
"BindKcpPort anger KCP-porten som servern lyssnar på. Om värdet är 0 lyssnar "
"servern inte efter KCP-anslutningar.<br />Som standard är värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:977
msgid "Common Settings"
@@ -95,18 +99,25 @@ msgstr "Vanliga inställningar"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:368
msgid "Configuration key: log.level."
msgstr ""
"BindPort anger porten som servern lyssnar på.<br />Som standard är värdet "
"7000."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:538
msgid "Configuration key: transport.quic.keepalivePeriod."
msgstr ""
"BindQuicPort anger QUIC-porten som servern lyssnar på. Om värdet är 0 "
"lyssnar servern inte efter QUIC-anslutningar.<br />Som standard är värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:542
msgid "Configuration key: transport.quic.maxIdleTimeout."
msgstr ""
"BindUdpPort anger UDP-porten som servern lyssnar på. Om värdet är 0 lyssnar "
"servern inte efter UDP-anslutningar.<br />Som standard är värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:546
msgid "Configuration key: transport.quic.maxIncomingStreams."
msgstr ""
"Konfigurationsfiler som inkluderas i den tillfälliga konfigurationsfilen"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:227
msgid "Custom 404 page"
@@ -131,6 +142,8 @@ msgstr "Inaktiverad"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:220
msgid "Do not update traffic when TCPMUX passthrough is enabled."
msgstr ""
"Dashboard TLS Key File anger sökvägen till filen med den privata TLS-nyckeln "
"för att aktivera HTTPS-åtkomst.<br />Krävs om HTTPS är aktiverat."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:224
msgid "Domain suffix for subdomain-based HTTP/HTTPS proxies."
@@ -171,22 +184,30 @@ msgstr "Miljövariabel"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:755
msgid "Environment variable must use KEY=value format."
msgstr ""
"DashboardPort anger porten som instrumentpanelen lyssnar på. Om värdet är 0 "
"startas inte instrumentpanelen.<br />Som standard är värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:333
msgid "Environment variables passed to token source exec. Use KEY=value."
msgstr ""
"DashboardPwd anger lösenordet som instrumentpanelen använder för "
"inloggning.<br />Som standard är värdet ”admin”."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:464
msgid ""
"Export Prometheus metrics on webServer /metrics API. It only takes effect "
"when web server port is set."
msgstr ""
"DashboardUser anger användarnamnet som instrumentpanelen använder för "
"inloggning.<br />Som standard är värdet ”admin”."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:145
msgid ""
"Extra root-level configuration fragments included before generated HTTP "
"plugin sections. Use raw settings for table-specific extra options."
msgstr ""
"DisableLogColor inaktiverar loggfärger när LogWay == ”console” om värdet är "
"true.<br />Som standard är värdet false."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:521
msgid "Force TLS"
@@ -236,7 +257,7 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:161
msgid "KCP bind port"
msgstr ""
msgstr "KCP-bindningsport"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:174
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:193
@@ -260,7 +281,7 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:367
msgid "Log level"
msgstr "Logg-nivå"
msgstr "Loggnivå"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:371
msgid "Log max days"
@@ -301,6 +322,9 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:561
msgid "Maximum ports each client can use. 0 means no limit."
msgstr ""
"LogMaxDays anger det högsta antalet dagar som logginformation lagras innan "
"den tas bort. Detta används endast om LogWay == ”file”.<br />Som standard är "
"värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:504
msgid "Maximum time to wait for a work connection."
@@ -309,6 +333,9 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:564
msgid "NAT hole analysis reserve hours"
msgstr ""
"MaxPortsPerClient anger det högsta antalet portar som en enskild klient får "
"proxyansluta till. Om värdet är 0 tillämpas ingen gräns.<br />Som standard "
"är värdet 0."
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:942
msgid "NOT RUNNING"
@@ -470,11 +497,11 @@ msgstr ""
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:123
msgid "Run daemon as group"
msgstr "Kör daemon som grupp"
msgstr "Kör demonen som grupp"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:122
msgid "Run daemon as user"
msgstr "Kör daemon som användare"
msgstr "Kör demonen som användare"
#: applications/luci-app-frps/htdocs/luci-static/resources/view/frps.js:983
msgid "SSH Tunnel"
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.8.12
PKG_RELEASE:=217
PKG_RELEASE:=218
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -332,7 +332,7 @@ run_socks() {
[ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=$TMP_PATH/$config_file
[ -n "$http_port" ] || http_port=0
[ -n "$http_config_file" ] && [ -z "$(echo ${http_config_file} | grep $TMP_PATH)" ] && http_config_file=$TMP_PATH/$http_config_file
if [ -n "$log_file" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
if [ -n "$log_file" ] && [ "$log_file" != "/dev/null" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
log_file=$TMP_PATH/$log_file
else
log_file="/dev/null"
@@ -535,7 +535,7 @@ run_redir() {
eval_set_val "$@"
local tcp_node_socks_flag tcp_node_http_flag
[ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=${GLOBAL_ACL_PATH}/${config_file}
if [ -n "$log_file" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
if [ -n "$log_file" ] && [ "$log_file" != "/dev/null" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
log_file=${GLOBAL_ACL_PATH}/${log_file}
else
log_file="/dev/null"
@@ -2064,6 +2064,7 @@ get_config() {
DNSMASQ_CONF_DIR="/tmp/dnsmasq.d"
fi
fi
[ -d "$DNSMASQ_CONF_DIR" ] || mkdir -p "$DNSMASQ_CONF_DIR"
set_cache_var GLOBAL_DNSMASQ_CONF ${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf
set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${GLOBAL_ACL_PATH}/dnsmasq.d
@@ -789,9 +789,11 @@ function add_rule(var)
end
if #conf_lines > 0 then
local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
conf_out:write(table.concat(conf_lines, "\n"))
conf_out:write("\n")
conf_out:close()
if conf_out then
conf_out:write(table.concat(conf_lines, "\n"))
conf_out:write("\n")
conf_out:close()
end
end
end
+2 -2
View File
@@ -6,8 +6,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.8.10
PKG_RELEASE:=79
PKG_VERSION:=26.8.14
PKG_RELEASE:=80
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
+118 -114
View File
@@ -4,6 +4,8 @@
module("luci.controller.passwall2", package.seeall)
local api = require "luci.passwall2.api"
local appname = api.appname -- not available
local c_config = api.c_config -- not available
local s_config = api.s_config -- not available
local uci = api.uci -- in funtion index()
local http = require "luci.http"
local util = require "luci.util"
@@ -20,12 +22,14 @@ function index()
end
local api = require "luci.passwall2.api"
local appname = api.appname -- global definitions not available
local c_config = api.c_config -- not available
local s_config = api.s_config -- not available
local uci = api.uci -- in function index()
entry({"admin", "services", appname}).dependent = true
entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true
entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true
local e
if uci:get(appname, "@global[0]", "hide_from_luci") ~= "1" then
if uci:get(c_config, "@global[0]", "hide_from_luci") ~= "1" then
e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("PassWall 2"), 0)
else
e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), nil, 0)
@@ -193,7 +197,7 @@ function check_ip()
end
function reset_config()
uci:revert(appname)
uci:revert(c_config)
luci.sys.call("echo '' > /tmp/log/passwall2.log")
luci.sys.call('/etc/init.d/passwall2 stop')
luci.sys.call('[ -f "/usr/share/passwall2/0_default_config" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2')
@@ -201,14 +205,14 @@ function reset_config()
end
function show_menu()
api.sh_uci_del(appname, "@global[0]", "hide_from_luci", true)
api.sh_uci_del(c_config, "@global[0]", "hide_from_luci", true)
luci.sys.call("rm -rf /tmp/luci-*")
luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
http.redirect(api.url())
end
function hide_menu()
api.sh_uci_set(appname, "@global[0]", "hide_from_luci", "1", true)
api.sh_uci_set(c_config, "@global[0]", "hide_from_luci", "1", true)
luci.sys.call("rm -rf /tmp/luci-*")
luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
@@ -244,10 +248,10 @@ function socks_autoswitch_add_node()
local id = http.formvalue("id")
local key = http.formvalue("key")
if id and id ~= "" and key and key ~= "" then
uci:set(appname, id, "enable_autoswitch", "1")
local new_list = uci:get(appname, id, "autoswitch_backup_node") or {}
uci:set(c_config, id, "enable_autoswitch", "1")
local new_list = uci:get(c_config, id, "autoswitch_backup_node") or {}
for i = #new_list, 1, -1 do
if (uci:get(appname, new_list[i], "remarks") or ""):find(key) then
if (uci:get(c_config, new_list[i], "remarks") or ""):find(key) then
table.remove(new_list, i)
end
end
@@ -256,8 +260,8 @@ function socks_autoswitch_add_node()
table.insert(new_list, e.id)
end
end
uci:set_list(appname, id, "autoswitch_backup_node", new_list)
api.uci_save(uci, appname)
uci:set_list(c_config, id, "autoswitch_backup_node", new_list)
api.uci_save(uci, c_config)
end
http.redirect(api.url("socks_config", id))
end
@@ -266,15 +270,15 @@ function socks_autoswitch_remove_node()
local id = http.formvalue("id")
local key = http.formvalue("key")
if id and id ~= "" and key and key ~= "" then
uci:set(appname, id, "enable_autoswitch", "1")
local new_list = uci:get(appname, id, "autoswitch_backup_node") or {}
uci:set(c_config, id, "enable_autoswitch", "1")
local new_list = uci:get(c_config, id, "autoswitch_backup_node") or {}
for i = #new_list, 1, -1 do
if (uci:get(appname, new_list[i], "remarks") or ""):find(key) then
if (uci:get(c_config, new_list[i], "remarks") or ""):find(key) then
table.remove(new_list, i)
end
end
uci:set_list(appname, id, "autoswitch_backup_node", new_list)
api.uci_save(uci, appname)
uci:set_list(c_config, id, "autoswitch_backup_node", new_list)
api.uci_save(uci, c_config)
end
http.redirect(api.url("socks_config", id))
end
@@ -365,7 +369,7 @@ function socks_status()
local id = http.formvalue("id")
e.index = index
e.socks_status = luci.sys.call(string.format("/bin/busybox top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep '%s' > /dev/null", appname, id)) == 0
local use_http = uci:get(appname, id, "http_port") or 0
local use_http = uci:get(c_config, id, "http_port") or 0
e.use_http = 0
if tonumber(use_http) > 0 then
e.use_http = 1
@@ -435,9 +439,9 @@ function update_config()
local data_t = jsonParse(data) or {}
if next(data_t) then
for k, v in pairs(data_t) do
uci:set(appname, id, k, v)
uci:set(c_config, id, k, v)
end
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http_write_json_ok()
return
end
@@ -449,20 +453,20 @@ function add_node()
local redirect = http.formvalue("redirect")
local uid = api.gen_random_char()
uci:section(appname, "nodes", uid)
uci:section(c_config, "nodes", uid)
local group = http.formvalue("group")
if group and group ~= "default" then
uci:set(appname, uid, "group", group)
uci:set(c_config, uid, "group", group)
end
uci:set(appname, uid, "type", "Xray")
uci:set(c_config, uid, "type", "Xray")
if redirect == "1" then
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http.redirect(api.url("node_config", uid))
else
api.uci_save(uci, appname, true, true)
api.uci_save(uci, c_config, true, true)
http_write_json({result = uid})
end
end
@@ -471,67 +475,67 @@ function set_node()
local type = http.formvalue("type")
local config = http.formvalue("config")
local section = http.formvalue("section")
uci:set(appname, type, config, section)
api.uci_save(uci, appname, true, true)
uci:set(c_config, type, config, section)
api.uci_save(uci, c_config, true, true)
http.redirect(api.url("log"))
end
function copy_node()
local section = http.formvalue("section")
local uid = api.gen_random_char()
uci:section(appname, "nodes", uid)
for k, v in pairs(uci:get_all(appname, section)) do
uci:section(c_config, "nodes", uid)
for k, v in pairs(uci:get_all(c_config, section)) do
if not k:match("^%.") and k ~= "group" then
if k == "remarks" then v = (v or "") .. "(1)" end
uci:set(appname, uid, k, v)
uci:set(c_config, uid, k, v)
end
end
uci:set(appname, uid, "add_mode", 1)
api.uci_save(uci, appname)
uci:set(c_config, uid, "add_mode", 1)
api.uci_save(uci, c_config)
http.redirect(api.url("node_config", uid))
end
function clear_all_nodes()
uci:set(appname, '@global[0]', "enabled", "0")
uci:set(appname, '@global[0]', "socks_enabled", "0")
uci:set(appname, '@global_haproxy[0]', "balancing_enable", "0")
uci:delete(appname, '@global[0]', "node")
uci:foreach(appname, "socks", function(t)
uci:delete(appname, t[".name"])
uci:set_list(appname, t[".name"], "autoswitch_backup_node", {})
uci:set(c_config, '@global[0]', "enabled", "0")
uci:set(c_config, '@global[0]', "socks_enabled", "0")
uci:set(c_config, '@global_haproxy[0]', "balancing_enable", "0")
uci:delete(c_config, '@global[0]', "node")
uci:foreach(c_config, "socks", function(t)
uci:delete(c_config, t[".name"])
uci:set_list(c_config, t[".name"], "autoswitch_backup_node", {})
end)
uci:foreach(appname, "haproxy_config", function(t)
uci:delete(appname, t[".name"])
uci:foreach(c_config, "haproxy_config", function(t)
uci:delete(c_config, t[".name"])
end)
uci:foreach(appname, "acl_rule", function(t)
uci:delete(appname, t[".name"], "node")
uci:foreach(c_config, "acl_rule", function(t)
uci:delete(c_config, t[".name"], "node")
end)
uci:foreach(appname, "nodes", function(node)
uci:delete(appname, node['.name'])
uci:foreach(c_config, "nodes", function(node)
uci:delete(c_config, node['.name'])
end)
uci:foreach(appname, "subscribe_list", function(t)
uci:delete(appname, t[".name"], "md5")
uci:delete(appname, t[".name"], "chain_proxy")
uci:delete(appname, t[".name"], "preproxy_node")
uci:delete(appname, t[".name"], "to_node")
uci:foreach(c_config, "subscribe_list", function(t)
uci:delete(c_config, t[".name"], "md5")
uci:delete(c_config, t[".name"], "chain_proxy")
uci:delete(c_config, t[".name"], "preproxy_node")
uci:delete(c_config, t[".name"], "to_node")
end)
api.uci_save(uci, appname, true, true)
api.uci_save(uci, c_config, true, true)
end
function delete_select_nodes()
local ids = http.formvalue("ids")
local redirect = http.formvalue("redirect")
string.gsub(ids, '[^' .. "," .. ']+', function(w)
if (uci:get(appname, "@global[0]", "node") or "") == w then
uci:delete(appname, '@global[0]', "node")
if (uci:get(c_config, "@global[0]", "node") or "") == w then
uci:delete(c_config, '@global[0]', "node")
end
uci:foreach(appname, "socks", function(t)
uci:foreach(c_config, "socks", function(t)
if t["node"] == w then
uci:delete(appname, t[".name"])
uci:delete(c_config, t[".name"])
end
local changed = false
local auto_switch_node_list = uci:get(appname, t[".name"], "autoswitch_backup_node") or {}
local auto_switch_node_list = uci:get(c_config, t[".name"], "autoswitch_backup_node") or {}
for i = #auto_switch_node_list, 1, -1 do
if w == auto_switch_node_list[i] then
table.remove(auto_switch_node_list, i)
@@ -539,31 +543,31 @@ function delete_select_nodes()
end
end
if changed then
uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list)
uci:set_list(c_config, t[".name"], "autoswitch_backup_node", auto_switch_node_list)
end
end)
uci:foreach(appname, "haproxy_config", function(t)
uci:foreach(c_config, "haproxy_config", function(t)
if t["lbss"] == w then
uci:delete(appname, t[".name"])
uci:delete(c_config, t[".name"])
end
end)
uci:foreach(appname, "acl_rule", function(t)
uci:foreach(c_config, "acl_rule", function(t)
if t["node"] == w then
uci:delete(appname, t[".name"], "node")
uci:delete(c_config, t[".name"], "node")
end
end)
uci:foreach(appname, "nodes", function(t)
uci:foreach(c_config, "nodes", function(t)
if t["preproxy_node"] == w then
uci:delete(appname, t[".name"], "preproxy_node")
uci:delete(appname, t[".name"], "chain_proxy")
uci:delete(c_config, t[".name"], "preproxy_node")
uci:delete(c_config, t[".name"], "chain_proxy")
end
if t["to_node"] == w then
uci:delete(appname, t[".name"], "to_node")
uci:delete(appname, t[".name"], "chain_proxy")
uci:delete(c_config, t[".name"], "to_node")
uci:delete(c_config, t[".name"], "chain_proxy")
end
local list_name = t["urltest_node"] and "urltest_node" or (t["balancing_node"] and "balancing_node")
if list_name then
local nodes = uci:get_list(appname, t[".name"], list_name)
local nodes = uci:get_list(c_config, t[".name"], list_name)
if nodes then
local changed = false
local new_nodes = {}
@@ -575,48 +579,48 @@ function delete_select_nodes()
end
end
if changed then
uci:set_list(appname, t[".name"], list_name, new_nodes)
uci:set_list(c_config, t[".name"], list_name, new_nodes)
end
end
end
if t["fallback_node"] == w then
uci:delete(appname, t[".name"], "fallback_node")
uci:delete(c_config, t[".name"], "fallback_node")
end
end)
uci:foreach(appname, "subscribe_list", function(t)
uci:foreach(c_config, "subscribe_list", function(t)
if t["preproxy_node"] == w then
uci:delete(appname, t[".name"], "preproxy_node")
uci:delete(appname, t[".name"], "chain_proxy")
uci:delete(c_config, t[".name"], "preproxy_node")
uci:delete(c_config, t[".name"], "chain_proxy")
end
if t["to_node"] == w then
uci:delete(appname, t[".name"], "to_node")
uci:delete(appname, t[".name"], "chain_proxy")
uci:delete(c_config, t[".name"], "to_node")
uci:delete(c_config, t[".name"], "chain_proxy")
end
end)
if (uci:get(appname, w, "add_mode") or "0") == "2" then
local group = uci:get(appname, w, "group") or ""
if (uci:get(c_config, w, "add_mode") or "0") == "2" then
local group = uci:get(c_config, w, "group") or ""
if group ~= "" then
uci:foreach(appname, "subscribe_list", function(t)
uci:foreach(c_config, "subscribe_list", function(t)
if t["remark"] == group then
uci:delete(appname, t[".name"], "md5")
uci:delete(c_config, t[".name"], "md5")
end
end)
end
end
uci:delete(appname, w)
uci:delete(c_config, w)
end)
if redirect == "1" then
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http.redirect(api.url("node_list"))
else
api.uci_save(uci, appname, true, true)
api.uci_save(uci, c_config, true, true)
end
end
function get_node()
local id = http.formvalue("id")
local result = {}
local show_node_info = api.uci_get_type("global_other", "show_node_info", "0")
local show_node_info = uci:get(c_config, "@global_other[0]", "show_node_info") or "0"
local function add_is_ipv6_key(o)
if o and o.address and show_node_info == "1" then
@@ -629,12 +633,12 @@ function get_node()
end
if id then
result = uci:get_all(appname, id)
result = uci:get_all(c_config, id)
add_is_ipv6_key(result)
else
local default_nodes = {}
local other_nodes = {}
uci:foreach(appname, "nodes", function(t)
uci:foreach(c_config, "nodes", function(t)
add_is_ipv6_key(t)
if not t.group or t.group == "" then
default_nodes[#default_nodes + 1] = t
@@ -653,12 +657,12 @@ function reassign_group()
local group = http.formvalue("group") or "default"
for id in ids:gmatch("([^,]+)") do
if group ~="" and group ~= "default" then
api.sh_uci_set(appname, id, "group", group)
api.sh_uci_set(c_config, id, "group", group)
else
api.sh_uci_del(appname, id, "group")
api.sh_uci_del(c_config, id, "group")
end
end
api.sh_uci_commit(appname)
api.sh_uci_commit(c_config)
http_write_json({ status = "ok" })
end
@@ -666,7 +670,7 @@ function save_node_list_opt()
local option = http.formvalue("option") or ""
local value = http.formvalue("value") or ""
if option ~= "" then
api.sh_uci_set(appname, "@global_other[0]", option, value, true)
api.sh_uci_set(c_config, "@global_other[0]", option, value, true)
end
http_write_json({ status = "ok" })
end
@@ -688,7 +692,7 @@ function rollback_rules()
return
end
local bak_dir = "/tmp/bak_v2ray/"
local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/")
local geo_dir = (uci:get(c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/")
fs.move(bak_dir .. arg_type .. ".dat", geo_dir .. arg_type .. ".dat")
fs.rmdir(bak_dir)
http_write_json_ok()
@@ -701,9 +705,9 @@ function server_update_config()
local data_t = jsonParse(data) or {}
if next(data_t) then
for k, v in pairs(data_t) do
uci:set(appname .. "_server", id, k, v)
uci:set(c_config .. "_server", id, k, v)
end
api.uci_save(uci, appname .. "_server")
api.uci_save(uci, c_config .. "_server")
http_write_json_ok()
return
end
@@ -814,7 +818,7 @@ function restore_backup()
fp:write(decoded)
fp:close()
if chunk_index + 1 == total_chunks then
uci:revert(appname)
uci:revert(c_config)
api.sys.call("echo '' > /tmp/log/passwall2.log")
api.log(0, string.format(" * PassWall2 %s", i18n.translate("Configuration file uploaded successfully…")))
local temp_dir = '/tmp/passwall2_bak'
@@ -857,7 +861,7 @@ function geo_view()
end
local function get_rules(str, type)
local rules_id = {}
uci:foreach(appname, "shunt_rules", function(s)
uci:foreach(c_config, "shunt_rules", function(s)
local list
if type == "geoip" then list = s.ip_list else list = s.domain_list end
for line in string.gmatch((list or ""), "[^\r\n]+") do
@@ -874,7 +878,7 @@ function geo_view()
end)
return rules_id
end
local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
local geo_dir = (uci:get(c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
local geosite_path = geo_dir .. "/geosite.dat"
local geoip_path = geo_dir .. "/geoip.dat"
local geo_type, file_path, cmd
@@ -946,13 +950,13 @@ function subscribe_manual()
http_write_json({ success = false, msg = "Missing section or URL, skip." })
return
end
local uci_url = api.sh_uci_get(appname, section, "url")
local uci_url = api.sh_uci_get(c_config, section, "url")
if not uci_url or uci_url == "" then
http_write_json({ success = false, msg = i18n.translate("Please save and apply before manually subscribing.") })
return
end
if uci_url ~= current_url then
api.sh_uci_set(appname, section, "url", current_url, true)
api.sh_uci_set(c_config, section, "url", current_url, true)
end
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start " .. section .. " manual >/dev/null 2>&1 &")
http_write_json({ success = true, msg = "Subscribe triggered." })
@@ -969,7 +973,7 @@ function subscribe_manual_all()
local url_list = util.split(urls, ",")
-- Check if there are any unsaved configurations.
for i, section in ipairs(section_list) do
local uci_url = api.sh_uci_get(appname, section, "url")
local uci_url = api.sh_uci_get(c_config, section, "url")
if not uci_url or uci_url == "" then
http_write_json({ success = false, msg = i18n.translate("Please save and apply before manually subscribing.") })
return
@@ -978,9 +982,9 @@ function subscribe_manual_all()
-- Save URLs that have changed.
for i, section in ipairs(section_list) do
local current_url = url_list[i] or ""
local uci_url = api.sh_uci_get(appname, section, "url")
local uci_url = api.sh_uci_get(c_config, section, "url")
if current_url ~= "" and uci_url ~= current_url then
api.sh_uci_set(appname, section, "url", current_url, true)
api.sh_uci_set(c_config, section, "url", current_url, true)
end
end
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start all manual >/dev/null 2>&1 &")
@@ -991,10 +995,10 @@ function flush_set()
local redirect = http.formvalue("redirect") or "0"
local reload = http.formvalue("reload") or "0"
if reload == "1" then
uci:set(appname, '@global[0]', "flush_set", "1")
api.uci_save(uci, appname, true, true)
uci:set(c_config, '@global[0]', "flush_set", "1")
api.uci_save(uci, c_config, true, true)
else
api.sh_uci_set(appname, "@global[0]", "flush_set", "1", true)
api.sh_uci_set(c_config, "@global[0]", "flush_set", "1", true)
end
if redirect == "1" then
http.redirect(api.url("log"))
@@ -1003,9 +1007,9 @@ end
function fetch_certsha256()
local id = http.formvalue("id") or ""
local address = (id ~= "") and uci:get(appname, id, "address") or ""
local port = (id ~= "") and uci:get(appname, id, "port") or 0
local sni = (id ~= "") and uci:get(appname, id, "tls_serverName") or ""
local address = (id ~= "") and uci:get(c_config, id, "address") or ""
local port = (id ~= "") and uci:get(c_config, id, "port") or 0
local sni = (id ~= "") and uci:get(c_config, id, "tls_serverName") or ""
sni = (sni ~= "") and sni or address
if address == "" or port == 0 then
http_write_json_error()
@@ -1020,11 +1024,11 @@ function get_shunt_rules()
local result = {}
if id then
result = uci:get_all(appname, id)
result = uci:get_all(c_config, id)
else
local default_items = {}
local other_items = {}
uci:foreach(appname, "shunt_rules", function(t)
uci:foreach(c_config, "shunt_rules", function(t)
if not t.group or t.group == "" then
default_items[#default_items + 1] = t
else
@@ -1043,7 +1047,7 @@ function add_shunt_rule()
local uid = add_name
if add_name then
local has = uci:get(appname, uid)
local has = uci:get(c_config, uid)
if has then
http_write_json_error({ message = i18n.translate("This ID already exists.") })
return
@@ -1051,18 +1055,18 @@ function add_shunt_rule()
else
uid = api.gen_random_char()
end
uci:section(appname, "shunt_rules", uid)
uci:section(c_config, "shunt_rules", uid)
local group = http.formvalue("group")
if group and group ~= "default" then
uci:set(appname, uid, "group", group)
uci:set(c_config, uid, "group", group)
end
if redirect == "1" then
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http.redirect(api.url("shunt_rules", uid))
else
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http_write_json_ok({uid = uid, redirect_url = api.url("shunt_rules", uid)})
end
end
@@ -1071,17 +1075,17 @@ function delete_select_shunt_rules()
local ids = http.formvalue("ids")
local redirect = http.formvalue("redirect")
string.gsub(ids, '[^' .. "," .. ']+', function(w)
uci:foreach(appname, "nodes", function(s)
uci:foreach(c_config, "nodes", function(s)
if s["protocol"] and s["protocol"] == "_shunt" then
uci:delete(appname, s[".name"], w)
uci:delete(c_config, s[".name"], w)
end
end)
uci:delete(appname, w)
uci:delete(c_config, w)
end)
if redirect == "1" then
api.uci_save(uci, appname)
api.uci_save(uci, c_config)
http.redirect(api.url("rule"))
else
api.uci_save(uci, appname, true, true)
api.uci_save(uci, c_config, true, true)
end
end
@@ -1,22 +1,16 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local sys = api.sys
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
s = m:section(TypedSection, "global", translate("ACLs"), "<font color='red'>" .. translate("ACLs is a tools which used to designate specific IP proxy mode.") .. "</font>")
s.anonymous = true
s = m:section(NamedSection, "@global[0]", "global", translate("ACLs"), "<font color='red'>" .. translate("ACLs is a tools which used to designate specific IP proxy mode.") .. "</font>")
o = s:option(Flag, "acl_enable", translate("Main switch"))
o.rmempty = false
o.default = false
-- [[ ACLs Settings ]]--
local cfgname = "acl_rule"
s = m:section(TypedSection, cfgname)
s = m:section(TypedSection, "acl_rule")
s.template = "cbi/tblsection"
s.sortable = true
s.anonymous = true
@@ -38,7 +32,7 @@ o = s:option(Value, "remarks", translate("Remarks"))
o.rmempty = true
local mac_t = {}
sys.net.mac_hints(function(e, t)
api.sys.net.mac_hints(function(e, t)
mac_t[e] = {
ip = t,
mac = e
@@ -81,9 +75,6 @@ i.cfgvalue = function(t, n)
return translate("No Proxy")
end
local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api
sortable.target_cfgname = cfgname
m:append(sortable)
m:appendTemplate("/cbi/sortable", {sectiontype = s.sectiontype})
return api.return_map(m)
@@ -1,18 +1,13 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(api.url("acl"))
end
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
local sys = api.sys
m:appendTemplate("/cbi/nodes_listvalue_com")
local port_validate = function(self, value, t)
return value:gsub("-", ":")
@@ -44,6 +39,7 @@ local doh_validate = function(self, value, t)
end
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
end
-- [[ ACLs Settings ]]--
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
s.addremove = false
@@ -73,7 +69,7 @@ o.validate = function(self, value, section)
end
local mac_t = {}
sys.net.mac_hints(function(e, t)
api.sys.net.mac_hints(function(e, t)
mac_t[#mac_t + 1] = {
ip = t,
mac = e
@@ -181,7 +177,7 @@ o:depends("mode", "1")
o.validate = port_validate
o = s:option(DummyValue, "_hide_node_option", "")
o.template = "passwall2/cbi/hidevalue"
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends("mode", "0")
o:depends({ tcp_no_redir_ports = "1:65535", udp_no_redir_ports = "1:65535" })
@@ -199,13 +195,13 @@ else
o.group = {}
end
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o.template = appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
current_node_id = o:formvalue(arg[1])
if not current_node_id then
current_node_id = m.uci:get(appname, arg[1], "node")
current_node_id = m:get(arg[1], "node")
end
current_node = current_node_id and m.uci:get_all(appname, current_node_id) or {}
current_node = current_node_id and m:get(current_node_id) or {}
o = s:option(Flag, "log", translate("Enable Node Log"))
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
@@ -259,7 +255,7 @@ end
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o = s:option(DummyValue, "_hide_dns_option", "")
o.template = "passwall2/cbi/hidevalue"
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ node = "" })
if GLOBAL_ENABLED == "1" and NODE then
@@ -1,21 +1,14 @@
local api = require "luci.passwall2.api"
local com = require "luci.passwall2.com"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
local com = require "luci.passwall2.com"
m = Map()
-- [[ App Settings ]]--
s = m:section(TypedSection, "global_app", translate("App Update"))
s.anonymous = true
s = m:section(NamedSection, "@global_app[0]", "global_app", translate("App Update"))
local app_version = Template(appname .. "/app_update/app_version")
app_version.api = api
app_version.config = m.config
app_version.com = com
s:append(app_version)
s:appendTemplate("/app_update/app_version", {com = com})
local k, v
for k, v in pairs(com) do
@@ -1,16 +1,18 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local fs = api.fs
local uci = api.uci
local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
local geo_dir = (uci:get(api.c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
local geosite_path = geo_dir .. "/geosite.dat"
local geoip_path = geo_dir .. "/geoip.dat"
if fs.access(geosite_path) and fs.access(geoip_path) then
f = SimpleForm(appname)
f = SimpleForm(api.c_config)
f.reset = false
f.submit = false
f:append(Template(appname .. "/rule/geoview"))
local obj = Template(api.appname .. "/rule/geoview")
obj.api = api
f:append(obj)
end
return f
return f
@@ -1,15 +1,12 @@
api = require "luci.passwall2.api"
appname = api.appname
datatypes = api.datatypes
has_singbox = api.finded_com("sing-box")
has_xray = api.finded_com("xray")
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
m:appendTemplate("/cbi/nodes_listvalue_com")
nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
@@ -40,7 +37,7 @@ for k, v in pairs(nodes_table) do
end
local socks_list = {}
m.uci:foreach(appname, "socks", function(s)
m:foreach("socks", function(s)
if s.enabled == "1" and s.node then
socks_list[#socks_list + 1] = {
id = s[".name"],
@@ -72,13 +69,9 @@ local doh_validate = function(self, value, t)
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
end
m:append(Template(appname .. "/global/status"))
m:appendTemplate("/global/status")
global_cfgid = (m:get("@global[0]") or {})[".name"] or ""
s = m:section(TypedSection, "global")
s.anonymous = true
s.addremove = false
s = m:section(NamedSection, "@global[0]", "global")
s:tab("Main", translate("Main"))
@@ -88,12 +81,12 @@ o.rmempty = false
---- Node
o = s:taboption("Main", ListValue, "node", "<a style='color: red'>" .. translate("Node") .. "</a>")
o.template = appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
o:value("", translate("Close"))
o.group = {""}
current_node_id = m.uci:get(appname, global_cfgid, "node")
current_node = current_node_id and m.uci:get_all(appname, current_node_id) or {}
current_node_id = m:get(s.section, "node")
current_node = current_node_id and m:get(current_node_id) or {}
-- Shunt Start
if (has_singbox or has_xray) and #nodes_table > 0 then
@@ -101,7 +94,7 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
if current_node.protocol == "_shunt" then
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
s_cfgid = s:cfgsections()[1],
s_cfgid = s.section,
node_id = current_node_id,
node = current_node,
socks_list = socks_list,
@@ -245,7 +238,7 @@ o = s:taboption("DNS", TextValue, "dns_hosts", translate("Domain Override"))
o.rows = 5
o.wrap = "off"
o.remove = function(self, section)
local node_value = s.fields["node"]:formvalue(global_cfgid)
local node_value = s.fields["node"]:formvalue(section)
if node_value then
local node_t = m:get(node_value) or {}
if node_t.type == "Xray" or node_t.type == "sing-box" then
@@ -297,11 +290,11 @@ o:depends("log_node", "1")
s:tab("faq", "FAQ")
o = s:taboption("faq", DummyValue, "")
o.template = appname .. "/global/faq"
o.template = m:template_path("/global/faq")
s:tab("maintain", translate("Maintain"))
o = s:taboption("maintain", DummyValue, "")
o.template = appname .. "/global/backup"
o.template = m:template_path("/global/backup")
-- [[ Socks Server ]]--
o = s:taboption("Main", Flag, "socks_enabled", "Socks " .. translate("Main switch"))
@@ -330,7 +323,7 @@ o.default = 1
o.rmempty = false
o = s2:option(ListValue, "node", translate("Socks Node"))
o.template = appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
o.group = {}
o = s2:option(DummyValue, "now_node", translate("Current Node"))
@@ -346,7 +339,7 @@ o.cfgvalue = function(_, n)
end
local n = 1
m.uci:foreach(appname, "socks", function(s)
m:foreach("socks", function(s)
if s[".name"] == section then
return false
end
@@ -382,12 +375,7 @@ for k, v in pairs(nodes_table) do
end
end
local footer = Template(appname .. "/global/footer")
footer.api = api
footer.global_cfgid = global_cfgid
footer.shunt_list = api.jsonc.stringify(shunt_list)
m:append(footer)
m:append(Template(appname .. "/global/status_bottom"))
m:appendTemplate("/global/footer", {shunt_list = api.jsonc.stringify(shunt_list)})
m:appendTemplate(Template("/global/status_bottom"))
return api.return_map(m)
@@ -1,7 +1,6 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local datatypes = api.datatypes
local net = require "luci.model.network".init()
api.set_default_cbi()
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
@@ -15,18 +14,14 @@ for k, e in ipairs(api.get_valid_nodes()) do
end
end
api.set_default_cbi()
m = Map()
m = Map(appname)
api.set_apply_on_parse(m)
m:append(Template(appname .. "/cbi/nodes_value_com"))
m:appendTemplate("/cbi/nodes_value_com")
-- [[ Haproxy Settings ]]--
s = m:section(TypedSection, "global_haproxy", translate("Basic Settings"))
s.anonymous = true
s = m:section(NamedSection, "@global_haproxy[0]", "global_haproxy", translate("Basic Settings"))
s:append(Template(appname .. "/haproxy/status"))
s:appendTemplate("/haproxy/status")
---- Balancing Enable
o = s:option(Flag, "balancing_enable", translate("Enable Load Balancing"))
@@ -69,9 +64,9 @@ o:depends("balancing_enable", true)
---- Health Check Type
o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
o.default = "passwall_logic"
o.default = "script_logic"
o:value("tcp", "TCP")
o:value("passwall_logic", translate("URL Test") .. string.format("(passwall %s)", translate("Inner implement")))
o:value("script_logic", translate("URL Test") .. string.format("(passwall2 %s)", translate("Inner implement")))
o:depends("balancing_enable", true)
---- Passwall Inner implement Probe URL
@@ -85,7 +80,7 @@ o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud
o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)")
o.default = o.keylist[3]
o.description = translate("The URL used to detect the connection status.")
o:depends("health_check_type", "passwall_logic")
o:depends("health_check_type", "script_logic")
---- Health Check Inter
o = s:option(Value, "health_check_inter", translate("Health Check Inter"))
@@ -99,11 +94,10 @@ o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<span style="color: red">%s</span>', translate("When the URL test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."))
end
o:depends("health_check_type", "passwall_logic")
o:depends("health_check_type", "script_logic")
-- [[ Balancing Settings ]]--
local cfgname = "haproxy_config"
s = m:section(TypedSection, cfgname, translate("Node List"))
s = m:section(TypedSection, "haproxy_config", translate("Node List"))
s.description = "<font color='red'>" ..
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") .. "<br>" ..
translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") .. "</font>"
@@ -132,7 +126,7 @@ o.rmempty = false
---- Node Address
o = s:option(Value, "lbss", translate("Node Address"))
o.template = appname .. "/cbi/nodes_value"
o.template = m:template_path("/cbi/nodes_value")
o.group = {}
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
@@ -180,11 +174,8 @@ o:value(0, translate("Primary"))
o:value(1, translate("Standby"))
o.rmempty = false
local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api
sortable.target_cfgname = cfgname
m:append(sortable)
m:appendTemplate("/cbi/sortable", {sectiontype = s.sectiontype})
m:append(Template(appname .. "/haproxy/js"))
m:appendTemplate("/haproxy/js")
return api.return_map(m)
@@ -9,7 +9,7 @@ local current_node_id = data.node_id
local node_list = data.node_list or api.get_node_list()
local groups = {}
m.uci:foreach(appname, "shunt_rules", function(s)
m:foreach("shunt_rules", function(s)
if s.group and s.group ~= "" then
groups[s.group] = true
end
@@ -123,7 +123,7 @@ end
local shunt_group_val = m:get(current_node_id, "shunt_group") or ""
shunt_group_val = shunt_group_val:lower()
local shunt_rules = {}
m.uci:foreach(appname, "shunt_rules", function(e)
m:foreach("shunt_rules", function(e)
local group = e.group or ""
group = group:lower()
if group == shunt_group_val then
@@ -146,7 +146,7 @@ table.insert(shunt_rules, {
})
s2 = m:section(Table, shunt_rules, " ")
s2.config = appname
s2.config = m.config
s2.sectiontype = "shunt_option_list"
o = s2:option(DummyValue, "remarks", translate("Rule"))
@@ -160,7 +160,7 @@ o.cfgvalue = function(self, section)
end
_node = s2:option(Value, "_node", translate("Node"))
_node.template = appname .. "/cbi/nodes_listvalue"
_node.template = m:template_path("/cbi/nodes_listvalue")
_node.group = {"","","",""}
_node:value("", translate("Close (Not use)"))
_node:value("_default", translate("Use default node"))
@@ -192,7 +192,7 @@ end
proxy_tag_node = s2:option(ListValue, "_proxy_tag", string.format('<a style="color:red" title="%s">%s</a>',
translate("Set the node to be used as a pre-proxy.") .. "\n" .. translate("Each rule has a separate switch that controls whether this rule uses the pre-proxy or not."),
translate("Preproxy")))
proxy_tag_node.template = appname .. "/cbi/nodes_listvalue"
proxy_tag_node.template = m:template_path("/cbi/nodes_listvalue")
proxy_tag_node.group = {""}
proxy_tag_node:value("", translate("Close (Not use)"))
proxy_tag_node.cfgvalue = function(self, section)
@@ -217,10 +217,4 @@ for k1, v1 in pairs(node_list) do
end
end
local footer = Template(appname .. "/include/shunt_options")
footer.api = api
footer.config = m.config
footer.id = current_node_id
footer.s_cfgid = s_cfgid or current_node_id
footer.normal_list = api.jsonc.stringify(node_list.normal_list)
m:append(footer)
m:appendTemplate("/include/shunt_options", {id = current_node_id, s_cfgid = s_cfgid or current_node_id, normal_list = api.jsonc.stringify(node_list.normal_list)})
@@ -1,30 +1,22 @@
api = require "luci.passwall2.api"
appname = api.appname
api.set_default_cbi()
m = Map(appname, translate("Node Config"))
m = Map()
m.redirect = api.url()
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(api.url("node_list"))
end
fs = require "nixio.fs"
formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
formvalue_key = "cbid." .. m.config .. "." .. arg[1] .. "."
local header = Template(appname .. "/node_config/header")
header.api = api
header.config = m.config
header.section = arg[1]
m:append(header)
m:append(Template(appname .. "/cbi/nodes_multivalue_com"))
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
m:appendTemplate("/node_config/header", {section = arg[1]})
m:appendTemplate("/cbi/nodes_multivalue_com")
m:appendTemplate("/cbi/nodes_listvalue_com")
groups = {}
m.uci:foreach(appname, "nodes", function(s)
m:foreach("nodes", function(s)
if s[".name"] ~= arg[1] then
if s.group and s.group ~= "" then
groups[s.group] = true
@@ -32,13 +24,13 @@ m.uci:foreach(appname, "nodes", function(s)
end
end)
s = m:section(NamedSection, arg[1], "nodes", "")
s = m:section(NamedSection, arg[1], "nodes", translate("Node Config"))
s.addremove = false
s.dynamic = false
o = s:option(DummyValue, "passwall2", " ")
o.rawhtml = true
o.template = "passwall2/node_config/link_share_man"
o.template = m:template_path("/node_config/link_share_man")
o.value = arg[1]
o = s:option(Value, "remarks", translate("Node Remarks"))
@@ -67,10 +59,10 @@ o.write = function(self, section, value)
m:set(section, self.option, value)
end
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall2/client/type/"
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. api.appname .. "/client/type/"
s.val = {}
s.val["type"] = m.uci:get(appname, arg[1], "type")
s.val["protocol"] = m.uci:get(appname, arg[1], "protocol")
s.val["type"] = m:get(arg[1], "type")
s.val["protocol"] = m:get(arg[1], "protocol")
if luci.http.formvalue("cbi.submit") == "1" then
local formvalue_type = luci.http.formvalue(formvalue_key .. "type")
@@ -92,10 +84,6 @@ for index, value in ipairs(type_table) do
setfenv(p_func, getfenv(1))(m, s)
end
local footer = Template(appname .. "/node_config/footer")
footer.api = api
footer.config = m.config
footer.section = arg[1]
m:append(footer)
m:appendTemplate("/node_config/footer", {section = arg[1]})
return api.return_map(m)
@@ -1,14 +1,10 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
-- [[ Other Settings ]]--
s = m:section(TypedSection, "global_other")
s.anonymous = true
s = m:section(NamedSection, "@global_other[0]", "global_other")
o = s:option(ListValue, "auto_detection_time", translate("Automatic detection delay"))
o:value("0", translate("Close"))
@@ -29,10 +25,7 @@ o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)")
o.default = o.keylist[3]
if true then
local o = Template(appname .. "/node_list/node_list")
o.map = m
o.api = api
m:append(o)
m:appendTemplate("/node_list/node_list")
if luci.http.formvalue("cbi.submit") == "1" then
local group_order = {}
@@ -45,7 +38,7 @@ if true then
new_order[#new_order + 1] = w
end)
for idx, name in ipairs(new_order) do
m.uci:reorder(appname, name, idx - 1)
m.uci:reorder(m.config, name, idx - 1)
end
end
end
@@ -1,6 +1,6 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local uci = api.uci
api.set_default_cbi()
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
@@ -38,20 +38,16 @@ if has_hysteria2 then
table.insert(hysteria2_type, s)
end
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
function m.on_before_save(self)
self.uci:foreach(appname, "subscribe_list", function(e)
self:foreach("subscribe_list", function(e)
self:del(e[".name"], "md5")
end)
end
-- [[ Subscribe Settings ]]--
s = m:section(TypedSection, "global_subscribe", "")
s.anonymous = true
s = m:section(NamedSection, "@global_subscribe[0]", "global_subscribe")
o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode"))
o:value("0", translate("Close"))
@@ -126,8 +122,7 @@ o.cfgvalue = function(self, section)
translate("Manual subscription All"))
end
local cfgname = "subscribe_list"
s = m:section(TypedSection, cfgname, "", "<font color='red'>" .. translate("When adding a new subscription, please save and apply before manually subscribing. If you only change the subscription URL, you can subscribe manually, and the system will save it automatically.") .. "</font>")
s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("When adding a new subscription, please save and apply before manually subscribing. If you only change the subscription URL, you can subscribe manually, and the system will save it automatically.") .. "</font>")
s.addremove = true
s.anonymous = true
s.sortable = true
@@ -150,7 +145,7 @@ o.validate = function(self, value, section)
return nil, translate("Remark cannot be empty.")
end
local duplicate = false
m.uci:foreach(appname, cfgname, function(e)
m:foreach(s.sectiontype, function(e)
if e[".name"] ~= section and e["remark"] and e["remark"]:lower() == value:lower() then
duplicate = true
return false
@@ -164,9 +159,9 @@ end
o.write = function(self, section, value)
local old = m:get(section, self.option) or ""
if old ~= value then
m.uci:foreach(appname, "nodes", function(e)
m:foreach("nodes", function(e)
if e["group"] and e["group"]:lower() == old:lower() then
m.uci:set(appname, e[".name"], "group", value)
m:set(e[".name"], "group", value)
end
if e["protocol"] and (e["protocol"] == "_balancing" or e["protocol"] == "_urltest") and e["node_group"] then
local gs = ""
@@ -178,7 +173,7 @@ o.write = function(self, section, value)
end
end
gs = api.trim(gs)
m.uci:set(appname, e[".name"], "node_group", gs)
m:set(e[".name"], "node_group", gs)
end
end)
end
@@ -196,7 +191,7 @@ o.cfgvalue = function(t, n)
end
str = str ~= "" and "<br>" .. str or ""
local num = 0
m.uci:foreach(appname, "nodes", function(s)
m:foreach("nodes", function(s)
if s["group"] and s["group"]:lower() == remark:lower() then
num = num + 1
end
@@ -225,11 +220,8 @@ o.cfgvalue = function(self, section)
section, translate("Manual subscription"))
end
local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api
sortable.target_cfgname = cfgname
m:append(sortable)
m:appendTemplate("/cbi/sortable", {sectiontype = s.sectiontype})
m:append(Template(appname .. "/node_subscribe/js"))
m:appendTemplate("/node_subscribe/js")
return api.return_map(m)
@@ -1,11 +1,8 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
m = Map()
m.redirect = api.url("node_subscribe")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
@@ -15,7 +12,7 @@ function m.on_before_save(self)
self:del(arg[1], "md5")
end
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
m:appendTemplate("/cbi/nodes_listvalue_com")
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
@@ -79,7 +76,7 @@ o.validate = function(self, value, section)
return nil, translate("Remark cannot be empty.")
end
local duplicate = false
m.uci:foreach(appname, "subscribe_list", function(e)
m:foreach("subscribe_list", function(e)
if e[".name"] ~= section and e["remark"] and e["remark"]:lower() == value:lower() then
duplicate = true
return false
@@ -93,9 +90,9 @@ end
o.write = function(self, section, value)
local old = m:get(section, self.option) or ""
if old ~= value then
m.uci:foreach(appname, "nodes", function(e)
m:foreach("nodes", function(e)
if e["group"] and e["group"]:lower() == old:lower() then
m.uci:set(appname, e[".name"], "group", value)
self:set(e[".name"], "group", value)
end
if e["protocol"] and (e["protocol"] == "_balancing" or e["protocol"] == "_urltest") and e["node_group"] then
local gs = ""
@@ -107,7 +104,7 @@ o.write = function(self, section, value)
end
end
gs = api.trim(gs)
m.uci:set(appname, e[".name"], "node_group", gs)
self:set(e[".name"], "node_group", gs)
end
end)
end
@@ -298,13 +295,13 @@ descrStr = translate(descrStr) .. "<br>" .. translate("Only support a layer of p
o1 = s:option(ListValue, "preproxy_node", translate("Preproxy Node"))
o1:depends({ ["chain_proxy"] = "1" })
o1.description = descrStr
o1.template = appname .. "/cbi/nodes_listvalue"
o1.template = m:template_path("/cbi/nodes_listvalue")
o1.group = {}
o2 = s:option(ListValue, "to_node", translate("Landing Node"))
o2:depends({ ["chain_proxy"] = "2" })
o2.description = descrStr
o2.template = appname .. "/cbi/nodes_listvalue"
o2.template = m:template_path("/cbi/nodes_listvalue")
o2.group = {}
o3 = s:option(Value, "outbound_iface", translate("Outbound Interface"))
@@ -1,5 +1,6 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
local fs = api.fs
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
@@ -8,15 +9,10 @@ local port_validate = function(self, value, t)
return value:gsub("-", ":")
end
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
-- [[ Delay Settings ]]--
s = m:section(TypedSection, "global_delay", translate("Delay Settings"))
s.anonymous = true
s.addremove = false
s = m:section(NamedSection, "@global_delay[0]", "global_delay", translate("Delay Settings"))
---- Open and close Daemon
o = s:option(Flag, "start_daemon", translate("Open and close Daemon"))
@@ -72,9 +68,7 @@ for index, value in ipairs({"stop", "start", "restart"}) do
end
-- [[ Forwarding Settings ]]--
s = m:section(TypedSection, "global_forwarding", translate("Forwarding Settings"))
s.anonymous = true
s.addremove = false
s = m:section(NamedSection, "@global_forwarding[0]", "global_forwarding", translate("Forwarding Settings"))
---- TCP No Redir Ports
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
@@ -205,9 +199,7 @@ o.validate = function(self, value)
end
if has_xray then
s_xray = m:section(TypedSection, "global_xray", "Xray " .. translate("Settings"))
s_xray.anonymous = true
s_xray.addremove = false
s_xray = m:section(NamedSection, "@global_xray[0]", "global_xray", "Xray " .. translate("Settings"))
o = s_xray:option(Flag, "fragment", translate("Fragment"), translate("TCP fragments, which can deceive the censorship system in some cases, such as bypassing SNI blacklists."))
o.default = 0
@@ -245,7 +237,7 @@ if has_xray then
o.default = 0
o:depends("sniffing", true)
local domains_excluded = string.format("/usr/share/%s/domains_excluded", appname)
local domains_excluded = string.format("/usr/share/%s/domains_excluded", m.config)
o = s_xray:option(TextValue, "excluded_domains", translate("Excluded Domains"), translate("If the traffic sniffing result is in this list, the destination address will not be overridden."))
o.rows = 15
o.wrap = "off"
@@ -268,11 +260,14 @@ if has_xray then
end
s_xray_noise.remove = function(self, section)
for k, v in pairs(self.children) do
v.rmempty = true
v.validate = nil
local o = m:get(section) or {}
if o[".type"] == self.sectiontype then
for k, v in pairs(self.children) do
v.rmempty = true
v.validate = nil
end
TypedSection.remove(self, section)
end
TypedSection.remove(self, section)
end
o = s_xray_noise:option(Flag, "enabled", translate("Enable"))
@@ -296,9 +291,7 @@ if has_xray then
end
if has_singbox then
s = m:section(TypedSection, "global_singbox", "Sing-Box " .. translate("Settings"))
s.anonymous = true
s.addremove = false
s = m:section(NamedSection, "@global_singbox[0]", "global_singbox", "Sing-Box " .. translate("Settings"))
o = s:option(Flag, "record_fragment", "TLS Record " .. translate("Fragment"),
translate("Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first."))
@@ -1,14 +1,10 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
-- [[ Rule Settings ]]--
s = m:section(TypedSection, "global_rules", translate("Rule status"))
s.anonymous = true
s = m:section(NamedSection, "@global_rules[0]", "global_rules", translate("Rule status"))
o = s:option(Value, "geoip_url", translate("GeoIP Update URL"))
o:value("https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", translate("Loyalsoldier/geoip"))
@@ -86,12 +82,10 @@ for _, f in ipairs(flags) do
o.rmempty = false
end
s:append(Template(appname .. "/rule/rule_version"))
s:appendTemplate("/rule/rule_version")
if true then
local o = Template(appname .. "/rule/shunt_rule_list")
o.api = api
m:append(o)
m:appendTemplate("/rule/shunt_rule_list")
if luci.http.formvalue("cbi.submit") == "1" then
local group_order = luci.http.formvaluetable("group.order")
@@ -103,7 +97,7 @@ if true then
new_order[#new_order + 1] = w
end)
for idx, name in ipairs(new_order) do
m.uci:reorder(appname, name, idx - 1)
m.uci:reorder(m.config, name, idx - 1)
end
end
end
@@ -1,19 +1,17 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local datatypes = api.datatypes
api.set_default_cbi()
m = Map(appname, "Sing-Box/Xray " .. translate("Shunt Rule"))
local datatypes = api.datatypes
m = Map()
m.redirect = api.url("rule")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
function m.on_before_save(self)
m:set("@global[0]", "flush_set", "1")
self:set("@global[0]", "flush_set", "1")
end
-- Add inline CSS to map description
@@ -47,7 +45,7 @@ end
local remarks_lookup = {}
local groups = {}
m.uci:foreach(appname, "shunt_rules", function(s)
m:foreach("shunt_rules", function(s)
if s[".name"] ~= arg[1] then
if s.remarks then
remarks_lookup[s.remarks] = s[".name"]
@@ -58,7 +56,7 @@ m.uci:foreach(appname, "shunt_rules", function(s)
end
end)
s = m:section(NamedSection, arg[1], "shunt_rules", "")
s = m:section(NamedSection, arg[1], "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"))
s.addremove = false
s.dynamic = false
@@ -1,17 +1,14 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map(appname)
api.set_apply_on_parse(m)
m = Map()
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(api.url())
end
m:append(Template(appname .. "/cbi/nodes_dynamiclist_com"))
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
m:appendTemplate("/cbi/nodes_dynamiclist_com")
m:appendTemplate("/cbi/nodes_listvalue_com")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
@@ -49,14 +46,14 @@ socks_node = s:option(ListValue, "node", translate("Node"))
if auto_switch_tip then
socks_node.description = auto_switch_tip
end
socks_node.template = appname .. "/cbi/nodes_listvalue"
socks_node.template = m:template_path("/cbi/nodes_listvalue")
socks_node.group = {}
o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o.default = "0"
local n = 1
m.uci:foreach(appname, "socks", function(s)
m:foreach("socks", function(s)
if s[".name"] == section then
return false
end
@@ -90,7 +87,7 @@ o:value("batch", translate("Batch"))
o = s:option(DynamicList, "autoswitch_backup_node", translate("List of backup nodes"))
o:depends("backup_node_add_mode", "manual")
o.template = appname .. "/cbi/nodes_dynamiclist"
o.template = m:template_path("/cbi/nodes_dynamiclist")
o.group = {}
o.write = function(self, section, value)
local n = s.fields["node"]:formvalue(section)
@@ -116,7 +113,7 @@ o:depends("backup_node_add_mode", "batch")
o.widget = "checkbox"
o:value("default", translate("default"))
local groups = {}
m.uci:foreach(appname, "nodes", function(s)
m:foreach("nodes", function(s)
if s.group and s.group ~= "" then
groups[s.group] = true
end
@@ -164,7 +161,7 @@ o.default = o.keylist[3]
o:depends("enable_autoswitch", true)
o = s:option(DummyValue, "btn")
o.template = appname .. "/socks_auto_switch/btn"
o.template = m:template_path("/socks_auto_switch/btn")
o:depends("backup_node_add_mode", "manual")
return api.return_map(m)
@@ -105,7 +105,7 @@ if load_balancing_options then -- [[ Load balancing Start ]]
o = s:option(MultiValue, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://xtls.github.io/config/routing.html#balancerobject'>document</a>"))
o:depends({ [_n("node_add_mode")] = "manual" })
o.widget = "checkbox"
o.template = appname .. "/cbi/nodes_multivalue"
o.template = m:template_path("/cbi/nodes_multivalue")
o.group = {}
for k1, v1 in pairs(node_list) do
if k1 == "socks_list" or k1 == "normal_list" then
@@ -171,7 +171,7 @@ if load_balancing_options then -- [[ Load balancing Start ]]
o:value("", translate("Close(Not use)"))
o:value("_direct", translate("Direct Connection"))
o:depends({ [_n("protocol")] = "_balancing" })
o.template = appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
-- Maximum number of fallback nesting layers
local MAX_FALLBACK_DEPTH = 3
-- Check if a loop will form.
@@ -863,7 +863,7 @@ if not load_shunt_options then
o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy."))
o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false })
o1.template = appname .. "/cbi/nodes_listvalue"
o1.template = m:template_path("/cbi/nodes_listvalue")
o1.group = {}
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
@@ -875,7 +875,7 @@ if not load_shunt_options then
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false })
o2.template = appname .. "/cbi/nodes_listvalue"
o2.template = m:template_path("/cbi/nodes_listvalue")
o2.group = {}
for k1, v1 in pairs(node_list) do
@@ -898,7 +898,7 @@ end
api.luci_types(arg[1], m, s, type_name, option_prefix)
if load_shunt_options then
local current_node = m.uci:get_all(appname, arg[1]) or {}
local current_node = m:get(arg[1]) or {}
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
node_id = arg[1],
@@ -107,7 +107,7 @@ if load_urltest_options then -- [[ URLTest Start ]]
o = s:option(MultiValue, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, <a target='_blank' href='https://sing-box.sagernet.org/configuration/outbound/urltest'>document</a>"))
o:depends({ [_n("node_add_mode")] = "manual" })
o.widget = "checkbox"
o.template = appname .. "/cbi/nodes_multivalue"
o.template = m:template_path("/cbi/nodes_multivalue")
o.group = {}
for k1, v1 in pairs(node_list) do
if k1 == "socks_list" or k1 == "normal_list" then
@@ -937,7 +937,7 @@ if not load_shunt_options then
o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy."))
o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false })
o1.template = appname .. "/cbi/nodes_listvalue"
o1.template = m:template_path("/cbi/nodes_listvalue")
o1.group = {}
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
@@ -949,7 +949,7 @@ if not load_shunt_options then
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false })
o2.template = appname .. "/cbi/nodes_listvalue"
o2.template = m:template_path("/cbi/nodes_listvalue")
o2.group = {}
for k1, v1 in pairs(node_list) do
@@ -972,7 +972,7 @@ end
api.luci_types(arg[1], m, s, type_name, option_prefix)
if load_shunt_options then
local current_node = m.uci:get_all(appname, arg[1]) or {}
local current_node = m:get(arg[1]) or {}
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
node_id = arg[1],
@@ -1,12 +1,9 @@
local api = require "luci.passwall2.api"
local appname = api.appname
api.set_default_cbi()
m = Map("passwall2_server", translate("Server-Side"))
api.set_apply_on_parse(m)
m = Map(api.s_config)
t = m:section(NamedSection, "global", "global")
t = m:section(NamedSection, "global", "global", translate("Server-Side"))
t.anonymous = true
t.addremove = false
@@ -88,17 +85,9 @@ e = s_server:option(Flag, "log", translate("Log"))
e.default = "1"
e.rmempty = false
local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api
sortable.appname = m.config
sortable.target_cfgname = s_server.sectiontype
m:append(sortable)
m:appendTemplate("/cbi/sortable", {sectiontype = s_server.sectiontype})
local server_list_status = Template(appname .. "/server/server_list_status")
server_list_status.api = api
server_list_status.appname = m.config
server_list_status.sectiontype = s_server.sectiontype
m:append(server_list_status)
m:appendTemplate("/server/server_list_status", {sectiontype = s_server.sectiontype})
s_user = m:section(TypedSection, "user", translate("Users Manager"))
s_user.anonymous = true
@@ -114,7 +103,7 @@ end
s_user.remove = function(self, section)
local o = m:get(section) or {}
if o[".type"] == self.sectiontype then
m.uci:foreach(m.config, "server", function(o)
m:foreach("server", function(o)
if o.user and section == o.user then
m:set(o[".name"], "user", "")
end
@@ -144,12 +133,8 @@ e.width = "25%"
e = s_user:option(DummyValue, "uuid", "UUID")
e.width = "25%"
local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api
sortable.appname = m.config
sortable.target_cfgname = s_user.sectiontype
m:append(sortable)
m:appendTemplate("/cbi/sortable", {sectiontype = s_user.sectiontype})
m:append(Template(appname .. "/server/log"))
m:appendTemplate("/server/log")
return api.return_map(m)
@@ -1,35 +1,27 @@
api = require "luci.passwall2.api"
appname = api.appname
fs = api.fs
api.set_default_cbi()
m = Map("passwall2_server", translate("Server Config"))
m = Map(api.s_config)
m.redirect = api.url("server")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
local header = Template(appname .. "/server/config_header")
header.api = api
header.config = m.config
header.section = arg[1]
m:append(header)
m:appendTemplate("/server/config_header", {section = arg[1]})
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
m:appendTemplate("/cbi/nodes_listvalue_com")
user_list = {}
m.uci:foreach(m.config, "user", function(s)
m:foreach("user", function(s)
user_list[#user_list + 1] = s
end)
s = m:section(NamedSection, arg[1], "server", "")
s = m:section(NamedSection, arg[1], "server", translate("Server Config"))
s.addremove = false
s.dynamic = false
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. appname .. "/server/type/"
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. api.appname .. "/server/type/"
s.val = m:get(arg[1]) or {}
o = s:option(Flag, "enable", translate("Enable"))
@@ -43,7 +35,7 @@ o.rmempty = false
o = s:option(ListValue, "type", translate("Type"))
local type_table = {}
for filename in fs.dir(types_dir) do
for filename in api.fs.dir(types_dir) do
table.insert(type_table, filename)
end
table.sort(type_table, function(a, b)
@@ -55,10 +47,6 @@ for index, value in ipairs(type_table) do
setfenv(p_func, getfenv(1))(m, s)
end
local footer = Template(appname .. "/server/config_footer")
footer.api = api
footer.config = m.config
footer.section = arg[1]
m:append(footer)
m:appendTemplate("/server/config_footer", {section = arg[1]})
return api.return_map(m)
@@ -446,7 +446,7 @@ o:value("", translate("Close"))
o:value("_socks", translate("Custom Socks"))
o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface"))
o.template = api.appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
o.group = {"","","",""}
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
@@ -424,7 +424,7 @@ o:value("", translate("Close"))
o:value("_socks", translate("Custom Socks"))
o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface"))
o.template = api.appname .. "/cbi/nodes_listvalue"
o.template = m:template_path("/cbi/nodes_listvalue")
o.group = {"","","",""}
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
@@ -1,24 +1,33 @@
api = require "luci.passwall2.api"
appname = api.appname
fs = api.fs
api.set_default_cbi()
m = Map("passwall2_server", translate("User Config"))
m = Map(api.s_config)
m.redirect = api.url("server")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
s = m:section(NamedSection, arg[1], "user", "")
s = m:section(NamedSection, arg[1], "user", translate("User Config"))
s.addremove = false
s.dynamic = false
o = s:option(Value, "username", translate("Username"))
o.datatype = "and(uciname,maxlength(24))"
o.rmempty = false
function o.validate(self, value, section)
local exists = false
m:foreach("user", function(s)
if s[".name"] ~= section and s.username == value then
exists = true
return false
end
end)
if exists then
return nil, translate("This username already exists.")
end
return value
end
o = s:option(Value, "password", translate("Password"))
o.rmempty = false
+99 -78
View File
@@ -1,5 +1,7 @@
module("luci.passwall2.api", package.seeall)
appname = "passwall2"
c_config = "passwall2"
s_config = "passwall2_server"
local com = require "luci.passwall2.com"
nixio = require "nixio"
fs = require "nixio.fs"
@@ -22,7 +24,7 @@ TMP_IFACE_PATH = TMP_PATH .. "/iface"
local lang = uci:get("luci", "main", "lang") or "auto"
if lang == "auto" then
local auto_lang = uci:get(appname, "@global[0]", "auto_lang")
local auto_lang = uci:get(c_config, "@global[0]", "auto_lang")
if auto_lang then lang = auto_lang end
end
if lang == "auto" then
@@ -234,7 +236,7 @@ function curl_direct(url, file, args)
end
function curl_auto(url, file, args)
local localhost_proxy = uci:get(appname, "@global[0]", "localhost_proxy") or "1"
local localhost_proxy = uci:get(c_config, "@global[0]", "localhost_proxy") or "1"
if localhost_proxy == "1" then
return curl_base(url, file, args)
else
@@ -493,7 +495,7 @@ function get_node_name(node_id)
if type(node_id) == "table" then
e = node_id
else
e = uci:get_all(appname, node_id)
e = uci:get_all(c_config, node_id)
end
if e then
if e.type and e.remarks then
@@ -509,11 +511,11 @@ function get_node_name(node_id)
end
function get_valid_nodes()
local show_node_info = uci_get_type("global_other", "show_node_info") or "0"
local show_node_info = uci:get(c_config, "@global_other[0]", "show_node_info") or "0"
local nodes = {}
local default_nodes = {}
local other_nodes = {}
uci:foreach(appname, "nodes", function(e)
uci:foreach(c_config, "nodes", function(e)
e.id = e[".name"]
if e.type and e.remarks then
local type_name = e.type
@@ -586,7 +588,7 @@ function get_node_list()
socks_list = {},
normal_list = {},
}
uci:foreach(appname, "socks", function(s)
uci:foreach(c_config, "socks", function(s)
if s.enabled == "1" and s.node then
node_list.socks_list[#node_list.socks_list + 1] = {
id = s[".name"],
@@ -685,22 +687,6 @@ function gen_random_char(length)
return sys.exec("echo -n $(head /dev/urandom | tr -dc A-Za-z0-9 | head -c %s)" % length)
end
function uci_get_type(type, config, default)
local value = uci:get_first(appname, type, config, default) or sys.exec("echo -n $(uci -q get " .. appname .. ".@" .. type .."[0]." .. config .. ")")
if (value == nil or value == "") and (default and default ~= "") then
value = default
end
return value
end
function uci_get_type_id(id, config, default)
local value = uci:get(appname, id, config, default) or sys.exec("echo -n $(uci -q get " .. appname .. "." .. id .. "." .. config .. ")")
if (value == nil or value == "") and (default and default ~= "") then
value = default
end
return value
end
function chmod_755(file)
if file and file ~= "" then
if not fs.access(file, "rwx", "rx", "rx") then
@@ -710,7 +696,7 @@ function chmod_755(file)
end
function get_customed_path(e)
return uci_get_type("global_app", e .. "_file")
return uci:get(c_config, "@global_app[0]", e .. "_file")
end
function finded_com(e)
@@ -769,7 +755,7 @@ end
function get_app_path(app_name)
if com[app_name] then
local def_path = com[app_name].default_path
local path = uci_get_type("global_app", app_name:gsub("%-","_") .. "_file")
local path = uci:get(c_config, "@global_app[0]", app_name:gsub("%-","_") .. "_file")
path = path and (#path>0 and path or def_path) or def_path
return path
end
@@ -1345,53 +1331,91 @@ function is_js_luci()
return sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0
end
function set_apply_on_parse(map)
if not map then
return
end
local lang = uci:get("luci", "main", "lang") or "auto"
if lang == "auto" then
local http = require "luci.http"
local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or ""
for lpat in aclang:gmatch("[%w-]+") do
lpat = lpat and lpat:gsub("-", "_")
if uci:get("luci", "languages", lpat) then
lang = lpat
break
end
lpat = lpat and lpat:lower()
if uci:get("luci", "languages", lpat) then
lang = lpat
break
end
end
if lang ~= "auto" then
sh_uci_set(appname, "@global[0]", "auto_lang", lang, true)
end
end
if is_js_luci() == true then
local hide_popup_box = nil
if hide_popup_box == true then
map.apply_on_parse = false
map.on_after_apply = function(self)
if self.redirect then
os.execute("sleep 1")
luci.http.redirect(self.redirect)
end
end
else
apply_redirect(map)
local old = map.on_after_save
map.on_after_save = function(self)
if old then old(self) end
map:set("@global[0]", "timestamp", os.time())
end
end
end
end
function set_default_cbi()
local cbi = require "luci.cbi"
if true then
--Map
local Map = cbi.Map
local original_init = Map.__init__
function Map.__init__(self, config, ...)
if not config then config = c_config end
original_init(self, config, ...)
self.api = require "luci.passwall2.api"
end
function Map.foreach(self, stype, func)
self.uci:foreach(self.config, stype, func)
end
function Map.template_path(self, template)
return appname .. template
end
function Map.appendTemplate(self, template, data)
local obj = cbi.Template(self:template_path(template))
obj.map = self
if data and next(data) then
for k, v in pairs(data) do
obj[k] = v
end
end
self:append(obj)
return obj
end
local lang = uci:get("luci", "main", "lang") or "auto"
if lang == "auto" then
local http = require "luci.http"
local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or ""
for lpat in aclang:gmatch("[%w-]+") do
lpat = lpat and lpat:gsub("-", "_")
if uci:get("luci", "languages", lpat) then
lang = lpat
break
end
lpat = lpat and lpat:lower()
if uci:get("luci", "languages", lpat) then
lang = lpat
break
end
end
if lang ~= "auto" then
sh_uci_set(c_config, "@global[0]", "auto_lang", lang, true)
end
end
if is_js_luci() == true then
local hide_popup_box = nil
if hide_popup_box == true then
Map.apply_on_parse = false
Map.on_after_apply = function(self)
if self.redirect then
os.execute("sleep 1")
luci.http.redirect(self.redirect)
end
end
else
apply_redirect(Map)
local old = Map.on_after_save
Map.on_after_save = function(self)
if old then old(self) end
self:set("@global[0]", "timestamp", os.time())
end
end
end
end
if true then
--AbstractSection
local AbstractSection = cbi.AbstractSection
function AbstractSection.appendTemplate(self, template, data)
local obj = cbi.Template(self.map:template_path(template))
obj.map = self.map
obj.section = self
if data and next(data) then
for k, v in pairs(data) do
obj[k] = v
end
end
self:append(obj)
return obj
end
end
if true then
--TextValue
local TextValue = cbi.TextValue
@@ -1428,18 +1452,15 @@ function return_map(map)
if true then
-- header
local header = cbi.Template(appname .. "/cbi/header")
header.api = api
header.config = map.config
header.map = map
table.insert(map.children, 1, header)
end
if true then
-- footer
local footer = cbi.Template(appname .. "/cbi/footer")
footer.api = api
footer.config = map.config
footer.map = map
map:append(footer)
end
return map
end
@@ -1570,7 +1591,7 @@ function format_go_time(input, default)
end
function apply_redirect(m)
local tmp_uci_file = "/etc/config/" .. appname .. "_redirect"
local tmp_uci_file = "/etc/config/" .. c_config .. "_redirect"
if m.redirect and m.redirect ~= "" then
if fs.access(tmp_uci_file) then
local redirect
@@ -1588,7 +1609,7 @@ function apply_redirect(m)
m.on_after_save = function(self)
local redirect = self.redirect
if redirect and redirect ~= "" then
uci:set(appname .. "_redirect", "@redirect[0]", "url", redirect)
uci:set(c_config .. "_redirect", "@redirect[0]", "url", redirect)
end
end
else
@@ -1693,7 +1714,7 @@ end
function get_socks_backup_nodes(id)
id = trim(id)
if id == "" then return "" end
local socks = uci:get_all(appname, id)
local socks = uci:get_all(c_config, id)
local nodes
if socks.backup_node_add_mode and socks.backup_node_add_mode == "batch" then
local node = {}
@@ -1714,7 +1735,7 @@ function get_socks_backup_nodes(id)
end
function get_core(field, candidates)
local v = uci:get(appname, "@global_subscribe[0]", field)
local v = uci:get(c_config, "@global_subscribe[0]", field)
if v and v ~= "" then
for _, c in ipairs(candidates) do
if c[2] == v and c[1] then
@@ -6,7 +6,7 @@ local sys = api.sys
local uci = api.uci
local jsonc = api.jsonc
local CONFIG = "passwall2_server"
local CONFIG = api.s_config
local CONFIG_PATH = "/tmp/etc/" .. CONFIG
local NFT_INCLUDE_FILE = CONFIG_PATH .. "/" .. CONFIG .. ".nft"
local LOG_APP_FILE = "/tmp/log/" .. CONFIG .. ".log"
@@ -9,7 +9,7 @@ function gen_config_server(node)
if node.users and #node.users > 0 then
users = {}
for i, v in ipairs(node.users) do
local user = uci:get_all("passwall2_server", v) or {}
local user = uci:get_all(api.s_config, v) or {}
if user[".type"] == "user" then
users[user.username] = user.password
end
@@ -74,7 +74,7 @@ function gen_config(var)
print("node Cannot be empty!")
return
end
local node = uci:get_all("passwall2", node_id)
local node = uci:get_all(api.c_config, node_id)
local local_socks_address = var["local_socks_address"] or "0.0.0.0"
local local_socks_port = var["local_socks_port"]
local local_socks_username = var["local_socks_username"]
@@ -9,7 +9,7 @@ function gen_config(var)
print("node Cannot be empty!")
return
end
local node = uci:get_all("passwall2", node_id)
local node = uci:get_all(api.c_config, node_id)
local run_type = var["run_type"]
local local_addr = var["local_addr"]
local local_port = var["local_port"]
@@ -6,7 +6,7 @@ local jsonc = api.jsonc
function gen_config_server(node)
local user = nil
if node.user then
user = uci:get_all("passwall2_server", node.user)
user = uci:get_all(api.s_config, node.user)
end
local config = {}
@@ -41,7 +41,7 @@ function gen_config(var)
print("node Cannot be empty!")
return
end
local node = uci:get_all("passwall2", node_id)
local node = uci:get_all(api.c_config, node_id)
local server_host = var["server_host"] or (node.address or ""):lower()
local server_port = var["server_port"] or node.port
local local_addr = var["local_addr"]
@@ -34,7 +34,7 @@ function check_geoview()
if GEO_VAR.OK == 0 then
api.log(0, "!!! Note: Geo rules cannot be used if the Geoview component is missing or the version is too low.")
else
GEO_VAR.DIR = GEO_VAR.DIR or (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
GEO_VAR.DIR = GEO_VAR.DIR or (uci:get(api.c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
GEO_VAR.SITE_PATH = GEO_VAR.SITE_PATH or (GEO_VAR.DIR .. "/geosite.dat")
GEO_VAR.IP_PATH = GEO_VAR.IP_PATH or (GEO_VAR.DIR .. "/geoip.dat")
if not fs.access(GEO_VAR.TO_SRS_PATH) then
@@ -794,7 +794,7 @@ function gen_config_server(node)
if node.users and #node.users > 0 then
users = {}
for i, v in ipairs(node.users) do
local user = uci:get_all("passwall2_server", v) or {}
local user = uci:get_all(api.s_config, v) or {}
if user[".type"] == "user" then
local u = {}
if node.protocol == "mixed" or node.protocol == "socks" or node.protocol == "http" or node.protocol == "naive" then
@@ -1030,7 +1030,7 @@ function gen_config_server(node)
}
sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.outbound_node_iface))
else
local outbound_node_t = uci:get_all("passwall2", node.outbound_node)
local outbound_node_t = uci:get_all(api.c_config, node.outbound_node)
if node.outbound_node == "_socks" or node.outbound_node == "_http" then
outbound_node_t = {
type = node.type,
@@ -1132,7 +1132,7 @@ function gen_config(var)
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
local singbox_settings = uci:get_all(appname, "@global_singbox[0]") or {}
local singbox_settings = uci:get_all(api.c_config, "@global_singbox[0]") or {}
local route = {
rules = {}
@@ -1195,7 +1195,7 @@ function gen_config(var)
local node = nil
if node_id then
node = uci:get_all(appname, node_id)
node = uci:get_all(api.c_config, node_id)
end
if local_socks_port then
@@ -1290,7 +1290,7 @@ function gen_config(var)
function get_node_by_id(node_id)
if not node_id or node_id == "" or node_id == "nil" then return nil end
local section = uci:get_all(appname, node_id) or {}
local section = uci:get_all(api.c_config, node_id) or {}
if section[".type"] == "socks" then
local result = {
[".name"] = node_id,
@@ -1569,7 +1569,7 @@ function gen_config(var)
end
--shunt rule
uci:foreach(appname, "shunt_rules", function(e)
uci:foreach(api.c_config, "shunt_rules", function(e)
if node["shunt_group"] ~= e.group then
return
end
@@ -1835,16 +1835,16 @@ function gen_config(var)
if dns_listen_port then
local dns_host = ""
if flag == "global" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
dns_host = uci:get(api.c_config, "@global[0]", "dns_hosts") or ""
else
flag = flag:gsub("acl_", "")
local dns_hosts_mode = uci:get(appname, flag, "dns_hosts_mode") or "default"
local dns_hosts_mode = uci:get(api.c_config, flag, "dns_hosts_mode") or "default"
if dns_hosts_mode == "default" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
dns_host = uci:get(api.c_config, "@global[0]", "dns_hosts") or ""
elseif dns_hosts_mode == "disable" then
dns_host = ""
elseif dns_hosts_mode == "custom" then
dns_host = uci:get(appname, flag, "dns_hosts") or ""
dns_host = uci:get(api.c_config, flag, "dns_hosts") or ""
end
end
if #dns_host > 0 then
@@ -501,7 +501,7 @@ function gen_config_server(node)
if node.users and #node.users > 0 then
users = {}
for i, v in ipairs(node.users) do
local user = uci:get_all("passwall2_server", v) or {}
local user = uci:get_all(api.s_config, v) or {}
if user[".type"] == "user" then
local u = {}
if node.protocol == "socks" or node.protocol == "http" then
@@ -633,7 +633,7 @@ function gen_config_server(node)
}
sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.outbound_node_iface))
else
local outbound_node_t = uci:get_all("passwall2", node.outbound_node)
local outbound_node_t = uci:get_all(api.c_config, node.outbound_node)
if node.outbound_node == "_socks" or node.outbound_node == "_http" then
outbound_node_t = {
type = node.type,
@@ -906,7 +906,7 @@ function gen_config(var)
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
local xray_settings = uci:get_all(appname, "@global_xray[0]") or {}
local xray_settings = uci:get_all(api.c_config, "@global_xray[0]") or {}
if xray_settings.fragment == "1" then
local lengths, delays = {}, {}
@@ -931,7 +931,7 @@ function gen_config(var)
if xray_settings.noise == "1" then
local noises = {}
uci:foreach(appname, "xray_noise_packets", function(n)
uci:foreach(api.c_config, "xray_noise_packets", function(n)
if n.enabled == "1" then
local noise = {
rand = (n.type == "rand" and n.packet) and (n.packet:find("-", 1, true) and n.packet or tonumber(n.packet)) or nil,
@@ -948,7 +948,7 @@ function gen_config(var)
} or nil
end
local node = node_id and uci:get_all(appname, node_id) or nil
local node = node_id and uci:get_all(api.c_config, node_id) or nil
local balancers = {}
local rules = {}
@@ -1000,7 +1000,7 @@ function gen_config(var)
function get_node_by_id(node_id)
if not node_id or node_id == "" or node_id == "nil" then return nil end
local section = uci:get_all(appname, node_id) or {}
local section = uci:get_all(api.c_config, node_id) or {}
if section[".type"] == "socks" then
local result = {
[".name"] = node_id,
@@ -1394,7 +1394,7 @@ function gen_config(var)
end
--shunt rule
uci:foreach(appname, "shunt_rules", function(e)
uci:foreach(api.c_config, "shunt_rules", function(e)
if node["shunt_group"] ~= e.group then
return
end
@@ -1590,16 +1590,16 @@ function gen_config(var)
local dns_host = ""
if flag == "global" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
dns_host = uci:get(api.c_config, "@global[0]", "dns_hosts") or ""
else
flag = flag:gsub("acl_", "")
local dns_hosts_mode = uci:get(appname, flag, "dns_hosts_mode") or "default"
local dns_hosts_mode = uci:get(api.c_config, flag, "dns_hosts_mode") or "default"
if dns_hosts_mode == "default" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
dns_host = uci:get(api.c_config, "@global[0]", "dns_hosts") or ""
elseif dns_hosts_mode == "disable" then
dns_host = ""
elseif dns_hosts_mode == "custom" then
dns_host = uci:get(appname, flag, "dns_hosts") or ""
dns_host = uci:get(api.c_config, flag, "dns_hosts") or ""
end
end
if #dns_host > 0 then
@@ -1977,7 +1977,7 @@ function gen_config(var)
if inbounds or outbounds then
local config = {
env = (function()
local asset_location = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
local asset_location = uci:get(api.c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
return { XRAY_LOCATION_ASSET = asset_location }
end)(),
log = {
@@ -1,6 +1,7 @@
<div id="app_version">
<%
local api = self.api
local map = self.map
local api = map.api
local com = self.com
-%>
@@ -1,3 +1,6 @@
<%
local map = self.map
-%>
<!-- map footer -->
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
@@ -1,11 +1,15 @@
<%
local map = self.map
local api = map.api
-%>
<!-- map header -->
<script src="<%=resource%>/view/<%=self.api.appname%>/cbi.js"></script>
<script src="<%=resource%>/view/<%=self.api.appname%>/func.js"></script>
<script src="<%=resource%>/view/<%=api.appname%>/cbi.js"></script>
<script src="<%=resource%>/view/<%=api.appname%>/func.js"></script>
<script type="text/javascript">
//<![CDATA[
function update_config(cfgid, data, redirect_url) {
XHR.get('<%=self.api.url("update_config")%>', {
XHR.get('<%=api.url("update_config")%>', {
id: cfgid,
data: JSON.stringify(data)
},
@@ -1,7 +1,8 @@
<%
local api = self.api
local appname = self.appname or api.appname
local target_cfgname = self.target_cfgname
local map = self.map
local sectiontype = self.sectiontype
local api = map.api
local appname = self.appname or map.config
-%>
<script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js"></script>
<style>
@@ -37,7 +38,7 @@ local target_cfgname = self.target_cfgname
}
@media screen and (max-width: 1152px) {
#cbi-<%=appname%>-<%=target_cfgname%> .cbi-section-table-titles {
#cbi-<%=appname%>-<%=sectiontype%> .cbi-section-table-titles {
display: none !important;
}
}
@@ -47,7 +48,7 @@ local target_cfgname = self.target_cfgname
//Add drag-and-drop sorting
document.addEventListener("DOMContentLoaded", function () {
function initSortableForTable() {
var section = document.getElementById("cbi-<%=appname%>-<%=target_cfgname%>");
var section = document.getElementById("cbi-<%=appname%>-<%=sectiontype%>");
if (!section) return;
// === insert drag handle ===
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<div class="cbi-section">
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<style>
.dns-con {
@@ -1,6 +1,8 @@
<%
local api = self.api
local appname = api.appname
local map = self.map
local api = map.api
local appname = map.config
local sid = "@global[0]"
-%>
<style>
#cbi-<%=appname%>-socks .td.cbi-value-field > div {
@@ -35,15 +37,17 @@ local appname = api.appname
</style>
<script type="text/javascript">
//<![CDATA[
let global_id = "<%=sid%>";
const shunt_list = JSON.parse('<%=self.shunt_list%>');
function to_edit_node(btn) {
function to_edit_node(btn, stype) {
if (!btn) return;
const idReg = /^cbid\..*\..*node$/;
if (!stype) return;
let hidden_select = null;
const container = btn.closest('#cbi-<%=appname%>-global') || btn.closest('#cbi-<%=appname%>-socks');
if (!container) return null;
const selects = container.querySelectorAll('select[id^="cbid."][id*="."][id$="node"]');
const stype_dom = document.getElementById("cbi-<%=appname%>-" + stype);
if (!stype_dom) return;
const selects = stype_dom.querySelectorAll('select[id^="cbid."][id*="."][id$="node"]');
const idReg = /^cbid\..*\..*node$/;
for (const sel of selects) {
if ( idReg.test(sel.id) && getComputedStyle(sel).display === "none" && (sel.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_FOLLOWING)) {
hidden_select = sel;
@@ -94,8 +98,7 @@ local appname = api.appname
);
}
let global_id = null;
const global = document.getElementById("cbi-<%=appname%>-global");
const global = document.getElementById("cbi-<%=appname%>-" + global_id);
if (global) {
// Add an "Edit" placeholder to the routing rule node in advance to ensure left alignment of the node list.
document.querySelectorAll('.td[data-widget="nodes_listvalue"][data-name="_node"] > div').forEach(container => {
@@ -109,10 +112,7 @@ local appname = api.appname
await delay(100);
const node = global.getElementsByClassName("cbi-section-node")[0];
const node_id = node.getAttribute("id");
global_id = node_id;
const all_node = node.querySelectorAll("[id]");
const all_node = global.querySelectorAll("[id]");
const reg1 = /^cbid\..*node\.main$/;
//const reg1 = /^cbid\..*\.(node)\.main$/;
@@ -129,7 +129,7 @@ local appname = api.appname
continue;
}
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
let html = '<a href="#" onclick="return to_edit_node(this, global_id);"><%:Edit%></a>';
const m = cbid.match(/\.node$/);
if (m) {
@@ -149,7 +149,7 @@ local appname = api.appname
const socks = document.getElementById("cbi-<%=appname%>-socks");
if (socks) {
const socks_enabled_dom = document.getElementById(global_id + "-socks_enabled");
const socks_enabled_dom = document.getElementById("cbi-<%=appname%>-" + global_id + "-socks_enabled");
const descr = socks.getElementsByClassName("cbi-section-descr")[0];
descr.replaceWith(socks_enabled_dom);
const rows = socks.getElementsByClassName("cbi-section-table-row");
@@ -164,7 +164,7 @@ local appname = api.appname
const node_select = document.getElementById(dom_id);
if (!node_select) continue;
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
let html = '<a href="#" onclick="return to_edit_node(this, \'socks\');"><%:Edit%></a>';
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_socks_log")%>?name=' + id.replace("cbi-<%=appname%>-", "") + '\', \'_blank\')"><%:Log%></a>';
node_select.insertAdjacentHTML("afterend",
@@ -200,7 +200,7 @@ local appname = api.appname
})();
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
const hiddenSelect = document.getElementById("cbid.<%=appname%>.<%=self.global_cfgid%>.node");
const hiddenSelect = document.getElementById("cbid.<%=appname%>.<%=sid%>.node");
let o_val = hiddenSelect.value
const o_hasItem = shunt_list.find(element => element.id == o_val);
hiddenSelect.addEventListener("change", function(el){
@@ -208,7 +208,7 @@ local appname = api.appname
const new_hasItem = shunt_list.find(element => element.id == new_val);
if (new_hasItem) {
XHR.get('<%=api.url("update_config")%>', {
id: "<%=self.global_cfgid%>",
id: "<%=sid%>",
data: JSON.stringify({
node: new_val
})
@@ -223,8 +223,8 @@ local appname = api.appname
});
} else {
try {
document.getElementById("tab.<%=appname%>.<%=self.global_cfgid%>.Shunt").classList.add('shunt-tab-hidden');
document.getElementById("tab.<%=appname%>.<%=self.global_cfgid%>.Shunt").style.display = "none";
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").classList.add('shunt-tab-hidden');
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").style.display = "none";
} catch (error) {}
try {
document.querySelector('li[data-tab*="Shunt"]').classList.add('shunt-tab-hidden');
@@ -232,7 +232,7 @@ local appname = api.appname
} catch (error) {}
}
});
let shunt_taboption = document.getElementById("container.<%=appname%>.<%=self.global_cfgid%>.Shunt");
let shunt_taboption = document.getElementById("container.<%=appname%>.<%=sid%>.Shunt");
if (shunt_taboption) {
let shunt_option_list = document.getElementById("cbi-<%=appname%>-shunt_option_list");
if (shunt_option_list) {
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<style>
@@ -1,6 +1,6 @@
<%
local api = require "luci.passwall2.api"
local appname = api.appname
local map = self.map
local appname = map.config
-%>
<style>
@@ -1,7 +1,8 @@
<%
local api = require "luci.passwall2.api"
local haproxy_enable = api.uci_get_type("global_haproxy", "balancing_enable", "0")
local console_port = api.uci_get_type("global_haproxy", "console_port", "")
local map = self.map
local api = map.api
local haproxy_enable = map:get("@global_haproxy[0]", "balancing_enable") or "0"
local console_port = map:get("@global_haproxy[0]", "console_port") or ""
-%>
<p id="_status"></p>
@@ -1,3 +1,10 @@
<%
local map = self.map
local api = map.api
local config = map.config
local id = self.id
local s_cfgid = self.s_cfgid
-%>
<style>
.hidden {
display: none !important;
@@ -54,15 +61,15 @@
}
}
document.addEventListener("DOMContentLoaded", function () {
waitForElement('select[name*="<%=self.config%>"][name*="shunt_group"]', function(el) {
waitForElement('select[name*="<%=config%>"][name*="shunt_group"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
if (o_val != el.value) {
let save = true;
if (save) {
update_config("<%=self.id%>", {
shunt_group: getOption("<%=self.config%>", "<%=self.s_cfgid%>", "shunt_group").value,
update_config("<%=id%>", {
shunt_group: getOption("<%=config%>", "<%=s_cfgid%>", "shunt_group").value,
}, get_current_url());
}
}
@@ -1,10 +1,16 @@
<%
local map = self.map
local api = map.api
local sid = self.section
local config = map.config
-%>
<script type="text/javascript">
//<![CDATA[
let node_id = "<%=self.section%>";
let node_config_url = '<%=self.api.url("node_config")%>/' + node_id;
let node_id = "<%=sid%>";
let node_config_url = '<%=api.url("node_config")%>/' + node_id;
document.addEventListener("DOMContentLoaded", function () {
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
waitForElement('select[name*="<%=config%>"][name*="type"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
@@ -18,16 +24,16 @@
}
*/
update_config(node_id, {
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
type: getOption("<%=self.config%>", "<%=self.section%>", "type").value,
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
group: getOption("<%=config%>", "<%=sid%>", "group").value,
type: getOption("<%=config%>", "<%=sid%>", "type").value,
protocol: ''
}, node_config_url);
}
}
});
});
waitForElement('select[name*="<%=self.config%>"][name*="protocol"]', function(el) {
waitForElement('select[name*="<%=config%>"][name*="protocol"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
@@ -43,9 +49,9 @@
}
*/
update_config(node_id, {
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
protocol: getOption("<%=self.config%>", "<%=self.section%>", name).value,
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
group: getOption("<%=config%>", "<%=sid%>", "group").value,
protocol: getOption("<%=config%>", "<%=sid%>", name).value,
}, node_config_url);
} else {
window.location.href = node_config_url + "?select_proto=" + encodeURIComponent(el.value);
@@ -1,3 +1,8 @@
<%
local map = self.map
local api = map.api
local sid = self.section
-%>
<script type="text/javascript">
//<![CDATA[
function fetchCertSha256(el) {
@@ -5,7 +10,7 @@
el.setAttribute("data-loading", "1");
el.style.pointerEvents = "none";
el.style.color = "red";
XHR.get('<%=self.api.url("fetch_certsha256")%>', { id: "<%=self.section%>" }, function(x, res) {
XHR.get('<%=api.url("fetch_certsha256")%>', { id: "<%=sid%>" }, function(x, res) {
el.setAttribute("data-loading", "0");
el.style.pointerEvents = "";
el.style.color = "";
@@ -1,18 +1,18 @@
<%
local api = self.api
local appname = api.appname
local map = self.map
local api = map.api
local appname = map.config
local default_node_type = ""
local shunt_rule_list = {}
local node = api.uci_get_type("global", "node")
local node = map:get("@global[0]", "node")
if node then
local node_type = api.uci_get_type_id(node, "type")
local node_protocol = api.uci_get_type_id(node, "protocol")
local node_type = map:get(node, "type")
local node_protocol = map:get(node, "protocol")
if (node_type == "Xray" or node_type == "sing-box") and node_protocol == "_shunt" then
default_node_type = node_protocol
local node_shunt_group = api.uci_get_type_id(node, "shunt_group")
map.uci:foreach(appname, "shunt_rules", function(e)
local node_shunt_group = map:get(node, "shunt_group")
map:foreach("shunt_rules", function(e)
if e[".name"] and e.remarks and e.group == node_shunt_group then
shunt_rule_list[#shunt_rule_list + 1] = e
end
@@ -431,8 +431,8 @@ table td, .table .td {
<script type="text/javascript">
//<![CDATA[
let auto_detection_time = "<%=api.uci_get_type("global_other", "auto_detection_time", "0")%>"
let show_node_info = "<%=api.uci_get_type("global_other", "show_node_info", "0")%>"
let auto_detection_time = "<%=map:get("@global_other[0]", "auto_detection_time") or "0"%>"
let show_node_info = "<%=map:get("@global_other[0]", "show_node_info") or "0"%>"
var ajax = {
list: [],
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<script type="text/javascript">
@@ -1,5 +1,5 @@
<%
local api = require "luci.passwall2.api"
local api = self.api
-%>
<style>
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
local fs = api.fs
local has_old_geoip = fs.access("/tmp/bak_v2ray/geoip.dat")
local has_old_geosite = fs.access("/tmp/bak_v2ray/geosite.dat")
@@ -1,6 +1,7 @@
<%
local api = self.api
local appname = api.appname
local map = self.map
local api = map.api
local appname = map.config
-%>
<script src="<%=resource%>/view/<%=appname%>/Sortable.min.js"></script>
<style>
@@ -1,13 +1,16 @@
<%
local api = self.api
local map = self.map
local api = map.api
local config = map.config
local section = self.section
-%>
<script type="text/javascript">
//<![CDATA[
let node_id = "<%=self.section%>";
let node_id = "<%=section%>";
let node_config_url = '<%=api.url("server_config")%>/' + node_id;
document.addEventListener("DOMContentLoaded", function () {
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
waitForElement('select[name*="<%=config%>"][name*="type"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
@@ -16,9 +19,9 @@ local api = self.api
if (save) {
//document.getElementsByClassName('cbi-button-save')[0].click();
server_update_config(node_id, {
enable: getOption("<%=self.config%>", node_id, "enable").value,
remarks: getOption("<%=self.config%>", node_id, "remarks").value,
type: getOption("<%=self.config%>", node_id, "type").value,
enable: getOption("<%=config%>", node_id, "enable").value,
remarks: getOption("<%=config%>", node_id, "remarks").value,
type: getOption("<%=config%>", node_id, "type").value,
protocol: ''
}, node_config_url);
}
@@ -1,7 +1,12 @@
<%
local map = self.map
local api = map.api
local section = self.section
-%>
<script type="text/javascript">
//<![CDATA[
function server_update_config(cfgid, data, redirect_url) {
XHR.get('<%=self.api.url("server_update_config")%>', {
XHR.get('<%=api.url("server_update_config")%>', {
id: cfgid,
data: JSON.stringify(data)
},
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<script type="text/javascript">
//<![CDATA[
@@ -1,5 +1,8 @@
<%
local api = self.api
local map = self.map
local api = map.api
local config = map.config
local sectiontype = self.sectiontype
-%>
<script type="text/javascript">
//<![CDATA[
@@ -19,7 +22,7 @@ local api = self.api
);
}
var edit_btn = document.getElementById("cbi-<%=self.appname%>-<%=self.sectiontype%>").getElementsByClassName("cbi-button cbi-button-edit");
var edit_btn = document.getElementById("cbi-<%=config%>-<%=sectiontype%>").getElementsByClassName("cbi-button cbi-button-edit");
for (var i = 0; i < edit_btn.length; i++) {
try {
var onclick_str = edit_btn[i].getAttribute("onclick");
@@ -1,5 +1,6 @@
<%
local api = require "luci.passwall2.api"
local map = self.map
local api = map.api
-%>
<script type="text/javascript">
+3 -30
View File
@@ -1378,24 +1378,6 @@ msgstr "<br />none: پیش‌فرض، بدون استتار، داده‌های
msgid "Use it together with the DNS disguised type. You can fill in any domain."
msgstr "از آن همراه با نوع استتار DNS استفاده کنید. می‌توانید هر دامنه‌ای را وارد کنید."
msgid "Auth"
msgstr "احراز هویت"
msgid "Socks for authentication"
msgstr "Socks برای احراز هویت"
msgid "Socks protocol authentication, support anonymous and password."
msgstr "احراز هویت پروتکل Socks، پشتیبانی از ناشناس و رمز عبور."
msgid "anonymous"
msgstr "ناشناس"
msgid "User Password"
msgstr "رمز عبور کاربر"
msgid "Username and Password must be used together!"
msgstr "نام کاربری و رمز عبور باید با هم استفاده شوند!"
msgid "Prefer firewall tools"
msgstr "ترجیح ابزارهای فایروال"
@@ -1405,18 +1387,6 @@ msgstr "IPv6 TProxy"
msgid "Experimental feature. Make sure that your node supports IPv6."
msgstr "ویژگی آزمایشی. مطمئن شوید که گره شما از IPv6 پشتیبانی می‌کند."
msgid "Status info"
msgstr "اطلاعات وضعیت"
msgid "Big icon"
msgstr "آیکون بزرگ"
msgid "Show node check"
msgstr "نمایش بررسی گره"
msgid "Show Show IP111"
msgstr "نمایش نمایش IP111"
msgid "Destination protocol"
msgstr "پروتکل مقصد"
@@ -2452,3 +2422,6 @@ msgstr "سوئیت‌های رمزدار"
msgid "Configures the list of supported cipher suites."
msgstr "فهرست مجموعه‌های رمز پشتیبانی‌شده را پیکربندی می‌کند."
msgid "This username already exists."
msgstr "این نام کاربری از قبل وجود دارد."
+3 -30
View File
@@ -1379,24 +1379,6 @@ msgstr "<br />none: по умолчанию, без маскировки, дан
msgid "Use it together with the DNS disguised type. You can fill in any domain."
msgstr "Используется вместе с типом маскировки DNS. Можно указать любой домен."
msgid "Auth"
msgstr "Аутентификация"
msgid "Socks for authentication"
msgstr "Аутентификация SOCKS"
msgid "Socks protocol authentication, support anonymous and password."
msgstr "Метод аутентификации SOCKS: анонимный или по логину/паролю."
msgid "anonymous"
msgstr "анонимно"
msgid "User Password"
msgstr "Логин и пароль"
msgid "Username and Password must be used together!"
msgstr "Логин и пароль должны быть указаны вместе!"
msgid "Prefer firewall tools"
msgstr "Предпочтительный инструмент фаервола"
@@ -1406,18 +1388,6 @@ msgstr "IPv6 TProxy"
msgid "Experimental feature. Make sure that your node supports IPv6."
msgstr "Экспериментальная функция. Убедитесь, что ваш сервер поддерживает IPv6."
msgid "Status info"
msgstr "Информация о статусе"
msgid "Big icon"
msgstr "Крупный значок"
msgid "Show node check"
msgstr "Показывать проверку серверов"
msgid "Show Show IP111"
msgstr "Показывать IP111"
msgid "Destination protocol"
msgstr "Целевой протокол"
@@ -2450,3 +2420,6 @@ msgstr "Наборы шифров"
msgid "Configures the list of supported cipher suites."
msgstr "Задает список поддерживаемых наборов шифров."
msgid "This username already exists."
msgstr "Это имя пользователя уже существует."
+3 -30
View File
@@ -1370,24 +1370,6 @@ msgstr "<br />none:默认值,不进行伪装,发送的数据是没有特
msgid "Use it together with the DNS disguised type. You can fill in any domain."
msgstr "配合伪装类型 DNS 使用,可随便填一个域名。"
msgid "Auth"
msgstr "身份认证"
msgid "Socks for authentication"
msgstr "Socks认证方式"
msgid "Socks protocol authentication, support anonymous and password."
msgstr "Socks 协议的认证方式,支持匿名方式和账号密码方式。"
msgid "anonymous"
msgstr "匿名"
msgid "User Password"
msgstr "账号密码"
msgid "Username and Password must be used together!"
msgstr "账号和密码必须同时使用!"
msgid "Prefer firewall tools"
msgstr "首选防火墙工具"
@@ -1397,18 +1379,6 @@ msgstr "IPv6透明代理(TProxy)"
msgid "Experimental feature. Make sure that your node supports IPv6."
msgstr "实验特性,请确保你的节点支持IPv6"
msgid "Status info"
msgstr "状态信息"
msgid "Big icon"
msgstr "大图标"
msgid "Show node check"
msgstr "显示节点检测"
msgid "Show Show IP111"
msgstr "显示IP111"
msgid "Destination protocol"
msgstr "目标协议"
@@ -2438,3 +2408,6 @@ msgstr "密码套件"
msgid "Configures the list of supported cipher suites."
msgstr "配置支持的密码套件列表。"
msgid "This username already exists."
msgstr "该用户名已存在。"
+3 -30
View File
@@ -1370,24 +1370,6 @@ msgstr "<br />none:默認值,不进行伪装,發送的數据是沒有特
msgid "Use it together with the DNS disguised type. You can fill in any domain."
msgstr "配合伪装類型 DNS 使用,可随便填一個域名。"
msgid "Auth"
msgstr "身份認證"
msgid "Socks for authentication"
msgstr "Socks認證方式"
msgid "Socks protocol authentication, support anonymous and password."
msgstr "Socks 協議的認證方式,支持匿名方式和账号密碼方式。"
msgid "anonymous"
msgstr "匿名"
msgid "User Password"
msgstr "账号密碼"
msgid "Username and Password must be used together!"
msgstr "账号和密碼必須同時使用!"
msgid "Prefer firewall tools"
msgstr "首選防火牆工具"
@@ -1397,18 +1379,6 @@ msgstr "IPv6透明代理(TProxy)"
msgid "Experimental feature. Make sure that your node supports IPv6."
msgstr "實驗特性,請確保你的節點支持IPv6"
msgid "Status info"
msgstr "状態信息"
msgid "Big icon"
msgstr "大图標"
msgid "Show node check"
msgstr "顯示節點檢測"
msgid "Show Show IP111"
msgstr "顯示IP111"
msgid "Destination protocol"
msgstr "目標協議"
@@ -2444,3 +2414,6 @@ msgstr "密碼套件"
msgid "Configures the list of supported cipher suites."
msgstr "配置支援的密碼套件列表。"
msgid "This username already exists."
msgstr "該用戶名已存在。"
@@ -8,19 +8,11 @@
EEOF
}
[ "`which nft`" ] && {
uci -q set passwall2.@global_forwarding[0].use_nft=1
uci -q commit passwall2
}
if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF
delete ucitrack.@passwall2[-1]
add ucitrack passwall2
set ucitrack.@passwall2[-1].init=passwall2
delete ucitrack.@passwall2_server[-1]
add ucitrack passwall2_server
set ucitrack.@passwall2_server[-1].init=passwall2_server
commit ucitrack
EOF
fi
@@ -31,11 +23,6 @@ uci -q batch <<-EOF
set firewall.passwall2.type='script'
set firewall.passwall2.path='/var/etc/passwall2.include'
delete firewall.passwall2_server
set firewall.passwall2_server=include
set firewall.passwall2_server.type='script'
set firewall.passwall2_server.path='/var/etc/passwall2_server.include'
set dhcp.@dnsmasq[0].localuse=1
commit dhcp
@@ -45,12 +32,9 @@ EOF
if [ -x "/sbin/fw3" ]; then
uci -q set firewall.passwall2.reload='1'
uci -q set firewall.passwall2_server.reload='1'
else
uci -q delete firewall.passwall2.reload
uci -q delete firewall.passwall2.fw4_compatible
uci -q delete firewall.passwall2_server.reload
uci -q delete firewall.passwall2_server.fw4_compatible
fi
uci commit firewall
@@ -0,0 +1,39 @@
#!/bin/sh
[ ! -f "/usr/share/ucitrack/luci-app-passwall2_server.json" ] && {
cat > /usr/share/ucitrack/luci-app-passwall2_server.json << EEOF
{
"config": "passwall2_server",
"init": "passwall2_server"
}
EEOF
}
if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF
delete ucitrack.@passwall2_server[-1]
add ucitrack passwall2_server
set ucitrack.@passwall2_server[-1].init=passwall2_server
commit ucitrack
EOF
fi
uci -q batch <<-EOF
delete firewall.passwall2_server
set firewall.passwall2_server=include
set firewall.passwall2_server.type='script'
set firewall.passwall2_server.path='/var/etc/passwall2_server.include'
EOF
if [ -x "/sbin/fw3" ]; then
uci -q set firewall.passwall2_server.reload='1'
else
uci -q delete firewall.passwall2_server.reload
uci -q delete firewall.passwall2_server.fw4_compatible
fi
uci commit firewall
rm -f /tmp/luci-indexcache /tmp/luci-indexcache.*
rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null
exit 0
@@ -351,7 +351,7 @@ run_socks() {
[ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=$TMP_PATH/$config_file
[ -n "$http_port" ] || http_port=0
[ -n "$http_config_file" ] && [ -z "$(echo ${http_config_file} | grep $TMP_PATH)" ] && http_config_file=$TMP_PATH/$http_config_file
if [ -n "$log_file" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
if [ -n "$log_file" ] && [ "$log_file" != "/dev/null" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then
log_file=$TMP_PATH/$log_file
else
log_file="/dev/null"
@@ -21,11 +21,11 @@ local haproxy_conf = var["-conf"]
local haproxy_dns = "127.0.0.1"
local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1"
local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp"
local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "20"
local balancingStrategy = uci:get(appname, "@global_haproxy[0]", "balancingStrategy") or "roundrobin"
local console_port = uci:get(appname, "@global_haproxy[0]", "console_port")
local bind_local = uci:get(appname, "@global_haproxy[0]", "bind_local") or "0"
local health_check_type = uci:get(api.c_config, "@global_haproxy[0]", "health_check_type") or "tcp"
local health_check_inter = uci:get(api.c_config, "@global_haproxy[0]", "health_check_inter") or "20"
local balancingStrategy = uci:get(api.c_config, "@global_haproxy[0]", "balancingStrategy") or "roundrobin"
local console_port = uci:get(api.c_config, "@global_haproxy[0]", "console_port")
local bind_local = uci:get(api.c_config, "@global_haproxy[0]", "bind_local") or "0"
local bind_address = "0.0.0.0"
if bind_local == "1" then bind_address = "127.0.0.1" end
@@ -92,15 +92,15 @@ f_out:write(haproxy_config)
local listens = {}
uci:foreach(appname, "haproxy_config", function(t)
uci:foreach(api.c_config, "haproxy_config", function(t)
if t.enabled == "1" then
local server_remark
local server_address
local server_port
local lbss = t.lbss
local listen_port = tonumber(t.haproxy_port) or 0
local server_node = uci:get_all(appname, lbss)
local hop = (health_check_type == "passwall_logic") and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil
local server_node = uci:get_all(api.c_config, lbss)
local hop = (health_check_type == "script_logic") and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil
hop = hop and hop:gsub(":", "-") or nil
if server_node and server_node.address and (server_node.port or hop) then
server_remark = server_node.address .. ":" .. (server_node.port or hop)
@@ -108,7 +108,7 @@ uci:foreach(appname, "haproxy_config", function(t)
server_port = server_node.port or hop
t.origin_address = server_address
t.origin_port = server_port
if health_check_type == "passwall_logic" then
if health_check_type == "script_logic" then
if server_node.type ~= "Socks" then
local relay_port = server_node.port
local new_port = api.get_new_port()
@@ -170,7 +170,7 @@ listen %s
balance %s
]], port, bind_address, port, balancingStrategy))
if health_check_type == "passwall_logic" then
if health_check_type == "script_logic" then
f_out:write(string.format([[
option external-check
external-check command "/usr/share/%s/haproxy_check.sh"
@@ -212,8 +212,8 @@ listen %s
end
-- Console config
local console_user = uci:get(appname, "@global_haproxy[0]", "console_user")
local console_password = uci:get(appname, "@global_haproxy[0]", "console_password")
local console_user = uci:get(api.c_config, "@global_haproxy[0]", "console_user")
local console_password = uci:get(api.c_config, "@global_haproxy[0]", "console_password")
local str = [[
listen console
bind 0.0.0.0:%s
@@ -228,8 +228,8 @@ f_out:write("\n" .. string.format(str, console_port, (console_user and console_u
f_out:close()
-- Built-in health check URL
if health_check_type == "passwall_logic" then
local probeUrl = uci:get(appname, "@global_haproxy[0]", "health_probe_url") or "https://www.google.com/generate_204"
if health_check_type == "script_logic" then
local probeUrl = uci:get(api.c_config, "@global_haproxy[0]", "health_probe_url") or "https://www.google.com/generate_204"
local f_url = io.open(haproxy_path .. "/Probe_URL", "w")
f_url:write(probeUrl)
f_url:close()
@@ -25,7 +25,7 @@ end
local function backup_servers()
local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server")
if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
uci:set(appname, "@global[0]", "dnsmasq_servers", DNSMASQ_DNS)
uci:set(api.c_config, "@global[0]", "dnsmasq_servers", DNSMASQ_DNS)
api.uci_save(uci, appname, true)
end
end
@@ -38,12 +38,12 @@ local function restore_servers()
tinsert(dns_table, v)
end
end
local OLD_SERVER = uci:get(appname, "@global[0]", "dnsmasq_servers")
local OLD_SERVER = uci:get(api.c_config, "@global[0]", "dnsmasq_servers")
if OLD_SERVER and #OLD_SERVER > 0 then
for k, v in ipairs(OLD_SERVER) do
tinsert(dns_table, v)
end
uci:delete(appname, "@global[0]", "dnsmasq_servers")
uci:delete(api.c_config, "@global[0]", "dnsmasq_servers")
api.uci_save(uci, appname, true)
end
if dns_table and #dns_table > 0 then
@@ -268,7 +268,7 @@ function add_rule(var)
-- Always use domestic DNS to resolve node domain names
if true then
fwd_dns = LOCAL_DNS
uci:foreach(appname, "nodes", function(t)
uci:foreach(api.c_config, "nodes", function(t)
local function process_address(address)
address = (address or ""):lower()
if address == "engage.cloudflareclient.com" then return end
@@ -2,11 +2,11 @@
local api = require "luci.passwall2.api"
local name = api.appname
local c_config = api.c_config
local fs = api.fs
local log = api.log
local sys = api.sys
local uci = api.uci
local jsonc = api.jsonc
local arg1 = arg[1]
local arg2 = arg[2]
@@ -16,9 +16,9 @@ local reboot = 0
local geoip_update = "0"
local geosite_update = "0"
local geoip_url = uci:get(name, "@global_rules[0]", "geoip_url") or "https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat"
local geosite_url = uci:get(name, "@global_rules[0]", "geosite_url") or "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
local asset_location = uci:get(name, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
local geoip_url = uci:get(c_config, "@global_rules[0]", "geoip_url") or "https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat"
local geosite_url = uci:get(c_config, "@global_rules[0]", "geosite_url") or "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
local asset_location = uci:get(c_config, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
asset_location = asset_location:match("/$") and asset_location or (asset_location .. "/")
local backup_path = "/tmp/bak_v2ray/"
@@ -134,7 +134,7 @@ local function fetch_geofile(geo_name, geo_type, url)
reboot = 1
log(1, api.i18n.translatef("%s update success.", geo_type))
else
log(1, api.i18n.translatef("%s update failed, please try again later.", geo_type))
log(1, api.i18n.translatef("%s update failed, please try again later or change URL.", geo_type))
return 1
end
else
@@ -148,7 +148,7 @@ local function fetch_geofile(geo_name, geo_type, url)
log(1, api.i18n.translatef("%s update success.", geo_type))
end
else
log(1, api.i18n.translatef("%s update failed, please try again later.", geo_type))
log(1, api.i18n.translatef("%s update failed, please try again later or change URL.", geo_type))
return 1
end
return 0
@@ -177,8 +177,8 @@ if arg2 then
end
end)
else
geoip_update = uci:get(name, "@global_rules[0]", "geoip_update") or "1"
geosite_update = uci:get(name, "@global_rules[0]", "geosite_update") or "1"
geoip_update = uci:get(c_config, "@global_rules[0]", "geoip_update") or "1"
geosite_update = uci:get(c_config, "@global_rules[0]", "geosite_update") or "1"
end
if geoip_update == "0" and geosite_update == "0" then
os.exit(0)
@@ -233,9 +233,9 @@ if geosite_update == "1" then
remove_tmp_geofile("geosite")
end
uci:set(name, "@global_rules[0]", "geoip_update", geoip_update)
uci:set(name, "@global_rules[0]", "geosite_update", geosite_update)
api.uci_save(uci, name, true)
uci:set(c_config, "@global_rules[0]", "geoip_update", geoip_update)
uci:set(c_config, "@global_rules[0]", "geosite_update", geosite_update)
api.uci_save(uci, c_config, true)
if reboot == 1 then
if arg3 == "cron" then
@@ -245,8 +245,8 @@ if reboot == 1 then
end
log(1, api.i18n.translate("Restart the service and apply the new rules."))
uci:set(name, "@global[0]", "flush_set", "1")
api.uci_save(uci, name, true, true)
uci:set(c_config, "@global[0]", "flush_set", "1")
api.uci_save(uci, c_config, true, true)
end
log(0, api.i18n.translate("The rules have been updated..."))
@@ -6,8 +6,9 @@
require 'luci.util'
require 'luci.jsonc'
require 'luci.sys'
local appname = 'passwall2'
local api = require ("luci.passwall2.api")
local api = require "luci.passwall2.api"
local appname = api.appname
local c_config = api.c_config
local datatypes = require "luci.cbi.datatypes"
-- these global functions are accessed all the time by the event handler
@@ -31,9 +32,9 @@ local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local DEFAULT_ALLOWINSECURE = true
local DEFAULT_FILTER_KEYWORD_MODE = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0"
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(appname, "@global_subscribe[0]", "filter_discard_list") or {}
local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(appname, "@global_subscribe[0]", "filter_keep_list") or {}
local DEFAULT_FILTER_KEYWORD_MODE = uci:get(c_config, "@global_subscribe[0]", "filter_keyword_mode") or "0"
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(c_config, "@global_subscribe[0]", "filter_discard_list") or {}
local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(c_config, "@global_subscribe[0]", "filter_keep_list") or {}
-- Nodes should be retrieved using the core type (if not set on the node subscription page, the default type will be used automatically).
local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_TROJAN_TYPE = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
@@ -130,13 +131,13 @@ do
local szType = "@global[0]"
local option = "node"
local node_id = uci:get(appname, szType, option)
local node_id = uci:get(c_config, szType, option)
CONFIG[#CONFIG + 1] = {
log = true,
remarks = i18n.translatef("Node"),
currentNode = node_id and uci:get_all(appname, node_id) or nil,
currentNode = node_id and uci:get_all(c_config, node_id) or nil,
set = function(o, server)
uci:set(appname, szType, option, server)
uci:set(c_config, szType, option, server)
o.newNodeId = server
end
}
@@ -145,7 +146,7 @@ do
if true then
local i = 0
local option = "node"
uci:foreach(appname, "socks", function(t)
uci:foreach(c_config, "socks", function(t)
i = i + 1
local id = t[".name"]
local node_id = t[option]
@@ -153,14 +154,14 @@ do
log = true,
id = id,
remarks = i18n.translatef("Socks node list [%s]", i),
currentNode = node_id and uci:get_all(appname, node_id) or nil,
currentNode = node_id and uci:get_all(c_config, node_id) or nil,
set = function(o, server)
if not server or server == "" then
if #nodes_table > 0 then
server = nodes_table[1][".name"]
end
end
uci:set(appname, t[".name"], option, server)
uci:set(c_config, t[".name"], option, server)
o.newNodeId = server
end
}
@@ -170,7 +171,7 @@ do
local newNodes = {}
for k, asb_node_id in ipairs(t.autoswitch_backup_node) do
if asb_node_id then
local currentNode = uci:get_all(appname, asb_node_id) or {}
local currentNode = uci:get_all(c_config, asb_node_id) or {}
if currentNode[".type"] == "nodes" then
currentNodes[#currentNodes + 1] = {
log = true,
@@ -192,7 +193,7 @@ do
set = function(o, newNodes)
if o then
if not newNodes then newNodes = o.newNodes end
uci:set_list(appname, id, "autoswitch_backup_node", newNodes or {})
uci:set_list(c_config, id, "autoswitch_backup_node", newNodes or {})
end
end
}
@@ -208,25 +209,25 @@ do
local ip, port = str:match("^([%d%.]+):(%d+)$")
return ip and datatypes.ipaddr(ip) and tonumber(port) and tonumber(port) <= 65535
end
uci:foreach(appname, "haproxy_config", function(t)
uci:foreach(c_config, "haproxy_config", function(t)
i = i + 1
local node_id = t[option]
CONFIG[#CONFIG + 1] = {
log = true,
id = t[".name"],
remarks = i18n.translatef("HAProxy node list [%s]", i),
currentNode = node_id and uci:get_all(appname, node_id) or nil,
currentNode = node_id and uci:get_all(c_config, node_id) or nil,
set = function(o, server)
-- Modify the LBS value only if it is not in IP:Port format.
if not is_ip_port(t[option]) then
uci:set(appname, t[".name"], option, server)
uci:set(c_config, t[".name"], option, server)
o.newNodeId = server
end
end,
delete = function(o)
-- Deletion is only performed if the current LBS value is not in IP:port format.
if not is_ip_port(t[option]) then
uci:delete(appname, t[".name"])
uci:delete(c_config, t[".name"])
end
end
}
@@ -235,7 +236,7 @@ do
if true then
local i = 0
uci:foreach(appname, "acl_rule", function(t)
uci:foreach(c_config, "acl_rule", function(t)
i = i + 1
local option = "node"
local node_id = t[option]
@@ -243,20 +244,20 @@ do
log = true,
id = t[".name"],
remarks = i18n.translatef("ACL list [%s]", i),
currentNode = node_id and uci:get_all(appname, node_id) or nil,
currentNode = node_id and uci:get_all(c_config, node_id) or nil,
set = function(o, server)
uci:set(appname, t[".name"], option, server)
uci:set(c_config, t[".name"], option, server)
o.newNodeId = server
end
}
end)
end
uci:foreach(appname, "nodes", function(node)
uci:foreach(c_config, "nodes", function(node)
local node_id = node[".name"]
if node.protocol and node.protocol == '_shunt' then
local rules = {}
uci:foreach(appname, "shunt_rules", function(e)
uci:foreach(c_config, "shunt_rules", function(e)
if e[".name"] and e.remarks then
table.insert(rules, e)
table.insert(rules, {
@@ -277,7 +278,7 @@ do
for k, e in pairs(rules) do
local _node_id = node[e[".name"]] or nil
if _node_id then
local section = uci:get_all(appname, _node_id) or {}
local section = uci:get_all(c_config, _node_id) or {}
if section[".type"] == "nodes" then
CONFIG[#CONFIG + 1] = {
log = false,
@@ -285,7 +286,7 @@ do
remarks = i18n.translatef("Shunt [%s] node", e.remarks),
set = function(o, server)
if not server then server = "" end
uci:set(appname, node_id, e[".name"], server)
uci:set(c_config, node_id, e[".name"], server)
o.newNodeId = server
end
}
@@ -302,7 +303,7 @@ do
log = true,
node = b_node_id,
currentNode = (function()
local section = uci:get_all(appname, b_node_id) or {}
local section = uci:get_all(c_config, b_node_id) or {}
if section[".type"] == "socks" then
return { Socks = b_node_id }
end
@@ -324,15 +325,15 @@ do
set = function(o, newNodes)
if o then
if not newNodes then newNodes = o.newNodes end
uci:set_list(appname, node_id, "balancing_node", newNodes or {})
uci:set_list(c_config, node_id, "balancing_node", newNodes or {})
end
end
}
-- Backup Node
local currentNode = uci:get_all(appname, node_id) or nil
local currentNode = uci:get_all(c_config, node_id) or nil
if currentNode and currentNode.fallback_node then
local section = uci:get_all(appname, currentNode.fallback_node) or {}
local section = uci:get_all(c_config, currentNode.fallback_node) or {}
if section[".type"] == "nodes" then
CONFIG[#CONFIG + 1] = {
log = true,
@@ -340,11 +341,11 @@ do
remarks = i18n.translatef("Xray Load Balancing node [%s] backup node", node_id),
currentNode = section,
set = function(o, server)
uci:set(appname, node_id, "fallback_node", server)
uci:set(c_config, node_id, "fallback_node", server)
o.newNodeId = server
end,
delete = function(o)
uci:delete(appname, node_id, "fallback_node")
uci:delete(c_config, node_id, "fallback_node")
end
}
end
@@ -359,7 +360,7 @@ do
log = true,
node = u_node_id,
currentNode = (function()
local section = uci:get_all(appname, u_node_id) or {}
local section = uci:get_all(c_config, u_node_id) or {}
if section[".type"] == "socks" then
return { Socks = u_node_id }
end
@@ -381,47 +382,47 @@ do
set = function(o, newNodes)
if o then
if not newNodes then newNodes = o.newNodes end
uci:set_list(appname, node_id, "urltest_node", newNodes or {})
uci:set_list(c_config, node_id, "urltest_node", newNodes or {})
end
end
}
else
-- Preproxy Node
local currentNode = uci:get_all(appname, node_id) or nil
local currentNode = uci:get_all(c_config, node_id) or nil
if currentNode and currentNode.preproxy_node then
local section = uci:get_all(appname, currentNode.preproxy_node) or {}
local section = uci:get_all(c_config, currentNode.preproxy_node) or {}
if section[".type"] == "nodes" then
CONFIG[#CONFIG + 1] = {
log = true,
id = node_id,
remarks = i18n.translatef("Node [%s] preproxy node", node_id),
currentNode = uci:get_all(appname, currentNode.preproxy_node) or nil,
currentNode = uci:get_all(c_config, currentNode.preproxy_node) or nil,
set = function(o, server)
uci:set(appname, node_id, "preproxy_node", server)
uci:set(c_config, node_id, "preproxy_node", server)
o.newNodeId = server
end,
delete = function(o)
uci:delete(appname, node_id, "preproxy_node")
uci:delete(c_config, node_id, "preproxy_node")
end
}
end
end
-- Landing node
local currentNode = uci:get_all(appname, node_id) or nil
local currentNode = uci:get_all(c_config, node_id) or nil
if currentNode and currentNode.to_node then
local section = uci:get_all(appname, currentNode.to_node) or {}
local section = uci:get_all(c_config, currentNode.to_node) or {}
if section[".type"] == "nodes" then
CONFIG[#CONFIG + 1] = {
log = true,
id = node_id,
remarks = i18n.translatef("Node [%s] landing node", node_id),
currentNode = uci:get_all(appname, currentNode.to_node) or nil,
currentNode = uci:get_all(c_config, currentNode.to_node) or nil,
set = function(o, server)
uci:set(appname, node_id, "to_node", server)
uci:set(c_config, node_id, "to_node", server)
o.newNodeId = server
end,
delete = function(o)
uci:delete(appname, node_id, "to_node")
uci:delete(c_config, node_id, "to_node")
end
}
end
@@ -2083,19 +2084,19 @@ local function truncate_nodes(group)
end
end
end
uci:foreach(appname, "nodes", function(node)
uci:foreach(c_config, "nodes", function(node)
if node.add_mode == "2" then
if (not group) or (group:lower() == (node.group or ""):lower()) then
uci:delete(appname, node['.name'])
uci:delete(c_config, node['.name'])
end
end
end)
uci:foreach(appname, "subscribe_list", function(o)
uci:foreach(c_config, "subscribe_list", function(o)
if (not group) or (group:lower() == (o.remark or ""):lower()) then
uci:delete(appname, o['.name'], "md5")
uci:delete(c_config, o['.name'], "md5")
end
end)
api.uci_save(uci, appname, true)
api.uci_save(uci, c_config, true)
end
local function select_node(nodes, config, parentConfig)
@@ -2238,10 +2239,10 @@ local function update_node(manual)
end
if manual == 0 and next(group) then
uci:foreach(appname, "nodes", function(node)
uci:foreach(c_config, "nodes", function(node)
-- Do not delete nodes if no new nodes are found or nodes were manually imported...
if node.add_mode == "2" and (node.group and group[node.group:lower()] == true) then
uci:delete(appname, node['.name'])
uci:delete(c_config, node['.name'])
end
end)
end
@@ -2254,9 +2255,9 @@ local function update_node(manual)
-- Subscription Group Chain Agent
local function valid_chain_node(node)
if not node then return "" end
local cp = uci:get(appname, node, "chain_proxy") or ""
local am = uci:get(appname, node, "add_mode") or "0"
chain_node_type = (cp == "" and am ~= "2") and (uci:get(appname, node, "type") or "") or ""
local cp = uci:get(c_config, node, "chain_proxy") or ""
local am = uci:get(c_config, node, "add_mode") or "0"
chain_node_type = (cp == "" and am ~= "2") and (uci:get(c_config, node, "type") or "") or ""
if chain_node_type ~= "Xray" and chain_node_type ~= "sing-box" then
chain_node_type = ""
return ""
@@ -2274,42 +2275,42 @@ local function update_node(manual)
chain_node_type = (outbound_iface_group ~= "") and "iface" or chain_node_type
end
for _, vv in ipairs(list) do
local cfgid = uci:section(appname, "nodes", api.gen_random_char())
local cfgid = uci:section(c_config, "nodes", api.gen_random_char())
for kkk, vvv in pairs(vv) do
if type(vvv) == "table" and next(vvv) ~= nil then
uci:set_list(appname, cfgid, kkk, vvv)
uci:set_list(c_config, cfgid, kkk, vvv)
else
if kkk ~= "group" or vvv ~= "default" then
uci:set(appname, cfgid, kkk, vvv)
uci:set(c_config, cfgid, kkk, vvv)
end
-- Sing-Box Node Domain resolver
if kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then
if domain_resolver then
uci:set(appname, cfgid, "domain_resolver", domain_resolver)
uci:set(c_config, cfgid, "domain_resolver", domain_resolver)
if domain_resolver_dns then
uci:set(appname, cfgid, "domain_resolver_dns", domain_resolver_dns)
uci:set(c_config, cfgid, "domain_resolver_dns", domain_resolver_dns)
elseif domain_resolver_dns_https then
uci:set(appname, cfgid, "domain_resolver_dns_https", domain_resolver_dns_https)
uci:set(c_config, cfgid, "domain_resolver_dns_https", domain_resolver_dns_https)
end
end
if domain_strategy then
if vvv == "sing-box" then
domain_strategy = (domain_strategy == "UseIPv4" and "ipv4_only") or (domain_strategy == "UseIPv6" and "ipv6_only") or domain_strategy
end
uci:set(appname, cfgid, "domain_strategy", domain_strategy)
uci:set(c_config, cfgid, "domain_strategy", domain_strategy)
end
end
-- Subscription Group Chain Agent
if chain_node_type ~= "" and kkk == "type" and (vvv == "Xray" or vvv == "sing-box") then
if preproxy_node_group ~="" then
uci:set(appname, cfgid, "chain_proxy", "1")
uci:set(appname, cfgid, "preproxy_node", preproxy_node_group)
uci:set(c_config, cfgid, "chain_proxy", "1")
uci:set(c_config, cfgid, "preproxy_node", preproxy_node_group)
elseif to_node_group ~= "" then
uci:set(appname, cfgid, "chain_proxy", "2")
uci:set(appname, cfgid, "to_node", to_node_group)
uci:set(c_config, cfgid, "chain_proxy", "2")
uci:set(c_config, cfgid, "to_node", to_node_group)
elseif outbound_iface_group ~= "" then
uci:set(appname, cfgid, "chain_proxy", "3")
uci:set(appname, cfgid, "outbound_iface", outbound_iface_group)
uci:set(c_config, cfgid, "chain_proxy", "3")
uci:set(c_config, cfgid, "outbound_iface", outbound_iface_group)
end
end
end
@@ -2320,16 +2321,16 @@ local function update_node(manual)
for cfgid, info in pairs(subscribe_info) do
for key, value in pairs(info) do
if value ~= "" then
uci:set(appname, cfgid, key, value)
uci:set(c_config, cfgid, key, value)
else
uci:delete(appname, cfgid, key)
uci:delete(c_config, cfgid, key)
end
end
end
if next(CONFIG) then
local nodes = {}
uci:foreach(appname, "nodes", function(node)
uci:foreach(c_config, "nodes", function(node)
nodes[#nodes + 1] = node
end)
@@ -2351,7 +2352,7 @@ local function update_node(manual)
end
end
api.uci_save(uci, appname, true)
api.uci_save(uci, c_config, true)
if arg[3] == "cron" then
if not fs.access("/var/lock/" .. appname .. ".lock") then
@@ -2484,10 +2485,10 @@ local execute = function()
local fail_list = {}
if arg[2] ~= "all" then
string.gsub(arg[2], '[^' .. "," .. ']+', function(w)
subscribe_list[#subscribe_list + 1] = uci:get_all(appname, w) or {}
subscribe_list[#subscribe_list + 1] = uci:get_all(c_config, w) or {}
end)
else
uci:foreach(appname, "subscribe_list", function(o)
uci:foreach(c_config, "subscribe_list", function(o)
subscribe_list[#subscribe_list + 1] = o
end)
end
@@ -2530,7 +2531,7 @@ local execute = function()
log(1, i18n.translatef("Subscription: [%s] No changes, no update required.", remark))
else
parse_link(raw_data, "2", remark, value)
uci:set(appname, cfgid, "md5", new_md5)
uci:set(c_config, cfgid, "md5", new_md5)
end
else
fail_list[#fail_list + 1] = value
@@ -2564,7 +2565,7 @@ local function check_instance(action)
os.exit(0)
else
luci.sys.call("touch " .. sub_lock)
uci:revert(appname)
uci:revert(c_config)
end
elseif action == "end" then
luci.sys.call("rm -f " .. sub_lock)
+2 -2
View File
@@ -8,8 +8,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xwan
PKG_VERSION:=1.0.0
PKG_RELEASE:=2
PKG_VERSION:=1.0.1
PKG_RELEASE:=3
PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE
+1 -1
View File
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
FOOTSTRAP_VERSION?=
ifneq ($(FOOTSTRAP_VERSION),)
PKG_VERSION:=$(FOOTSTRAP_VERSION)
PKG_RELEASE:=16
PKG_RELEASE:=17
endif
LUCI_TITLE:=Footstrap Theme
@@ -88,10 +88,10 @@ function clearViewIntervals() {
/* ONE line per document whatever went wrong: this runs on every navigation, and a router that
* cannot read L.Poll cannot read it on the next click either — a message per click would bury the
* console the user is reading it in. */
let _pollTimerWarned = false;
let _pollWarned = false;
function warnPollUnreadable(msg) {
if (_pollTimerWarned) return;
_pollTimerWarned = true;
if (_pollWarned) return;
_pollWarned = true;
console.error(msg);
}
@@ -301,11 +301,13 @@ function adoptMarkup(t, head) {
*
* The heading is COPIED, not invented: it is the text of the header cell in the same position, so
* the card says exactly what the column header says. Never overwrites an existing data-title — if
* the app set one, that is the app's answer and it knows more than a positional guess. Cheap enough
* to re-run on every fit pass (it is skipped entirely once the cells carry the attribute), which
* matters because these tables are POLLED: the rows are replaced wholesale every few seconds, and
* the fresh ones arrive without it. */
* the app set one, that is the app's answer and it knows more than a positional guess. Re-run on
* every fit pass, because these tables are POLLED: the rows are replaced wholesale every few
* seconds and the fresh ones arrive without the attribute. What keeps that affordable is the
* PER-ROW skip below: a captioned row is recognised from one cell instead of all of them, so a
* table LuCI captioned itself costs one attribute test per row and nothing else. */
function labelCells(t, head) {
const rows = t.querySelectorAll('.tr, tbody tr');
/* A `<thead>` that was WRITTEN as markup nests a real `<tr>` — the parser inserts one even where
* the author left it out — while one built by E() holds the `<th>`s directly (see above). Reading
* `head.children` blind therefore captioned every cell of a parsed table with the header row's
@@ -315,9 +317,30 @@ function labelCells(t, head) {
const titleRow = (head.firstElementChild && head.firstElementChild.tagName === 'TR') ? head.firstElementChild : head;
const titles = [ ...titleRow.children ].map((c) => (c.textContent || '').trim());
if (!titles.some(Boolean)) return;
for (const row of t.querySelectorAll('.tr, tbody tr')) {
for (const row of rows) {
if (row === head) continue;
const cells = row.children;
/* ---- SKIP A ROW THAT IS ALREADY CAPTIONED, ASKED OF THE ROW AND OF NOTHING ELSE ----
*
* A claimed table is revisited on every fit pass — a MUTATION pass, not a once-a-second one —
* so the common case has to be answered cheaply: everything LuCI renders is captioned by
* `ui.Table` as it builds it, and the walk could never find work there. Testing the row's FIRST
* cell answers that in one attribute read instead of one per cell.
*
* The row, rather than the table, is what carries the answer, and that is the whole point: a
* poll appends or replaces rows one at a time, and a table can hold captioned and bare rows at
* once. A table-level probe has to guess WHICH row speaks for the rest, and every choice is
* wrong for some shape — asking the last row stalls forever on a `<tfoot>` of per-column
* totals, which is captioned once and then never bare again while fresh rows keep arriving in
* the `<tbody>` above it (`t.rows` spans thead, tbody and tfoot, and the query above is in
* document order). Asked per row, there is nothing to guess: a fresh row has no caption and is
* walked, a captioned one is skipped, and cells replaced INSIDE a surviving row arrive bare and
* are walked too.
*
* A first cell that can never take a caption — one that spans columns, or whose header text is
* empty — leaves its row walked on every pass. That is the safe direction and it is bounded by
* the row, not the table: the walk is idempotent and writes nothing it has not been asked to. */
if (cells.length && cells[0].hasAttribute('data-title')) continue;
/* COLUMN cursor, not the cell index: a cell that spans N columns occupies N of the header's
* slots while advancing the cell index by one, so keying titles off `i` captioned every cell
* AFTER a spanning one with the heading of the column to its left — "Hostname" over an IP
@@ -172,13 +172,30 @@
.fs-themerow:hover {
background: var(--fs-panel2); color: var(--fs-text); opacity: 1;
}
.fs-sidebar ul.nav > li.active > a,
.fs-sidebar ul.nav > li > a.active,
.fs-sidebar ul.nav ul a.active,
.fs-themerow[aria-expanded="true"],
.fs-modemenu li.active a {
background: var(--fs-accent-soft); color: var(--fs-accent);
}
/* ---- THE FILL MARKS THE PAGE, AND A CATEGORY IS NOT A PAGE ----
*
* `li.active` is set on the SECTION that contains the current page as well as on the page's own
* row, so `li.active > a` used to hand the same accent plate to both — on System -> System that
* is two identical plates, one above the other, both reading "System" (issue #37). Measured
* before this rule: the open category and the current leaf were the same fill, the same ink and
* the same 13px/600, differing in 2px of padding.
*
* The markup already says which is which and this only makes the paint agree with it:
* menu-footstrap.js puts `aria-current="page"` on the LEAF alone, because a section header is a
* disclosure control rather than a link to where you are. So the plate stays with the page and
* the ancestor keeps the accent INK — still visibly the branch you are in, without competing
* with the page for the same signal — while an ancestor that is also the page itself is matched
* by `a.active` above and keeps the plate.
*
* Unscoped, like the rule above it: the accordion, the bar's dropdown and the rail's flyout all
* render one markup, and a per-layout copy is what the "one look, every layout" note is about. */
.fs-sidebar ul.nav > li.active > a:not(.active) { color: var(--fs-accent); }
/* Keyboard focus for the chrome controls. Covers the buttons/links the theme itself renders,
* which had only the UA default (menu links: base's thin dotted outline).
+23 -2
View File
@@ -378,7 +378,13 @@
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li > a {
display: flex; align-items: center; gap: var(--fs-space-3);
padding: var(--fs-space-2-5) var(--fs-space-3);
font-size: var(--fs-type); white-space: normal;
/* BOLD is the root level's own signal, and it is the one the type scale can promise:
* `--fs-weight-bold` has a face everywhere, while `--fs-weight-normal` is documented in
* 02-tokens.css as having none of its own — so lightening the CHILDREN instead would
* look like hierarchy on a system stack and like nothing at all on a router whose admin
* installed a 600/700 subset. Only the accordion is deep enough to need the distinction;
* the bar keeps one level of items and is left alone. */
font-size: var(--fs-type); font-weight: var(--fs-weight-bold); white-space: normal;
line-height: 1.1;
}
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li > a .fs-ico { display: block; }
@@ -407,7 +413,22 @@
* (below) is a popup again but flies its panel out sideways, and brings its own
* horizontal bridge (li.has-sub::after). */
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li.has-sub > ul::before { content: none; }
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li.open > ul { display: flex; margin: var(--fs-space-0-5) 0 var(--fs-space-1-5) var(--fs-space-7); }
/* ---- THE OPEN SECTION IS A GROUP, AND IT HAS TO LOOK LIKE ONE ----
*
* An indent alone did not say where a long section ended: after ten children, the next root
* category read as an eleventh child (issue #37). A hairline down the group's reading edge
* draws that boundary, and the wider bottom margin separates the last child from the next
* category — the two cues cost nothing but a border and 6px.
*
* No `:not([data-rail="true"])` guard: in the rail this same `ul` becomes a flyout card,
* whose rule (below) restates `border` and `margin` as shorthands at higher specificity, so
* neither declaration here survives into it. Checked in place rather than assumed. */
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li.open > ul {
display: flex;
margin: var(--fs-space-1) 0 var(--fs-space-3) var(--fs-space-7);
padding-inline-start: var(--fs-space-1);
border-inline-start: 1px solid var(--fs-border);
}
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav > li.has-sub.open > ul { display: flex; }
:root[data-layout="sidebar"]:not([data-narrow]) .fs-sidebar ul.nav ul a { padding: var(--fs-space-2) var(--fs-space-3); }
+4 -4
View File
@@ -1,14 +1,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=mihomo-alpha
PKG_VERSION:=2026.07.08
PKG_RELEASE:=18
PKG_VERSION:=2026.08.13
PKG_RELEASE:=19
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
PKG_SOURCE_VERSION:=cbd11db1e13a75d8e680e0fe7742c95be4cba2be
PKG_SOURCE_VERSION:=3cac869656f8ce2793afced148ebd5d4280b3e08
PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL3.0+
@@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=no-mips16
PKG_BUILD_VERSION:=alpha-cbd11db
PKG_BUILD_VERSION:=alpha-3cac869
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_TIME:=$(shell date -u -Iseconds)
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fastfetch
PKG_VERSION:=2.67.0
PKG_RELEASE:=13
PKG_VERSION:=2.67.1
PKG_RELEASE:=14
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?