mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-10 18:34:18 +08:00
✨ Sync 2026-08-13 21:00:03
This commit is contained in:
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.8.12
|
||||
PKG_RELEASE:=215
|
||||
PKG_RELEASE:=216
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -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!'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -57,12 +57,13 @@ function index()
|
||||
|
||||
--[[ Server ]]
|
||||
entry({"admin", "services", appname, "server"}, cbi(appname .. "/server/index"), _("Server-Side"), 99).leaf = true
|
||||
entry({"admin", "services", appname, "server_user"}, cbi(appname .. "/server/user")).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
|
||||
entry({"admin", "services", appname, "server_user_status"}, call("server_user_status")).leaf = true
|
||||
entry({"admin", "services", appname, "server_user_log"}, call("server_user_log")).leaf = true
|
||||
entry({"admin", "services", appname, "server_status"}, call("server_status")).leaf = true
|
||||
entry({"admin", "services", appname, "server_log"}, call("server_log")).leaf = true
|
||||
entry({"admin", "services", appname, "server_get_log"}, call("server_get_log")).leaf = true
|
||||
entry({"admin", "services", appname, "server_clear_log"}, call("server_clear_log")).leaf = true
|
||||
entry({"admin", "services", appname, "link_add_node"}, call("link_add_node")).leaf = true
|
||||
@@ -89,7 +90,6 @@ function index()
|
||||
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
|
||||
entry({"admin", "services", appname, "reassign_group"}, call("reassign_group")).leaf = true
|
||||
entry({"admin", "services", appname, "get_node"}, call("get_node")).leaf = true
|
||||
entry({"admin", "services", appname, "save_node_order"}, call("save_node_order")).leaf = true
|
||||
entry({"admin", "services", appname, "save_node_list_opt"}, call("save_node_list_opt")).leaf = true
|
||||
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true
|
||||
entry({"admin", "services", appname, "rollback_rules"}, call("rollback_rules")).leaf = true
|
||||
@@ -101,7 +101,6 @@ function index()
|
||||
entry({"admin", "services", appname, "get_shunt_rules"}, call("get_shunt_rules")).leaf = true
|
||||
entry({"admin", "services", appname, "add_shunt_rule"}, call("add_shunt_rule")).leaf = true
|
||||
entry({"admin", "services", appname, "delete_select_shunt_rules"}, call("delete_select_shunt_rules")).leaf = true
|
||||
entry({"admin", "services", appname, "save_shunt_rule_order"}, call("save_shunt_rule_order")).leaf = true
|
||||
|
||||
--[[rule_list]]
|
||||
entry({"admin", "services", appname, "read_rulelist"}, call("read_rulelist")).leaf = true
|
||||
@@ -797,19 +796,6 @@ function get_node()
|
||||
http_write_json(result)
|
||||
end
|
||||
|
||||
function save_node_order()
|
||||
local ids = http.formvalue("ids") or ""
|
||||
local new_order = {}
|
||||
for id in ids:gmatch("([^,]+)") do
|
||||
new_order[#new_order + 1] = id
|
||||
end
|
||||
for idx, name in ipairs(new_order) do
|
||||
luci.sys.call(string.format("uci -q reorder %s.%s=%d", appname, name, idx - 1))
|
||||
end
|
||||
api.sh_uci_commit(appname)
|
||||
http_write_json({ status = "ok" })
|
||||
end
|
||||
|
||||
function reassign_group()
|
||||
local ids = http.formvalue("ids") or ""
|
||||
local group = http.formvalue("group") or "default"
|
||||
@@ -878,14 +864,14 @@ function server_update_config()
|
||||
http_write_json_error()
|
||||
end
|
||||
|
||||
function server_user_status()
|
||||
function server_status()
|
||||
local e = {}
|
||||
e.index = http.formvalue("index")
|
||||
e.status = luci.sys.call(string.format("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep -i '%s' >/dev/null", appname .. "_server", http.formvalue("id"))) == 0
|
||||
http_write_json(e)
|
||||
end
|
||||
|
||||
function server_user_log()
|
||||
function server_log()
|
||||
local id = http.formvalue("id")
|
||||
if fs.access("/tmp/etc/passwall_server/" .. id .. ".log") then
|
||||
local content = luci.sys.exec("cat /tmp/etc/passwall_server/" .. id .. ".log")
|
||||
@@ -1286,16 +1272,3 @@ function delete_select_shunt_rules()
|
||||
api.uci_save(uci, appname, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
function save_shunt_rule_order()
|
||||
local ids = http.formvalue("ids") or ""
|
||||
local new_order = {}
|
||||
for id in ids:gmatch("([^,]+)") do
|
||||
new_order[#new_order + 1] = id
|
||||
end
|
||||
for idx, name in ipairs(new_order) do
|
||||
luci.sys.call(string.format("uci -q reorder %s.%s=%d", appname, name, idx - 1))
|
||||
end
|
||||
api.sh_uci_commit(appname)
|
||||
http_write_json({ status = "ok" })
|
||||
end
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = "passwall"
|
||||
local sys = api.sys
|
||||
local datatypes = api.datatypes
|
||||
|
||||
api.set_default_cbi()
|
||||
|
||||
@@ -30,6 +28,29 @@ 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]
|
||||
|
||||
m:append(Template(appname .. "/node_list/node_list"))
|
||||
if true then
|
||||
local o = Template(appname .. "/node_list/node_list")
|
||||
o.map = m
|
||||
o.api = api
|
||||
m:append(o)
|
||||
|
||||
if luci.http.formvalue("cbi.submit") == "1" then
|
||||
local group_order = {}
|
||||
group_order = luci.http.formvaluetable("group.order")
|
||||
if group_order then
|
||||
for k, v in pairs(group_order) do
|
||||
if v and v~= "" then
|
||||
local new_order = {}
|
||||
string.gsub(v, "[^" .. " " .. "]+", function(w)
|
||||
new_order[#new_order + 1] = w
|
||||
end)
|
||||
for idx, name in ipairs(new_order) do
|
||||
m.uci:reorder(appname, name, idx - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return api.return_map(m)
|
||||
|
||||
@@ -146,7 +146,26 @@ end
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
|
||||
if has_xray or has_singbox then
|
||||
m:append(Template(appname .. "/rule/shunt_rule_list"))
|
||||
local o = Template(appname .. "/rule/shunt_rule_list")
|
||||
o.api = api
|
||||
m:append(o)
|
||||
|
||||
if luci.http.formvalue("cbi.submit") == "1" then
|
||||
local group_order = luci.http.formvaluetable("group.order")
|
||||
if group_order then
|
||||
for k, v in pairs(group_order) do
|
||||
if v and v~= "" then
|
||||
local new_order = {}
|
||||
string.gsub(v, "[^" .. " " .. "]+", function(w)
|
||||
new_order[#new_order + 1] = w
|
||||
end)
|
||||
for idx, name in ipairs(new_order) do
|
||||
m.uci:reorder(appname, name, idx - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return api.return_map(m)
|
||||
|
||||
@@ -18,38 +18,39 @@ e.default = "90"
|
||||
e.datatype = "range(0,600)"
|
||||
e.rmempty = false
|
||||
|
||||
local cfgname = "user"
|
||||
t = m:section(TypedSection, cfgname, translate("Users Manager"))
|
||||
t.anonymous = true
|
||||
t.addremove = true
|
||||
t.sortable = true
|
||||
t.template = "cbi/tblsection"
|
||||
t.extedit = api.url("server_user", "%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('<font class="_users_status">%s</font>', translate("Collecting data..."))
|
||||
return string.format('<font class="_servers_status">%s</font>', 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)
|
||||
@@ -87,20 +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 = cfgname
|
||||
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 = 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"))
|
||||
|
||||
m:append(Template(appname .. "/server/users_list_status"))
|
||||
|
||||
return api.return_map(m)
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 = ""
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -102,29 +102,33 @@ local function start()
|
||||
nft_file:write('flush chain inet fw4 PSW-SERVER\n')
|
||||
nft_file:write('insert rule inet fw4 input position 0 jump PSW-SERVER comment "PSW-SERVER"\n')
|
||||
end
|
||||
uci:foreach(CONFIG, "user", function(user)
|
||||
local id = user[".name"]
|
||||
local enable = user.enable
|
||||
uci:foreach(CONFIG, "server", function(server)
|
||||
local id = server[".name"]
|
||||
local enable = server.enable
|
||||
if enable and tonumber(enable) == 1 then
|
||||
local enable_log = user.log
|
||||
local enable_log = server.log
|
||||
local log_path = nil
|
||||
if enable_log and enable_log == "1" then
|
||||
log_path = CONFIG_PATH .. "/" .. id .. ".log"
|
||||
else
|
||||
log_path = nil
|
||||
end
|
||||
local remarks = user.remarks
|
||||
local port = tonumber(user.port)
|
||||
local remarks = server.remarks
|
||||
local port = tonumber(server.port)
|
||||
local bin
|
||||
local config = {}
|
||||
local config_file = CONFIG_PATH .. "/" .. id .. ".json"
|
||||
local udp_forward = 1
|
||||
local type = user.type or ""
|
||||
local type = server.type or ""
|
||||
if type == "Socks" then
|
||||
local auth = ""
|
||||
if user.auth and user.auth == "1" then
|
||||
local username = user.username or ""
|
||||
local password = user.password or ""
|
||||
if server.auth and server.auth == "1" then
|
||||
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
|
||||
@@ -133,59 +137,59 @@ local function start()
|
||||
end
|
||||
bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path)
|
||||
elseif type == "SSR" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
if server.custom == "1" and server.config_str then
|
||||
config = jsonc.parse(api.base64Decode(server.config_str))
|
||||
else
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(server)
|
||||
end
|
||||
local udp_param = ""
|
||||
udp_forward = tonumber(user.udp_forward) or 1
|
||||
udp_forward = tonumber(server.udp_forward) or 1
|
||||
if udp_forward == 1 then
|
||||
udp_param = "-u"
|
||||
end
|
||||
type = type:lower()
|
||||
bin = ln_run("/usr/bin/" .. type .. "-server", type .. "-server", "-c " .. config_file .. " " .. udp_param, log_path)
|
||||
elseif type == "SS-Rust" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
if server.custom == "1" and server.config_str then
|
||||
config = jsonc.parse(api.base64Decode(server.config_str))
|
||||
else
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(server)
|
||||
end
|
||||
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
|
||||
elseif type == "Xray" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
if server.custom == "1" and server.config_str then
|
||||
config = jsonc.parse(api.base64Decode(server.config_str))
|
||||
if log_path then
|
||||
if not config.log then
|
||||
config.log = {}
|
||||
end
|
||||
config.log.loglevel = user.loglevel
|
||||
config.log.loglevel = server.loglevel
|
||||
end
|
||||
else
|
||||
config = require(require_dir .. "util_xray").gen_config_server(user)
|
||||
config = require(require_dir .. "util_xray").gen_config_server(server)
|
||||
end
|
||||
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
|
||||
elseif type == "sing-box" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
if server.custom == "1" and server.config_str then
|
||||
config = jsonc.parse(api.base64Decode(server.config_str))
|
||||
if log_path then
|
||||
if not config.log then
|
||||
config.log = {}
|
||||
end
|
||||
config.log.timestamp = true
|
||||
config.log.disabled = false
|
||||
config.log.level = user.loglevel
|
||||
config.log.level = server.loglevel
|
||||
config.log.output = log_path
|
||||
end
|
||||
else
|
||||
config = require(require_dir .. "util_sing-box").gen_config_server(user)
|
||||
config = require(require_dir .. "util_sing-box").gen_config_server(server)
|
||||
end
|
||||
bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path)
|
||||
elseif type == "Hysteria2" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
if server.custom == "1" and server.config_str then
|
||||
config = jsonc.parse(api.base64Decode(server.config_str))
|
||||
else
|
||||
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
|
||||
config = require(require_dir .. "util_hysteria2").gen_config_server(server)
|
||||
end
|
||||
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
|
||||
end
|
||||
@@ -203,7 +207,7 @@ local function start()
|
||||
cmd(bin)
|
||||
end
|
||||
|
||||
local bind_local = user.bind_local or 0
|
||||
local bind_local = server.bind_local or 0
|
||||
if bind_local and tonumber(bind_local) ~= 1 and port then
|
||||
if nft_flag == "0" then
|
||||
ipt(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local api = self.api
|
||||
local appname = api.appname
|
||||
local map = self.map
|
||||
local is_js_luci = api.is_js_luci()
|
||||
local section_tag = is_js_luci and "div" or "fieldset"
|
||||
-%>
|
||||
@@ -500,15 +501,7 @@ table td, .table .td {
|
||||
let firstDataRow = parent.querySelector("tr:not(.cbi-section-table-titles)");
|
||||
if (firstDataRow && firstDataRow !== row) {
|
||||
parent.insertBefore(row, firstDataRow);
|
||||
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||
if (save_order_btn) {
|
||||
const new_order = get_node_order(group);
|
||||
if (!arraysEqual(new_order, origin_group_node_order[group])) {
|
||||
save_order_btn.style.display = null;
|
||||
} else {
|
||||
save_order_btn.style.display = "none";
|
||||
}
|
||||
}
|
||||
set_order(group);
|
||||
}
|
||||
break;
|
||||
case "del_all":
|
||||
@@ -652,48 +645,24 @@ table td, .table .td {
|
||||
return ids;
|
||||
}
|
||||
|
||||
function save_current_page_order(group) {
|
||||
var table = document.getElementById("cbi-<%=appname%>-nodes-" + group + "-table");
|
||||
function set_order(group) {
|
||||
let table = document.getElementById("cbi-<%=appname%>-nodes-" + group + "-table");
|
||||
if (!table) {
|
||||
alert("<%:No table!%>");
|
||||
return;
|
||||
}
|
||||
var rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||
let rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||
if (!rows || rows.length === 0) {
|
||||
alert("<%:No nodes!%>");
|
||||
return;
|
||||
}
|
||||
var btn = document.getElementById("save_order_btn_" + group);
|
||||
if (btn) {
|
||||
btn.style.display = "none";
|
||||
btn.disabled = true;
|
||||
}
|
||||
var ids = [];
|
||||
let ids = [];
|
||||
rows.forEach(function(row) {
|
||||
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||
let id = row.id.replace("cbi-<%=appname%>-", "");
|
||||
ids.push(id);
|
||||
});
|
||||
ajax.abortAll();
|
||||
XHR.get('<%=api.url("save_node_order")%>', {
|
||||
group: group,
|
||||
ids: ids.join(",")
|
||||
},
|
||||
function(x, result) {
|
||||
if (btn) {
|
||||
btn.style.display = null;
|
||||
btn.disabled = false;
|
||||
}
|
||||
if (x && x.status === 200) {
|
||||
origin_group_node_order[group] = get_node_order(group);
|
||||
alert("<%:Saved current page order successfully.%>");
|
||||
if (btn) {
|
||||
btn.style.display = "none";
|
||||
}
|
||||
} else {
|
||||
alert("<%:Save failed!%>");
|
||||
}
|
||||
}
|
||||
);
|
||||
const input_order = document.getElementsByName(`group.order.${group}`)[0];
|
||||
input_order.value = ids.join(" ");
|
||||
}
|
||||
|
||||
//获取当前使用的节点
|
||||
@@ -947,16 +916,7 @@ table td, .table .td {
|
||||
forceFallback: false,
|
||||
swapThreshold: 0.65,
|
||||
onEnd: function (evt) {
|
||||
//save_current_page_order(group); // 自动提交保存
|
||||
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||
if (save_order_btn) {
|
||||
const new_order = get_node_order(group);
|
||||
if (!arraysEqual(new_order, origin_group_node_order[group])) {
|
||||
save_order_btn.style.display = null;
|
||||
} else {
|
||||
save_order_btn.style.display = "none";
|
||||
}
|
||||
}
|
||||
set_order(group);
|
||||
}
|
||||
};
|
||||
try {
|
||||
@@ -1302,9 +1262,9 @@ table td, .table .td {
|
||||
</tr>
|
||||
{{node-tr}}
|
||||
</table>
|
||||
<input type="hidden" name="group.order.{{group}}">
|
||||
<div class="cbi-section-create cbi-tblsection-create">
|
||||
<input class="cbi-button cbi-button-add" type="button" value="<%:Add%>" onclick="node_action('add')">
|
||||
<input class="cbi-button cbi-button-apply" style="display: none" type="button" id="save_order_btn_{{group}}" value="<%:Save Order%>" onclick="save_current_page_order('{{group}}')">
|
||||
</div>
|
||||
</<%=section_tag%>>
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local api = self.api
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
local is_js_luci = api.is_js_luci()
|
||||
local section_tag = is_js_luci and "div" or "fieldset"
|
||||
local title_tag = is_js_luci and "h3" or "legend"
|
||||
@@ -185,15 +184,7 @@ table td, .table .td {
|
||||
let firstDataRow = parent.querySelector("tr:not(.cbi-section-table-titles)");
|
||||
if (firstDataRow && firstDataRow !== row) {
|
||||
parent.insertBefore(row, firstDataRow);
|
||||
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||
if (save_order_btn) {
|
||||
const new_order = get_shunt_rule_order(group);
|
||||
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||
save_order_btn.style.display = null;
|
||||
} else {
|
||||
save_order_btn.style.display = "none";
|
||||
}
|
||||
}
|
||||
set_order(group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,48 +205,24 @@ table td, .table .td {
|
||||
return ids;
|
||||
}
|
||||
|
||||
function save_current_page_order(group) {
|
||||
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||
function set_order(group) {
|
||||
let table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||
if (!table) {
|
||||
alert("<%:No table!%>");
|
||||
return;
|
||||
}
|
||||
var rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||
let rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||
if (!rows || rows.length === 0) {
|
||||
alert("<%:No shunt_rules!%>");
|
||||
return;
|
||||
}
|
||||
var btn = document.getElementById("save_order_btn_" + group);
|
||||
if (btn) {
|
||||
btn.style.display = "none";
|
||||
btn.disabled = true;
|
||||
}
|
||||
var ids = [];
|
||||
let ids = [];
|
||||
rows.forEach(function(row) {
|
||||
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||
let id = row.id.replace("cbi-<%=appname%>-", "");
|
||||
ids.push(id);
|
||||
});
|
||||
XHR.get('<%=api.url("save_shunt_rule_order")%>', {
|
||||
group: group,
|
||||
ids: ids.join(",")
|
||||
},
|
||||
function(x, result) {
|
||||
if (btn) {
|
||||
btn.style.display = null;
|
||||
btn.disabled = false;
|
||||
}
|
||||
if (x && x.status === 200) {
|
||||
// origin_group_shunt_rule_order[group] = get_shunt_rule_order(group);
|
||||
alert("<%:Saved current page order successfully.%>");
|
||||
// if (btn) {
|
||||
// btn.style.display = "none";
|
||||
// }
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("<%:Save failed!%>");
|
||||
}
|
||||
}
|
||||
);
|
||||
const input_order = document.getElementsByName(`group.order.${group}`)[0];
|
||||
input_order.value = ids.join(" ");
|
||||
}
|
||||
|
||||
// List drag and rearrange
|
||||
@@ -274,16 +241,7 @@ table td, .table .td {
|
||||
forceFallback: false,
|
||||
swapThreshold: 0.65,
|
||||
onEnd: function (evt) {
|
||||
//save_current_page_order(group); // Auto save
|
||||
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||
if (save_order_btn) {
|
||||
const new_order = get_shunt_rule_order(group);
|
||||
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||
save_order_btn.style.display = null;
|
||||
} else {
|
||||
save_order_btn.style.display = "none";
|
||||
}
|
||||
}
|
||||
set_order(group);
|
||||
}
|
||||
};
|
||||
try {
|
||||
@@ -339,10 +297,10 @@ table td, .table .td {
|
||||
</tr>
|
||||
{{shunt_rule-tr}}
|
||||
</table>
|
||||
<input type="hidden" name="group.order.{{group}}">
|
||||
<div class="cbi-section-create cbi-tblsection-create">
|
||||
<input type="text" id="add_name_{{group}}">
|
||||
<input class="cbi-button cbi-button-add" type="button" value="<%:Add%>" onclick="toPage('add')">
|
||||
<input class="cbi-button cbi-button-apply" style="display: none" type="button" id="save_order_btn_{{group}}" value="<%:Save Order%>" onclick="save_current_page_order('{{group}}')">
|
||||
</div>
|
||||
</<%=section_tag%>>
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,7 @@ local api = self.api
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
let node_id = "<%=self.section%>";
|
||||
let node_config_url = '<%=api.url("server_user")%>/' + node_id;
|
||||
let node_config_url = '<%=api.url("server_config")%>/' + node_id;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<%
|
||||
local api = self.api
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var _servers_status = document.getElementsByClassName('_servers_status');
|
||||
for(var i = 0; i < _servers_status.length; i++) {
|
||||
var id = _servers_status[i].parentElement.parentElement.parentElement.id;
|
||||
id = id.substr(id.lastIndexOf("-") + 1);
|
||||
XHR.get('<%=api.url("server_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
_servers_status[result.index].setAttribute("style","font-weight:bold;");
|
||||
_servers_status[result.index].setAttribute("color",result.status ? "green":"red");
|
||||
_servers_status[result.index].innerHTML = (result.status ? '✓' : 'X');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var edit_btn = document.getElementById("cbi-<%=self.appname%>-<%=self.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");
|
||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
||||
var td = edit_btn[i].parentNode;
|
||||
var new_div = "";
|
||||
// Add `log` button
|
||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Log%>" onclick="window.open(\'' + '<%=api.url("server_log")%>' + '?id=' + id + '\', \'_blank\')"/> ';
|
||||
td.innerHTML = new_div + td.innerHTML;
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
@@ -1,38 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var _users_status = document.getElementsByClassName('_users_status');
|
||||
for(var i = 0; i < _users_status.length; i++) {
|
||||
var id = _users_status[i].parentElement.parentElement.parentElement.id;
|
||||
id = id.substr(id.lastIndexOf("-") + 1);
|
||||
XHR.get('<%=api.url("server_user_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
_users_status[result.index].setAttribute("style","font-weight:bold;");
|
||||
_users_status[result.index].setAttribute("color",result.status ? "green":"red");
|
||||
_users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var edit_btn = document.getElementById("cbi-passwall_server-user").getElementsByClassName("cbi-button cbi-button-edit");
|
||||
for (var i = 0; i < edit_btn.length; i++) {
|
||||
try {
|
||||
var onclick_str = edit_btn[i].getAttribute("onclick");
|
||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
||||
var td = edit_btn[i].parentNode;
|
||||
var new_div = "";
|
||||
//添加"日志"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Log%>" onclick="window.open(\'' + '<%=api.url("server_user_log")%>' + '?id=' + id + '\', \'_blank\')"/> ';
|
||||
td.innerHTML = new_div + td.innerHTML;
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
@@ -490,12 +490,6 @@ msgstr "节点备注"
|
||||
msgid "Add Mode"
|
||||
msgstr "添加方式"
|
||||
|
||||
msgid "Save Order"
|
||||
msgstr "保存当前顺序"
|
||||
|
||||
msgid "Saved current page order successfully."
|
||||
msgstr "保存当前页面顺序成功。"
|
||||
|
||||
msgid "Drag to reorder"
|
||||
msgstr "拖动以重排"
|
||||
|
||||
@@ -1670,9 +1664,15 @@ msgstr "服务器端"
|
||||
msgid "Server Config"
|
||||
msgstr "服务器配置"
|
||||
|
||||
msgid "Servers Manager"
|
||||
msgstr "服务器管理"
|
||||
|
||||
msgid "Users Manager"
|
||||
msgstr "用户管理"
|
||||
|
||||
msgid "User Config"
|
||||
msgstr "用户配置"
|
||||
|
||||
msgid "Logs"
|
||||
msgstr "日志"
|
||||
|
||||
@@ -2109,9 +2109,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 查询"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user