diff --git a/dae/Makefile b/dae/Makefile index 27e7e3b8..5e551d25 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -10,7 +10,7 @@ PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=039adf5080465653d166b8c7428515dfa11431d9 +PKG_SOURCE_VERSION:=9b40cd67c1c6a799f28ee9879d43f7f5b527683f PKG_SOURCE_URL:=https://github.com/olicesx/dae.git PKG_MIRROR_HASH:=skip diff --git a/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js index 3f9d6470..61224808 100644 --- a/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js +++ b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js @@ -20,19 +20,31 @@ function is_timehhmm(str) { } if (typeof cbi_validators !== 'undefined' && cbi_validators !== null) { + cbi_validators['base64'] = function() { + return isBase64(this); + } cbi_validators['json'] = function() { return is_json(this); } cbi_validators['timehhmm'] = function() { return is_timehhmm(this); } + cbi_validators['uuid'] = function() { + return isUUID(this); + } } else { L.require('validation').then(function(validation) { + validation.types['base64'] = function() { + return this.assert(isBase64(this.value), _('Must be Base64 text!')); + } 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)')); } + validation.types['uuid'] = function() { + return this.assert(isUUID(this.value), _('Must be UUID format!')); + } }); } diff --git a/luci-app-passwall/htdocs/luci-static/resources/view/passwall/func.js b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/func.js index e7923077..8c9e27c8 100644 --- a/luci-app-passwall/htdocs/luci-static/resources/view/passwall/func.js +++ b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/func.js @@ -8,6 +8,11 @@ function arraysEqual(a, b) { return true; } +function isBase64(str) { + const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/; + return base64Regex.test(str); +} + function decodeIfBase64(str) { try { let s = str.replace(/-/g, '+').replace(/_/g, '/'); @@ -24,6 +29,11 @@ function decodeIfBase64(str) { return str; } +function isUUID(str) { + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + return uuidRegex.test(str); +} + function waitForElement(selector, callback) { const el = document.querySelector(selector); if (el) return callback(el); diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 7696f474..c4d5b1c4 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -56,6 +56,7 @@ function index() --[[ Server ]] entry({"admin", "services", appname, "server"}, cbi(appname .. "/server/index"), _("Server-Side"), 99).leaf = true entry({"admin", "services", appname, "server_config"}, cbi(appname .. "/server/server_config")).leaf = true + entry({"admin", "services", appname, "server_user_config"}, cbi(appname .. "/server/user_config")).leaf = true --[[ API ]] entry({"admin", "services", appname, "server_update_config"}, call("server_update_config")).leaf = true diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua index 46bf66e7..8399593f 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua @@ -18,37 +18,39 @@ e.default = "90" e.datatype = "range(0,600)" e.rmempty = false -t = m:section(TypedSection, "server", translate("Servers Manager")) -t.anonymous = true -t.addremove = true -t.sortable = true -t.template = "cbi/tblsection" -t.extedit = api.url("server_config", "%s") -function t.create(e, t) + +s_server = m:section(TypedSection, "server", translate("Servers Manager")) +s_server.anonymous = true +s_server.addremove = true +s_server.sortable = true +s_server.template = "cbi/tblsection" +s_server.extedit = api.url("server_config", "%s") +function s_server.create(self, section) local uid = api.gen_random_char() - TypedSection.create(e, uid) - luci.http.redirect(e.extedit:format(uid)) + TypedSection.create(self, uid) + luci.http.redirect(self.extedit:format(uid)) end -function t.remove(e, t) - e.map.proceed = true - e.map:del(t) - luci.http.redirect(api.url("server")) +function s_server.remove(self, section) + local o = m:get(section) or {} + if o[".type"] == self.sectiontype then + m:del(section) + end end -e = t:option(Flag, "enable", translate("Enable")) +e = s_server:option(Flag, "enable", translate("Enable")) e.width = "5%" e.rmempty = false -e = t:option(DummyValue, "status", translate("Status")) +e = s_server:option(DummyValue, "status", translate("Status")) e.rawhtml = true e.cfgvalue = function(t, n) return string.format('%s', translate("Collecting data...")) end -e = t:option(DummyValue, "remarks", translate("Remarks")) +e = s_server:option(DummyValue, "remarks", translate("Remarks")) e.width = "15%" -e = t:option(DummyValue, "type", translate("Type")) +e = s_server:option(DummyValue, "type", translate("Type")) e.width = "20%" e.rawhtml = true e.cfgvalue = function(t, n) @@ -86,24 +88,74 @@ e.cfgvalue = function(t, n) return str end -e = t:option(DummyValue, "port", translate("Port")) +e = s_server:option(DummyValue, "port", translate("Port")) -e = t:option(Flag, "log", translate("Log")) +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 = t.sectiontype +sortable.target_cfgname = s_server.sectiontype m:append(sortable) 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 = t.sectiontype +server_list_status.sectiontype = s_server.sectiontype m:append(server_list_status) +s_user = m:section(TypedSection, "user", translate("Users Manager")) +s_user.anonymous = true +s_user.addremove = true +s_user.sortable = true +s_user.template = "cbi/tblsection" +s_user.extedit = api.url("server_user_config", "%s") +s_user.create = function(e, section) + local uid = api.gen_random_char() + TypedSection.create(e, uid) + luci.http.redirect(e.extedit:format(uid)) +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) + if o.user and section == o.user then + m:set(o[".name"], "user", "") + end + local changed = false + local users = o.users or {} + for i = #users, 1, -1 do + if section == users[i] then + table.remove(users, i) + changed = true + end + end + if changed then + m:set(o[".name"], "users", users) + end + end) + m:del(section) + luci.http.redirect(api.url("server")) + end +end + +e = s_user:option(DummyValue, "username", translate("Username")) +e.width = "25%" + +e = s_user:option(DummyValue, "password", translate("Password")) +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:append(Template(appname .. "/server/log")) return api.return_map(m) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua index 89b70292..c810884c 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua @@ -20,7 +20,12 @@ m:append(header) m:append(Template(appname .. "/cbi/nodes_listvalue_com")) -s = m:section(NamedSection, arg[1], "user", "") +user_list = {} +m.uci:foreach(m.config, "user", function(s) + user_list[#user_list + 1] = s +end) + +s = m:section(NamedSection, arg[1], "server", "") s.addremove = false s.dynamic = false diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua index 661727d6..7e02c51b 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua @@ -28,6 +28,12 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o:depends({ [_n("custom")] = false }) +o = s:option(DynamicList, _n("users"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ [_n("custom")] = false }) + o = s:option(Flag, _n("realms"), translate("Realms")) o.default = "0" o.rewrite_option = o.option @@ -48,11 +54,6 @@ o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio o.rewrite_option = o.option o:depends({ [_n("realms")] = "1" }) -o = s:option(Value, _n("auth_password"), translate("Auth Password")) -o.password = true -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua index e97a5379..82c34a40 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua @@ -48,27 +48,18 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o:depends({ [_n("custom")] = false }) -o = s:option(Flag, _n("auth"), translate("Auth")) -o.validate = function(self, value, t) - if value and value == "1" then - local user_v = s.fields[_n("username")] and s.fields[_n("username")]:formvalue(t) or "" - local pass_v = s.fields[_n("password")] and s.fields[_n("password")]:formvalue(t) or "" - if user_v == "" or pass_v == "" then - return nil, translate("Username and Password must be used together!") - end - end - return value + +o = s:option(DynamicList, _n("users"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) end -o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "http" }) - -o = s:option(Value, _n("username"), translate("Username")) -o:depends({ [_n("auth")] = true }) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true -o:depends({ [_n("auth")] = true }) +o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "shadowsocks" }) +o:depends({ [_n("protocol")] = "vmess" }) +o:depends({ [_n("protocol")] = "vless" }) +o:depends({ [_n("protocol")] = "trojan" }) +o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol")) o:value("tcp", "TCP") @@ -97,6 +88,9 @@ o.rewrite_option = "method" for a, t in ipairs(x_ss_method_list) do o:value(t) end o:depends({ [_n("protocol")] = "shadowsocks" }) +o = s:option(Value, _n("ss_password"), translate("Password")) +o:depends({ [_n("protocol")] = "shadowsocks" }) + o = s:option(ListValue, _n("ss_network"), translate("Transport")) o.default = "tcp,udp" o:value("tcp", "TCP") @@ -109,14 +103,6 @@ o.default = "1" o.rmempty = false o:depends({ [_n("protocol")] = "socks" }) -o = s:option(DynamicList, _n("uuid"), translate("ID") .. "/" .. translate("Password")) -for i = 1, 3 do - o:value(api.gen_uuid()) -end -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) - o = s:option(ListValue, _n("flow"), translate("flow")) o.default = "" o:value("", translate("Disable")) @@ -141,10 +127,6 @@ o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ [_n("hysteria2_realms")] = "1" }) -o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) -o.password = true -o:depends({ [_n("protocol")] = "hysteria2"}) - o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua index 8ac9630e..dd13c4fc 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua @@ -60,35 +60,27 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o:depends({ [_n("custom")] = false }) -o = s:option(Flag, _n("auth"), translate("Auth")) -o.validate = function(self, value, t) - if value and value == "1" then - local user_v = s.fields[_n("username")] and s.fields[_n("username")]:formvalue(t) or "" - local pass_v = s.fields[_n("password")] and s.fields[_n("password")]:formvalue(t) or "" - if user_v == "" or pass_v == "" then - return nil, translate("Username and Password must be used together!") - end - end - return value +o = s:option(DynamicList, _n("users"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) end o:depends({ [_n("protocol")] = "mixed" }) o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "http" }) - -o = s:option(Value, _n("username"), translate("Username")) -o:depends({ [_n("auth")] = true }) -o:depends({ [_n("protocol")] = "naive" }) -o:depends({ [_n("protocol")] = "anytls" }) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true -o:depends({ [_n("auth")] = true }) o:depends({ [_n("protocol")] = "shadowsocks" }) +o:depends({ [_n("protocol")] = "vmess" }) +o:depends({ [_n("protocol")] = "vless" }) +o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "naive" }) +o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "tuic" }) +o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "anytls" }) if singbox_tags:find("with_quic") then + o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password")) + o:depends({ [_n("protocol")] = "hysteria" }) + o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps")) o.default = "100" o:depends({ [_n("protocol")] = "hysteria" }) @@ -97,20 +89,6 @@ if singbox_tags:find("with_quic") then o.default = "100" o:depends({ [_n("protocol")] = "hysteria" }) - o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(ListValue, _n("hysteria_auth_type"), translate("Auth Type")) - o:value("disable", translate("Disable")) - o:value("string", translate("STRING")) - o:value("base64", translate("BASE64")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_auth_password"), translate("Auth Password")) - o.password = true - o:depends({ [_n("protocol")] = "hysteria", [_n("hysteria_auth_type")] = "string"}) - o:depends({ [_n("protocol")] = "hysteria", [_n("hysteria_auth_type")] = "base64"}) - o = s:option(Value, _n("hysteria_recv_window_conn"), translate("QUIC stream receive window")) o:depends({ [_n("protocol")] = "hysteria" }) @@ -174,10 +152,6 @@ if singbox_tags:find("with_quic") then o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } o:depends({ [_n("hysteria2_realms")] = "1" }) - o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) - o.password = true - o:depends({ [_n("protocol")] = "hysteria2"}) - o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") @@ -233,14 +207,8 @@ o.rewrite_option = "method" for a, t in ipairs(ss_method_list) do o:value(t) end o:depends({ [_n("protocol")] = "shadowsocks" }) -o = s:option(DynamicList, _n("uuid"), translate("ID") .. "/" .. translate("Password")) -for i = 1, 3 do - o:value(api.gen_uuid()) -end -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "tuic" }) +o = s:option(Value, _n("ss_password"), translate("Password")) +o:depends({ [_n("protocol")] = "shadowsocks" }) o = s:option(ListValue, _n("flow"), translate("flow")) o.default = "" diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua index bfb00061..0e8632fc 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua @@ -27,22 +27,11 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o = s:option(Flag, _n("auth"), translate("Auth")) -o.validate = function(self, value, t) - if value and value == "1" then - local user_v = s.fields[_n("username")] and s.fields[_n("username")]:formvalue(t) or "" - local pass_v = s.fields[_n("password")] and s.fields[_n("password")]:formvalue(t) or "" - if user_v == "" or pass_v == "" then - return nil, translate("Username and Password must be used together!") - end - end - return value + +o = s:option(ListValue, _n("user"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) end - -o = s:option(Value, _n("username"), translate("Username")) -o:depends({ [_n("auth")] = true }) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true o:depends({ [_n("auth")] = true }) o = s:option(Flag, _n("log"), translate("Log")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua index 54b710ec..7ac9f03c 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua @@ -32,8 +32,10 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o:depends({ [_n("custom")] = false }) -o = s:option(Value, _n("password"), translate("Password")) -o.password = true +o = s:option(ListValue, _n("user"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("method"), translate("Encrypt Method")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua index d77cf74c..d1db102f 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua @@ -45,8 +45,10 @@ o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" o:depends({ [_n("custom")] = false }) -o = s:option(Value, _n("password"), translate("Password")) -o.password = true +o = s:option(ListValue, _n("user"), translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("method"), translate("Encrypt Method")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua new file mode 100644 index 00000000..8bbd351f --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua @@ -0,0 +1,31 @@ +api = require "luci.passwall.api" +appname = api.appname +fs = api.fs + +api.set_default_cbi() + +m = Map("passwall_server", translate("User 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.addremove = false +s.dynamic = false + +o = s:option(Value, "username", translate("Username")) +o.datatype = "and(uciname,maxlength(24))" +o.rmempty = false + +o = s:option(Value, "password", translate("Password")) +o.rmempty = false + +o = s:option(Value, "uuid", "UUID") +o.datatype = "uuid" +o.default = api.gen_uuid() +o.rmempty = false + +return api.return_map(m) diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 6193e1f9..553f0008 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -369,6 +369,12 @@ function is_timehhmm(str) end datatypes.timehhmm = is_timehhmm +function is_uuid(str) + local pattern = "^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$" + return string.match(str, pattern) ~= nil +end +datatypes.uuid = is_uuid + function is_normal_node(e) if e and e.type and e.protocol and (e.protocol == "_balancing" or e.protocol == "_shunt" or e.protocol == "_iface" or e.protocol == "_urltest") then return false diff --git a/luci-app-passwall/luasrc/passwall/server_app.lua b/luci-app-passwall/luasrc/passwall/server_app.lua index 321e7a19..e76f6a69 100644 --- a/luci-app-passwall/luasrc/passwall/server_app.lua +++ b/luci-app-passwall/luasrc/passwall/server_app.lua @@ -123,8 +123,12 @@ local function start() if type == "Socks" then local auth = "" if server.auth and server.auth == "1" then - local username = server.username or "" - local password = server.password or "" + local user = nil + if server.user then + user = uci:get_all("passwall_server", server.user) + end + local username = user and user.username or "" + local password = user and user.password or "" if username ~= "" and password ~= "" then username = "-u " .. username password = "-P " .. password diff --git a/luci-app-passwall/luasrc/passwall/util_hysteria2.lua b/luci-app-passwall/luasrc/passwall/util_hysteria2.lua index 8c43f811..f6f32739 100644 --- a/luci-app-passwall/luasrc/passwall/util_hysteria2.lua +++ b/luci-app-passwall/luasrc/passwall/util_hysteria2.lua @@ -4,6 +4,20 @@ local uci = api.uci local jsonc = api.jsonc function gen_config_server(node) + local users = node.users or {} + local users = nil + 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 {} + if user[".type"] == "user" then + users[user.username] = user.password + end + end + if not next(users) then + users = nil + end + end local config = { listen = (function() if node.hysteria2_realms and node.hysteria2_realm_url then @@ -25,10 +39,10 @@ function gen_config_server(node) password = node.hysteria2_obfs_password } } or nil, - auth = { - type = "password", - password = node.hysteria2_auth_password - }, + auth = users and { + type = "userpass", + userpass = users + } or nil, bandwidth = (node.hysteria2_up_mbps or node.hysteria2_down_mbps) and { up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or nil, down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or nil diff --git a/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua b/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua index 819b8278..23c8e21e 100644 --- a/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua +++ b/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua @@ -4,9 +4,13 @@ local uci = api.uci local jsonc = api.jsonc function gen_config_server(node) + local user = nil + if node.user then + user = uci:get_all("passwall2_server", node.user) + end local config = {} config.server_port = tonumber(node.port) - config.password = node.password + config.password = user and user.password or "" config.timeout = tonumber(node.timeout) config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false config.method = node.method diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index dbad6348..aff9b794 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -766,39 +766,71 @@ function gen_config_server(node) listen_port = tonumber(node.port), } + local users = node.users or {} + local users = nil + 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 {} + if user[".type"] == "user" then + local u = {} + if node.protocol == "mixed" or node.protocol == "socks" or node.protocol == "http" or node.protocol == "naive" then + u.username = user.username + u.password = user.password + end + if node.protocol == "shadowsocks" or node.protocol == "trojan" then + u.name = user.username + u.password = user.password + end + if node.protocol == "vmess" then + u.name = user.username + u.uuid = user.uuid + u.alterId = 0 + end + if node.protocol == "vless" then + u.name = user.username + u.uuid = user.uuid + u.flow = node.flow + end + if node.protocol == "hysteria" then + u.name = user.username + u.auth_str = user.password + end + if node.protocol == "tuic" then + u.name = user.username + u.password = user.password + u.uuid = user.uuid + end + if node.protocol == "hysteria2" then + u.name = user.username + u.password = user.password + end + users[#users + 1] = u + end + end + if #users == 0 then + users = nil + end + end + local protocol_table = nil if node.protocol == "mixed" then protocol_table = { - users = (node.auth == "1") and { - { - username = node.username, - password = node.password - } - } or nil, + users = users, set_system_proxy = false } end if node.protocol == "socks" then protocol_table = { - users = (node.auth == "1") and { - { - username = node.username, - password = node.password - } - } or nil + users = users } end if node.protocol == "http" then protocol_table = { - users = (node.auth == "1") and { - { - username = node.username, - password = node.password - } - } or nil, + users = users, tls = (node.tls == "1") and tls or nil, } end @@ -806,21 +838,14 @@ function gen_config_server(node) if node.protocol == "shadowsocks" then protocol_table = { method = node.method, - password = node.password, + password = node.ss_password, + users = users, multiplex = mux, } end if node.protocol == "vmess" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - name = node.uuid[i], - uuid = node.uuid[i], - alterId = 0, - } - end + if users then protocol_table = { users = users, tls = (node.tls == "1") and tls or nil, @@ -831,15 +856,7 @@ function gen_config_server(node) end if node.protocol == "vless" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - name = node.uuid[i], - uuid = node.uuid[i], - flow = node.flow, - } - end + if users then protocol_table = { users = users, tls = (node.tls == "1") and tls or nil, @@ -850,14 +867,7 @@ function gen_config_server(node) end if node.protocol == "trojan" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - name = node.uuid[i], - password = node.uuid[i], - } - end + if users then protocol_table = { users = users, tls = (node.tls == "1") and tls or nil, @@ -870,15 +880,12 @@ function gen_config_server(node) end if node.protocol == "naive" then - protocol_table = { - users = { - { - username = node.username, - password = node.password - } - }, - tls = tls, - } + if users then + protocol_table = { + users = users, + tls = tls + } + end end if node.protocol == "hysteria" then @@ -888,13 +895,7 @@ function gen_config_server(node) up_mbps = tonumber(node.hysteria_up_mbps), down_mbps = tonumber(node.hysteria_down_mbps), obfs = node.hysteria_obfs, - users = { - { - name = "user1", - auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil, - auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil, - } - }, + users = users, recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, --1.14 to stream_receive_window recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, --1.14 to connection_receive_window max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, --1.14 to max_concurrent_streams @@ -904,31 +905,21 @@ function gen_config_server(node) end if node.protocol == "tuic" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - name = node.uuid[i], - uuid = node.uuid[i], - password = node.password - } - end - tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "default") and (function() - local alpn = {} - string.gsub(node.tuic_alpn, '[^,]+', function(w) - table.insert(alpn, w) - end) - if #alpn > 0 then return alpn end - return nil - end)() or nil - protocol_table = { - users = users, - congestion_control = node.tuic_congestion_control or "cubic", - zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false, - heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s", - tls = tls - } - end + tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "default") and (function() + local alpn = {} + string.gsub(node.tuic_alpn, '[^,]+', function(w) + table.insert(alpn, w) + end) + if #alpn > 0 then return alpn end + return nil + end)() or nil + protocol_table = { + users = users, + congestion_control = node.tuic_congestion_control or "cubic", + zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false, + heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s", + tls = tls + } end if node.protocol == "hysteria2" then @@ -953,12 +944,7 @@ function gen_config_server(node) end return o end)(node.hysteria2_obfs_type), - users = { - { - name = "user1", - password = node.hysteria2_auth_password or nil, - } - }, + users = users, ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false, tls = tls, realm = node.hysteria2_realms and (function() @@ -978,15 +964,12 @@ function gen_config_server(node) end if node.protocol == "anytls" then - protocol_table = { - users = { - { - name = (node.username and node.username ~= "") and node.username or "sekai", - password = node.password - } - }, - tls = tls, - } + if users then + protocol_table = { + users = users, + tls = tls, + } + end end if node.protocol == "direct" then diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 862e56ca..95c1ae06 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -488,17 +488,46 @@ function gen_config_server(node) { protocol = "freedom", tag = "direct", settings = { finalRules = {{ action = "allow" }}}}, { protocol = "blackhole", tag = "blocked" } } - if node.protocol == "vmess" or node.protocol == "vless" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - id = node.uuid[i], - flow = (node.protocol == "vless" - and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none")) - and node.flow and node.flow ~= "") and node.flow or nil - } + local users = node.users or {} + local users = nil + 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 {} + if user[".type"] == "user" then + local u = {} + if node.protocol == "socks" or node.protocol == "http" then + u.user = user.username + u.pass = user.password + end + if node.protocol == "shadowsocks" or node.protocol == "trojan" then + u.email = user.username + u.password = user.password + end + if node.protocol == "vmess" then + u.email = user.username + u.id = user.uuid + u.alterId = 0 + end + if node.protocol == "vless" then + u.email = user.username + u.id = user.uuid + u.flow = node.flow + end + if node.protocol == "hysteria2" then + u.email = user.username + u.auth = user.password + end + users[#users + 1] = u end + end + if #users == 0 then + users = nil + end + end + + if node.protocol == "vmess" or node.protocol == "vless" then + if users then settings = { users = users, decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil @@ -507,40 +536,25 @@ function gen_config_server(node) elseif node.protocol == "socks" then settings = { udp = ("1" == node.udp_forward) and true or false, - auth = ("1" == node.auth) and "password" or "noauth", - users = ("1" == node.auth) and { - { - user = node.username, - pass = node.password - } - } or nil + auth = users and "password" or "noauth", + users = users } elseif node.protocol == "http" then settings = { allowTransparent = false, - users = ("1" == node.auth) and { - { - user = node.username, - pass = node.password - } - } or nil + users = users } node.transport = "tcp" node.tcp_guise = "none" elseif node.protocol == "shadowsocks" then settings = { method = node.method, - password = node.password, - network = node.ss_network or "TCP,UDP" + password = node.ss_password, + users = users, + network = node.ss_network or "tcp,udp" } elseif node.protocol == "trojan" then - if node.uuid then - local users = {} - for i = 1, #node.uuid do - users[i] = { - password = node.uuid[i], - } - end + if users then settings = { users = users } @@ -548,9 +562,7 @@ function gen_config_server(node) elseif node.protocol == "hysteria2" then settings = { version = 2, - users = node.hysteria2_auth_password and { - { auth = node.hysteria2_auth_password } - } + users = users } elseif node.protocol == "dokodemo-door" then settings = { diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 98cd9371..55db06d5 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1628,6 +1628,9 @@ msgstr "服务器管理" msgid "Users Manager" msgstr "用户管理" +msgid "User Config" +msgstr "用户配置" + msgid "Logs" msgstr "日志" @@ -2064,9 +2067,15 @@ msgstr "使用自定义配置" msgid "Custom Config" msgstr "自定义配置" +msgid "Must be Base64 text!" +msgstr "必须是 Base64 内容!" + msgid "Must be JSON text!" msgstr "必须是 JSON 文本内容!" +msgid "Must be UUID format!" +msgstr "必须是 UUID 格式!" + msgid "Geo View" msgstr "Geo 查询"