update 2026-08-13 20:57:15

This commit is contained in:
action committed 2026-08-13 20:57:15 +08:00
1 parent 90a7fd0798
commit 172837898d
20 files changed
+332 -245

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@ PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=039adf5080465653d166b8c7428515dfa11431d9 PKG_SOURCE_VERSION:=9b40cd67c1c6a799f28ee9879d43f7f5b527683f
PKG_SOURCE_URL:=https://github.com/olicesx/dae.git PKG_SOURCE_URL:=https://github.com/olicesx/dae.git
PKG_MIRROR_HASH:=skip PKG_MIRROR_HASH:=skip
@@ -20,19 +20,31 @@ function is_timehhmm(str) {
} }
if (typeof cbi_validators !== 'undefined' && cbi_validators !== null) { if (typeof cbi_validators !== 'undefined' && cbi_validators !== null) {
cbi_validators['base64'] = function() {
return isBase64(this);
}
cbi_validators['json'] = function() { cbi_validators['json'] = function() {
return is_json(this); return is_json(this);
} }
cbi_validators['timehhmm'] = function() { cbi_validators['timehhmm'] = function() {
return is_timehhmm(this); return is_timehhmm(this);
} }
cbi_validators['uuid'] = function() {
return isUUID(this);
}
} else { } else {
L.require('validation').then(function(validation) { L.require('validation').then(function(validation) {
validation.types['base64'] = function() {
return this.assert(isBase64(this.value), _('Must be Base64 text!'));
}
validation.types['json'] = function() { validation.types['json'] = function() {
return this.assert(is_json(this.value), _('Must be JSON text!')); return this.assert(is_json(this.value), _('Must be JSON text!'));
} }
validation.types['timehhmm'] = function() { validation.types['timehhmm'] = function() {
return this.assert(is_timehhmm(this.value), _('valid time (hh:mm)')); 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!'));
}
}); });
} }
@@ -8,6 +8,11 @@ function arraysEqual(a, b) {
return true; 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) { function decodeIfBase64(str) {
try { try {
let s = str.replace(/-/g, '+').replace(/_/g, '/'); let s = str.replace(/-/g, '+').replace(/_/g, '/');
@@ -24,6 +29,11 @@ function decodeIfBase64(str) {
return 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) { function waitForElement(selector, callback) {
const el = document.querySelector(selector); const el = document.querySelector(selector);
if (el) return callback(el); if (el) return callback(el);
@@ -56,6 +56,7 @@ function index()
--[[ Server ]] --[[ Server ]]
entry({"admin", "services", appname, "server"}, cbi(appname .. "/server/index"), _("Server-Side"), 99).leaf = true 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_config"}, cbi(appname .. "/server/server_config")).leaf = true
entry({"admin", "services", appname, "server_user_config"}, cbi(appname .. "/server/user_config")).leaf = true
--[[ API ]] --[[ API ]]
entry({"admin", "services", appname, "server_update_config"}, call("server_update_config")).leaf = true entry({"admin", "services", appname, "server_update_config"}, call("server_update_config")).leaf = true
@@ -18,37 +18,39 @@ e.default = "90"
e.datatype = "range(0,600)" e.datatype = "range(0,600)"
e.rmempty = false e.rmempty = false
t = m:section(TypedSection, "server", translate("Servers Manager"))
t.anonymous = true s_server = m:section(TypedSection, "server", translate("Servers Manager"))
t.addremove = true s_server.anonymous = true
t.sortable = true s_server.addremove = true
t.template = "cbi/tblsection" s_server.sortable = true
t.extedit = api.url("server_config", "%s") s_server.template = "cbi/tblsection"
function t.create(e, t) s_server.extedit = api.url("server_config", "%s")
function s_server.create(self, section)
local uid = api.gen_random_char() local uid = api.gen_random_char()
TypedSection.create(e, uid) TypedSection.create(self, uid)
luci.http.redirect(e.extedit:format(uid)) luci.http.redirect(self.extedit:format(uid))
end
function s_server.remove(self, section)
local o = m:get(section) or {}
if o[".type"] == self.sectiontype then
m:del(section)
end end
function t.remove(e, t)
e.map.proceed = true
e.map:del(t)
luci.http.redirect(api.url("server"))
end end
e = t:option(Flag, "enable", translate("Enable")) e = s_server:option(Flag, "enable", translate("Enable"))
e.width = "5%" e.width = "5%"
e.rmempty = false e.rmempty = false
e = t:option(DummyValue, "status", translate("Status")) e = s_server:option(DummyValue, "status", translate("Status"))
e.rawhtml = true e.rawhtml = true
e.cfgvalue = function(t, n) e.cfgvalue = function(t, n)
return string.format('<font class="_servers_status">%s</font>', translate("Collecting data...")) return string.format('<font class="_servers_status">%s</font>', translate("Collecting data..."))
end end
e = t:option(DummyValue, "remarks", translate("Remarks")) e = s_server:option(DummyValue, "remarks", translate("Remarks"))
e.width = "15%" e.width = "15%"
e = t:option(DummyValue, "type", translate("Type")) e = s_server:option(DummyValue, "type", translate("Type"))
e.width = "20%" e.width = "20%"
e.rawhtml = true e.rawhtml = true
e.cfgvalue = function(t, n) e.cfgvalue = function(t, n)
@@ -86,24 +88,74 @@ e.cfgvalue = function(t, n)
return str return str
end 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.default = "1"
e.rmempty = false e.rmempty = false
local sortable = Template(appname .. "/cbi/sortable") local sortable = Template(appname .. "/cbi/sortable")
sortable.api = api sortable.api = api
sortable.appname = m.config sortable.appname = m.config
sortable.target_cfgname = t.sectiontype sortable.target_cfgname = s_server.sectiontype
m:append(sortable) m:append(sortable)
local server_list_status = Template(appname .. "/server/server_list_status") local server_list_status = Template(appname .. "/server/server_list_status")
server_list_status.api = api server_list_status.api = api
server_list_status.appname = m.config server_list_status.appname = m.config
server_list_status.sectiontype = t.sectiontype server_list_status.sectiontype = s_server.sectiontype
m:append(server_list_status) 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")) m:append(Template(appname .. "/server/log"))
return api.return_map(m) return api.return_map(m)
@@ -20,7 +20,12 @@ m:append(header)
m:append(Template(appname .. "/cbi/nodes_listvalue_com")) 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.addremove = false
s.dynamic = false s.dynamic = false
@@ -28,6 +28,12 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false }) 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 = s:option(Flag, _n("realms"), translate("Realms"))
o.default = "0" o.default = "0"
o.rewrite_option = o.option 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.rewrite_option = o.option
o:depends({ [_n("realms")] = "1" }) 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 = s:option(ListValue, _n("obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable")) o:value("", translate("Disable"))
o:value("salamander") o:value("salamander")
@@ -48,27 +48,18 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth"))
o.validate = function(self, value, t) o = s:option(DynamicList, _n("users"), translate("User"))
if value and value == "1" then for i, v in ipairs(user_list) do
local user_v = s.fields[_n("username")] and s.fields[_n("username")]:formvalue(t) or "" o:value(v[".name"], v.username)
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
end
return value
end
o:depends({ [_n("protocol")] = "socks" })
o:depends({ [_n("protocol")] = "http" }) o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "socks" })
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")] = "shadowsocks" }) 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 = s:option(ListValue, _n("d_protocol"), translate("Destination protocol"))
o:value("tcp", "TCP") 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 for a, t in ipairs(x_ss_method_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocks" }) 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 = s:option(ListValue, _n("ss_network"), translate("Transport"))
o.default = "tcp,udp" o.default = "tcp,udp"
o:value("tcp", "TCP") o:value("tcp", "TCP")
@@ -109,14 +103,6 @@ o.default = "1"
o.rmempty = false o.rmempty = false
o:depends({ [_n("protocol")] = "socks" }) 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 = s:option(ListValue, _n("flow"), translate("flow"))
o.default = "" o.default = ""
o:value("", translate("Disable")) 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.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ [_n("hysteria2_realms")] = "1" }) 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 = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable")) o:value("", translate("Disable"))
o:value("salamander") o:value("salamander")
@@ -60,35 +60,27 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth")) o = s:option(DynamicList, _n("users"), translate("User"))
o.validate = function(self, value, t) for i, v in ipairs(user_list) do
if value and value == "1" then o:value(v[".name"], v.username)
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
end end
o:depends({ [_n("protocol")] = "mixed" }) o:depends({ [_n("protocol")] = "mixed" })
o:depends({ [_n("protocol")] = "socks" }) o:depends({ [_n("protocol")] = "socks" })
o:depends({ [_n("protocol")] = "http" }) 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")] = "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")] = "naive" })
o:depends({ [_n("protocol")] = "hysteria" })
o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o:depends({ [_n("protocol")] = "anytls" }) o:depends({ [_n("protocol")] = "anytls" })
if singbox_tags:find("with_quic") then 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 = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps"))
o.default = "100" o.default = "100"
o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "hysteria" })
@@ -97,20 +89,6 @@ if singbox_tags:find("with_quic") then
o.default = "100" o.default = "100"
o:depends({ [_n("protocol")] = "hysteria" }) 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 = s:option(Value, _n("hysteria_recv_window_conn"), translate("QUIC stream receive window"))
o:depends({ [_n("protocol")] = "hysteria" }) 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.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ [_n("hysteria2_realms")] = "1" }) 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 = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable")) o:value("", translate("Disable"))
o:value("salamander") o:value("salamander")
@@ -233,14 +207,8 @@ o.rewrite_option = "method"
for a, t in ipairs(ss_method_list) do o:value(t) end for a, t in ipairs(ss_method_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocks" }) o:depends({ [_n("protocol")] = "shadowsocks" })
o = s:option(DynamicList, _n("uuid"), translate("ID") .. "/" .. translate("Password")) o = s:option(Value, _n("ss_password"), translate("Password"))
for i = 1, 3 do o:depends({ [_n("protocol")] = "shadowsocks" })
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(ListValue, _n("flow"), translate("flow")) o = s:option(ListValue, _n("flow"), translate("flow"))
o.default = "" o.default = ""
@@ -27,22 +27,11 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o = s:option(Flag, _n("auth"), translate("Auth")) 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
end
o = s:option(Value, _n("username"), translate("Username")) o = s:option(ListValue, _n("user"), translate("User"))
o:depends({ [_n("auth")] = true }) for i, v in ipairs(user_list) do
o:value(v[".name"], v.username)
o = s:option(Value, _n("password"), translate("Password")) end
o.password = true
o:depends({ [_n("auth")] = true }) o:depends({ [_n("auth")] = true })
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
@@ -32,8 +32,10 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(ListValue, _n("user"), translate("User"))
o.password = true for i, v in ipairs(user_list) do
o:value(v[".name"], v.username)
end
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method")) o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
@@ -45,8 +45,10 @@ o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(ListValue, _n("user"), translate("User"))
o.password = true for i, v in ipairs(user_list) do
o:value(v[".name"], v.username)
end
o:depends({ [_n("custom")] = false }) o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method")) o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
@@ -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)
@@ -369,6 +369,12 @@ function is_timehhmm(str)
end end
datatypes.timehhmm = is_timehhmm 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) 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 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 return false
@@ -123,8 +123,12 @@ local function start()
if type == "Socks" then if type == "Socks" then
local auth = "" local auth = ""
if server.auth and server.auth == "1" then if server.auth and server.auth == "1" then
local username = server.username or "" local user = nil
local password = server.password or "" 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 if username ~= "" and password ~= "" then
username = "-u " .. username username = "-u " .. username
password = "-P " .. password password = "-P " .. password
@@ -4,6 +4,20 @@ local uci = api.uci
local jsonc = api.jsonc local jsonc = api.jsonc
function gen_config_server(node) 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 = { local config = {
listen = (function() listen = (function()
if node.hysteria2_realms and node.hysteria2_realm_url then if node.hysteria2_realms and node.hysteria2_realm_url then
@@ -25,10 +39,10 @@ function gen_config_server(node)
password = node.hysteria2_obfs_password password = node.hysteria2_obfs_password
} }
} or nil, } or nil,
auth = { auth = users and {
type = "password", type = "userpass",
password = node.hysteria2_auth_password userpass = users
}, } or nil,
bandwidth = (node.hysteria2_up_mbps or node.hysteria2_down_mbps) and { bandwidth = (node.hysteria2_up_mbps or node.hysteria2_down_mbps) and {
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or nil, 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 down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or nil
@@ -4,9 +4,13 @@ local uci = api.uci
local jsonc = api.jsonc local jsonc = api.jsonc
function gen_config_server(node) function gen_config_server(node)
local user = nil
if node.user then
user = uci:get_all("passwall2_server", node.user)
end
local config = {} local config = {}
config.server_port = tonumber(node.port) config.server_port = tonumber(node.port)
config.password = node.password config.password = user and user.password or ""
config.timeout = tonumber(node.timeout) config.timeout = tonumber(node.timeout)
config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false
config.method = node.method config.method = node.method
@@ -766,39 +766,71 @@ function gen_config_server(node)
listen_port = tonumber(node.port), 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 local protocol_table = nil
if node.protocol == "mixed" then if node.protocol == "mixed" then
protocol_table = { protocol_table = {
users = (node.auth == "1") and { users = users,
{
username = node.username,
password = node.password
}
} or nil,
set_system_proxy = false set_system_proxy = false
} }
end end
if node.protocol == "socks" then if node.protocol == "socks" then
protocol_table = { protocol_table = {
users = (node.auth == "1") and { users = users
{
username = node.username,
password = node.password
}
} or nil
} }
end end
if node.protocol == "http" then if node.protocol == "http" then
protocol_table = { protocol_table = {
users = (node.auth == "1") and { users = users,
{
username = node.username,
password = node.password
}
} or nil,
tls = (node.tls == "1") and tls or nil, tls = (node.tls == "1") and tls or nil,
} }
end end
@@ -806,21 +838,14 @@ function gen_config_server(node)
if node.protocol == "shadowsocks" then if node.protocol == "shadowsocks" then
protocol_table = { protocol_table = {
method = node.method, method = node.method,
password = node.password, password = node.ss_password,
users = users,
multiplex = mux, multiplex = mux,
} }
end end
if node.protocol == "vmess" then if node.protocol == "vmess" then
if node.uuid then if users then
local users = {}
for i = 1, #node.uuid do
users[i] = {
name = node.uuid[i],
uuid = node.uuid[i],
alterId = 0,
}
end
protocol_table = { protocol_table = {
users = users, users = users,
tls = (node.tls == "1") and tls or nil, tls = (node.tls == "1") and tls or nil,
@@ -831,15 +856,7 @@ function gen_config_server(node)
end end
if node.protocol == "vless" then if node.protocol == "vless" then
if node.uuid then if users then
local users = {}
for i = 1, #node.uuid do
users[i] = {
name = node.uuid[i],
uuid = node.uuid[i],
flow = node.flow,
}
end
protocol_table = { protocol_table = {
users = users, users = users,
tls = (node.tls == "1") and tls or nil, tls = (node.tls == "1") and tls or nil,
@@ -850,14 +867,7 @@ function gen_config_server(node)
end end
if node.protocol == "trojan" then if node.protocol == "trojan" then
if node.uuid then if users then
local users = {}
for i = 1, #node.uuid do
users[i] = {
name = node.uuid[i],
password = node.uuid[i],
}
end
protocol_table = { protocol_table = {
users = users, users = users,
tls = (node.tls == "1") and tls or nil, tls = (node.tls == "1") and tls or nil,
@@ -870,16 +880,13 @@ function gen_config_server(node)
end end
if node.protocol == "naive" then if node.protocol == "naive" then
if users then
protocol_table = { protocol_table = {
users = { users = users,
{ tls = tls
username = node.username,
password = node.password
}
},
tls = tls,
} }
end end
end
if node.protocol == "hysteria" then if node.protocol == "hysteria" then
protocol_table = { protocol_table = {
@@ -888,13 +895,7 @@ function gen_config_server(node)
up_mbps = tonumber(node.hysteria_up_mbps), up_mbps = tonumber(node.hysteria_up_mbps),
down_mbps = tonumber(node.hysteria_down_mbps), down_mbps = tonumber(node.hysteria_down_mbps),
obfs = node.hysteria_obfs, obfs = node.hysteria_obfs,
users = { users = 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,
}
},
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_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 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 max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, --1.14 to max_concurrent_streams
@@ -904,15 +905,6 @@ function gen_config_server(node)
end end
if node.protocol == "tuic" then 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() tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "default") and (function()
local alpn = {} local alpn = {}
string.gsub(node.tuic_alpn, '[^,]+', function(w) string.gsub(node.tuic_alpn, '[^,]+', function(w)
@@ -929,7 +921,6 @@ function gen_config_server(node)
tls = tls tls = tls
} }
end end
end
if node.protocol == "hysteria2" then if node.protocol == "hysteria2" then
protocol_table = { protocol_table = {
@@ -953,12 +944,7 @@ function gen_config_server(node)
end end
return o return o
end)(node.hysteria2_obfs_type), end)(node.hysteria2_obfs_type),
users = { users = users,
{
name = "user1",
password = node.hysteria2_auth_password or nil,
}
},
ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false, ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false,
tls = tls, tls = tls,
realm = node.hysteria2_realms and (function() realm = node.hysteria2_realms and (function()
@@ -978,16 +964,13 @@ function gen_config_server(node)
end end
if node.protocol == "anytls" then if node.protocol == "anytls" then
if users then
protocol_table = { protocol_table = {
users = { users = users,
{
name = (node.username and node.username ~= "") and node.username or "sekai",
password = node.password
}
},
tls = tls, tls = tls,
} }
end end
end
if node.protocol == "direct" then if node.protocol == "direct" then
protocol_table = { protocol_table = {
+47 -35
View File
@@ -488,17 +488,46 @@ function gen_config_server(node)
{ protocol = "freedom", tag = "direct", settings = { finalRules = {{ action = "allow" }}}}, { protocol = "blackhole", tag = "blocked" } { protocol = "freedom", tag = "direct", settings = { finalRules = {{ action = "allow" }}}}, { protocol = "blackhole", tag = "blocked" }
} }
if node.protocol == "vmess" or node.protocol == "vless" then local users = node.users or {}
if node.uuid then local users = nil
local users = {} if node.users and #node.users > 0 then
for i = 1, #node.uuid do users = {}
users[i] = { for i, v in ipairs(node.users) do
id = node.uuid[i], local user = uci:get_all("passwall2_server", v) or {}
flow = (node.protocol == "vless" if user[".type"] == "user" then
and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none")) local u = {}
and node.flow and node.flow ~= "") and node.flow or nil if node.protocol == "socks" or node.protocol == "http" then
} u.user = user.username
u.pass = user.password
end 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 = { settings = {
users = users, users = users,
decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil 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 elseif node.protocol == "socks" then
settings = { settings = {
udp = ("1" == node.udp_forward) and true or false, udp = ("1" == node.udp_forward) and true or false,
auth = ("1" == node.auth) and "password" or "noauth", auth = users and "password" or "noauth",
users = ("1" == node.auth) and { users = users
{
user = node.username,
pass = node.password
}
} or nil
} }
elseif node.protocol == "http" then elseif node.protocol == "http" then
settings = { settings = {
allowTransparent = false, allowTransparent = false,
users = ("1" == node.auth) and { users = users
{
user = node.username,
pass = node.password
}
} or nil
} }
node.transport = "tcp" node.transport = "tcp"
node.tcp_guise = "none" node.tcp_guise = "none"
elseif node.protocol == "shadowsocks" then elseif node.protocol == "shadowsocks" then
settings = { settings = {
method = node.method, method = node.method,
password = node.password, password = node.ss_password,
network = node.ss_network or "TCP,UDP" users = users,
network = node.ss_network or "tcp,udp"
} }
elseif node.protocol == "trojan" then elseif node.protocol == "trojan" then
if node.uuid then if users then
local users = {}
for i = 1, #node.uuid do
users[i] = {
password = node.uuid[i],
}
end
settings = { settings = {
users = users users = users
} }
@@ -548,9 +562,7 @@ function gen_config_server(node)
elseif node.protocol == "hysteria2" then elseif node.protocol == "hysteria2" then
settings = { settings = {
version = 2, version = 2,
users = node.hysteria2_auth_password and { users = users
{ auth = node.hysteria2_auth_password }
}
} }
elseif node.protocol == "dokodemo-door" then elseif node.protocol == "dokodemo-door" then
settings = { settings = {
+9
View File
@@ -1628,6 +1628,9 @@ msgstr "服务器管理"
msgid "Users Manager" msgid "Users Manager"
msgstr "用户管理" msgstr "用户管理"
msgid "User Config"
msgstr "用户配置"
msgid "Logs" msgid "Logs"
msgstr "日志" msgstr "日志"
@@ -2064,9 +2067,15 @@ msgstr "使用自定义配置"
msgid "Custom Config" msgid "Custom Config"
msgstr "自定义配置" msgstr "自定义配置"
msgid "Must be Base64 text!"
msgstr "必须是 Base64 内容!"
msgid "Must be JSON text!" msgid "Must be JSON text!"
msgstr "必须是 JSON 文本内容!" msgstr "必须是 JSON 文本内容!"
msgid "Must be UUID format!"
msgstr "必须是 UUID 格式!"
msgid "Geo View" msgid "Geo View"
msgstr "Geo 查询" msgstr "Geo 查询"