diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 79fdd5ee..6a80b3bb 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.7.12 +PKG_VERSION:=26.7.16 PKG_RELEASE:=1 PKG_PO_VERSION:=$(PKG_VERSION) diff --git a/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/cbi.js b/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/cbi.js new file mode 100644 index 00000000..3f9d6470 --- /dev/null +++ b/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/cbi.js @@ -0,0 +1,38 @@ +function is_json(str) { + try { + const result = JSON.parse(str); + return typeof result === 'object' && result !== null; + } catch (e) { + return false; + } +} + +function is_timehhmm(str) { + const match = String(str).match(/^(\d?\d):(\d\d)$/); + if (match) { + const hour = parseInt(match[1], 10); + const minute = parseInt(match[2], 10); + if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59) { + return true; + } + } + return false; +} + +if (typeof cbi_validators !== 'undefined' && cbi_validators !== null) { + cbi_validators['json'] = function() { + return is_json(this); + } + cbi_validators['timehhmm'] = function() { + return is_timehhmm(this); + } +} else { + L.require('validation').then(function(validation) { + validation.types['json'] = function() { + return this.assert(is_json(this.value), _('Must be JSON text!')); + } + validation.types['timehhmm'] = function() { + return this.assert(is_timehhmm(this.value), _('valid time (hh:mm)')); + } + }); +} diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index a2bc949a..1fac463a 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -113,6 +113,8 @@ function index() --[[geoview]] entry({"admin", "services", appname, "geo_view"}, call("geo_view")).leaf = true + + entry({"admin", "services", appname, "fetch_certsha256"}, call("fetch_certsha256")).leaf = true end local function http_write_json(content) @@ -939,3 +941,17 @@ function flush_set() http.redirect(api.url("log")) end 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 "" + sni = (sni ~= "") and sni or address + if address == "" or port == 0 then + http_write_json_error() + return + end + local data = api.fetch_cert_sha256(address, port, sni, 5) + http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 }) +end diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl.lua index 3df0c9f7..0b815a51 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl.lua @@ -2,6 +2,8 @@ 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) @@ -13,7 +15,8 @@ o.rmempty = false o.default = false -- [[ ACLs Settings ]]-- -s = m:section(TypedSection, "acl_rule") +local cfgname = "acl_rule" +s = m:section(TypedSection, cfgname) s.template = "cbi/tblsection" s.sortable = true s.anonymous = true @@ -65,4 +68,9 @@ i.cfgvalue = function(t, n) return v end -return m +local sortable = Template(appname .. "/cbi/sortable") +sortable.api = api +sortable.target_cfgname = cfgname +m:append(sortable) + +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua index b8b77501..b366d623 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua @@ -1,6 +1,8 @@ local api = require "luci.passwall2.api" local appname = api.appname +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -379,4 +381,4 @@ for k, v in pairs(nodes_table) do end end -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua index afdef1b9..462046e3 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua @@ -2,6 +2,8 @@ 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) @@ -28,4 +30,4 @@ o.cfgvalue = function(t, n) return string.format('%s', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually.")) end -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/geoview.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/geoview.lua index 071d8e80..abd9c1f1 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/geoview.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/geoview.lua @@ -1,5 +1,5 @@ local api = require "luci.passwall2.api" -local appname = "passwall2" +local appname = api.appname local fs = api.fs local uci = api.uci diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index 6195b0bd..7e0e4a82 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -4,6 +4,8 @@ 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) @@ -386,4 +388,4 @@ footer.shunt_list = api.jsonc.stringify(shunt_list) m:append(footer) -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua index 6a8732ee..06dad374 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua @@ -15,6 +15,8 @@ for k, e in ipairs(api.get_valid_nodes()) do end end +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -100,7 +102,8 @@ end o:depends("health_check_type", "passwall_logic") -- [[ Balancing Settings ]]-- -s = m:section(TypedSection, "haproxy_config", translate("Node List")) +local cfgname = "haproxy_config" +s = m:section(TypedSection, cfgname, translate("Node List")) s.description = "" .. 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.") .. "
" .. 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!") .. "
" @@ -176,6 +179,11 @@ 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:append(Template(appname .. "/haproxy/js")) -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_config.lua index 5051bd7b..ead7043f 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_config.lua @@ -1,6 +1,8 @@ api = require "luci.passwall2.api" appname = api.appname +api.set_default_cbi() + m = Map(appname, translate("Node Config")) m.redirect = api.url() api.set_apply_on_parse(m) @@ -94,7 +96,6 @@ local footer = Template(appname .. "/node_config/footer") footer.api = api footer.config = m.config footer.section = arg[1] - m:append(footer) -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_list.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_list.lua index 745188de..37fb1867 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_list.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_list.lua @@ -3,6 +3,8 @@ local appname = api.appname local datatypes = api.datatypes local sys = api.sys +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -33,4 +35,4 @@ s:append(Template(appname .. "/node_list/link_add_node")) m:append(Template(appname .. "/node_list/node_list")) -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe.lua index 7140ac5c..6ffdd44a 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe.lua @@ -38,6 +38,8 @@ if has_hysteria2 then table.insert(hysteria2_type, s) end +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -124,7 +126,8 @@ o.cfgvalue = function(self, section) translate("Manual subscription All")) end -s = m:section(TypedSection, "subscribe_list", "", "" .. 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.") .. "") +local cfgname = "subscribe_list" +s = m:section(TypedSection, cfgname, "", "" .. 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.") .. "") s.addremove = true s.anonymous = true s.sortable = true @@ -144,7 +147,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.uci:foreach(appname, cfgname, function(e) if e[".name"] ~= section and e["remark"] and e["remark"]:lower() == value:lower() then duplicate = true return false @@ -219,6 +222,11 @@ 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:append(Template(appname .. "/node_subscribe/js")) -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua index b5068ccc..198e19bc 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua @@ -1,6 +1,8 @@ local api = require "luci.passwall2.api" local appname = api.appname +api.set_default_cbi() + m = Map(appname) m.redirect = api.url("node_subscribe") api.set_apply_on_parse(m) @@ -255,13 +257,7 @@ for t = 0, 23 do end end o.default = "0:00" -o.validate = function(self, value) - local b = api.is_timehhmm(value) - if b then - return value - end - return nil -end +o.datatype = "timehhmm" o:depends("update_week_mode", "0") o:depends("update_week_mode", "1") o:depends("update_week_mode", "2") @@ -336,4 +332,4 @@ o.description = translate("Some subscription providers may require a hardware id translate("Enabling this option will send a hashed HWID when updating subscriptions.") .. "
" .. translate("This may reveal limited hardware information. Enable only if you trust your provider.") -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua index a715756c..b46db196 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua @@ -8,6 +8,8 @@ local port_validate = function(self, value, t) return value:gsub("-", ":") end +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -53,13 +55,7 @@ for index, value in ipairs({"stop", "start", "restart"}) do end end o.default = "0:00" - o.validate = function(self, value) - local b = api.is_timehhmm(value) - if b then - return value - end - return nil - end + o.datatype = "timehhmm" o:depends(value .. "_week_mode", "0") o:depends(value .. "_week_mode", "1") o:depends(value .. "_week_mode", "2") @@ -312,4 +308,4 @@ if has_singbox then o.default = 0 end -return m +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua index 2fba7319..e0b65f42 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua @@ -1,6 +1,8 @@ local api = require "luci.passwall2.api" local appname = api.appname +api.set_default_cbi() + m = Map(appname) api.set_apply_on_parse(m) @@ -59,13 +61,7 @@ for t = 0, 23 do end end o.default = "0:00" -o.validate = function(self, value) - local b = api.is_timehhmm(value) - if b then - return value - end - return nil -end +o.datatype = "timehhmm" o:depends("update_week_mode", "0") o:depends("update_week_mode", "1") o:depends("update_week_mode", "2") @@ -92,7 +88,8 @@ end s:append(Template(appname .. "/rule/rule_version")) -s = m:section(TypedSection, "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"), "" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "") +local cfgname = "shunt_rules" +s = m:section(TypedSection, cfgname, "Sing-Box/Xray " .. translate("Shunt Rule"), "" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "") s.template = "cbi/tblsection" s.anonymous = false s.addremove = true @@ -113,4 +110,9 @@ end o = s:option(DummyValue, "remarks", translate("Remarks")) -return m +local sortable = Template(appname .. "/cbi/sortable") +sortable.api = api +sortable.target_cfgname = cfgname +m:append(sortable) + +return api.return_map(m) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua index e154fa84..f7035984 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua @@ -2,6 +2,8 @@ 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")) m.redirect = api.url("rule") api.set_apply_on_parse(m) @@ -248,4 +250,4 @@ ip_list.description = "