diff --git a/package/lienol/luci-app-passwall/Makefile b/package/lienol/luci-app-passwall/Makefile
index 8614606e8e..c9c1f091b9 100644
--- a/package/lienol/luci-app-passwall/Makefile
+++ b/package/lienol/luci-app-passwall/Makefile
@@ -6,9 +6,9 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
-PKG_VERSION:=3.9
-PKG_RELEASE:=72
-PKG_DATE:=20201012
+PKG_VERSION:=4
+PKG_RELEASE:=1
+PKG_DATE:=20201204
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
@@ -33,9 +33,13 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server
bool "Include ShadowsocksR Server"
default y
+config PACKAGE_$(PKG_NAME)_INCLUDE_Xray
+ bool "Include Xray"
+ default y if i386||x86_64||arm||aarch64
+
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
bool "Include V2ray"
- default y if i386||x86_64||arm||aarch64
+ default n
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Plus
bool "Include Trojan_Plus"
@@ -48,7 +52,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_GO
config PACKAGE_$(PKG_NAME)_INCLUDE_Brook
bool "Include Brook"
default n
-
+
config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
bool "Include NaiveProxy"
default n
@@ -60,19 +64,19 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_kcptun
config PACKAGE_$(PKG_NAME)_INCLUDE_haproxy
bool "Include haproxy"
default y
-
+
config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
bool "Include ChinaDNS-NG"
default n
-
+
config PACKAGE_$(PKG_NAME)_INCLUDE_https_dns_proxy
bool "Include Https DNS Proxy(DoH)"
default y
-
+
config PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks
bool "Include dns2socks"
default n
-
+
config PACKAGE_$(PKG_NAME)_INCLUDE_v2ray-plugin
bool "Include v2ray-plugin (Shadowsocks plugin)"
default y if i386||x86_64||arm||aarch64
@@ -101,6 +105,7 @@ define Package/$(PKG_NAME)
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR:shadowsocksr-libev-alt \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR:shadowsocksr-libev-ssr-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server:shadowsocksr-libev-server \
+ +PACKAGE_$(PKG_NAME)_INCLUDE_Xray:xray \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Plus:trojan-plus \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_GO:trojan-go \
@@ -137,21 +142,20 @@ define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./root/etc/config/passwall $(1)/etc/config/passwall
$(INSTALL_CONF) ./root/etc/config/passwall_server $(1)/etc/config/passwall_server
-
+
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./root/etc/init.d/passwall $(1)/etc/init.d/passwall
$(INSTALL_BIN) ./root/etc/init.d/passwall_server $(1)/etc/init.d/passwall_server
-
+
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_CONF) ./root/etc/uci-defaults/* $(1)/etc/uci-defaults
-
+
$(INSTALL_DIR) $(1)/usr/share/passwall
cp -pR ./root/usr/share/passwall/* $(1)/usr/share/passwall
$(INSTALL_CONF) ./root/etc/config/passwall $(1)/usr/share/passwall/config.default
-
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci/
-
+
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
po2lmo ./po/zh-cn/passwall.po $(1)/usr/lib/lua/luci/i18n/passwall.zh-cn.lmo
endef
diff --git a/package/lienol/luci-app-passwall/luasrc/controller/passwall.lua b/package/lienol/luci-app-passwall/luasrc/controller/passwall.lua
index 85ab30b8e2..c1b2f7482d 100644
--- a/package/lienol/luci-app-passwall/luasrc/controller/passwall.lua
+++ b/package/lienol/luci-app-passwall/luasrc/controller/passwall.lua
@@ -4,8 +4,10 @@ local appname = "passwall"
local ucic = luci.model.uci.cursor()
local http = require "luci.http"
local util = require "luci.util"
+local api = require "luci.model.cbi.passwall.api.api"
local kcptun = require "luci.model.cbi.passwall.api.kcptun"
local brook = require "luci.model.cbi.passwall.api.brook"
+local xray = require "luci.model.cbi.passwall.api.xray"
local v2ray = require "luci.model.cbi.passwall.api.v2ray"
local trojan_go = require "luci.model.cbi.passwall.api.trojan_go"
@@ -65,6 +67,8 @@ function index()
entry({"admin", "services", appname, "kcptun_update"}, call("kcptun_update")).leaf = true
entry({"admin", "services", appname, "brook_check"}, call("brook_check")).leaf = true
entry({"admin", "services", appname, "brook_update"}, call("brook_update")).leaf = true
+ entry({"admin", "services", appname, "xray_check"}, call("xray_check")).leaf = true
+ entry({"admin", "services", appname, "xray_update"}, call("xray_update")).leaf = true
entry({"admin", "services", appname, "v2ray_check"}, call("v2ray_check")).leaf = true
entry({"admin", "services", appname, "v2ray_update"}, call("v2ray_update")).leaf = true
entry({"admin", "services", appname, "trojan_go_check"}, call("trojan_go_check")).leaf = true
@@ -239,10 +243,22 @@ function set_node()
end
function copy_node()
- local e = {}
local section = luci.http.formvalue("section")
- luci.http.prepare_content("application/json")
- luci.http.write_json(e)
+ local uuid = api.gen_uuid()
+ ucic:section(appname, "nodes", uuid)
+ for k, v in pairs(ucic:get_all(appname, section)) do
+ local filter = k:find("%.")
+ if filter and filter == 1 then
+ else
+ xpcall(function()
+ ucic:set(appname, uuid, k, v)
+ end,
+ function(e)
+ end)
+ end
+ end
+ ucic:commit(appname)
+ luci.http.redirect(luci.dispatcher.build_url("admin", "services", appname, "node_config", uuid))
end
function clear_all_nodes()
@@ -285,11 +301,11 @@ function check_port()
ucic:foreach(appname, "nodes", function(s)
local ret = ""
local tcp_socket
- if (s.use_kcp and s.use_kcp == "1" and s.kcp_port) or
- (s.v2ray_transport and s.v2ray_transport == "mkcp" and s.port) then
+ if (s.use_kcp and s.use_kcp == "1" and s.kcp_port) or (s.transport and s.transport == "mkcp" and s.port) then
else
local type = s.type
- if type and type ~= "V2ray_balancing" and type ~= "V2ray_shunt" and
+ local protocol = s.protocol
+ if type and (protocol and protocol ~= "_balancing" and protocol ~= "_shunt") and
s.address and s.port and s.remarks then
node_name = "%s:[%s] %s:%s" % {s.type, s.remarks, s.address, s.port}
tcp_socket = nixio.socket("inet", "stream")
@@ -366,6 +382,25 @@ function brook_update()
http_write_json(json)
end
+function xray_check()
+ local json = xray.to_check("")
+ http_write_json(json)
+end
+
+function xray_update()
+ local json = nil
+ local task = http.formvalue("task")
+ if task == "extract" then
+ json = xray.to_extract(http.formvalue("file"), http.formvalue("subfix"))
+ elseif task == "move" then
+ json = xray.to_move(http.formvalue("file"))
+ else
+ json = xray.to_download(http.formvalue("url"))
+ end
+
+ http_write_json(json)
+end
+
function v2ray_check()
local json = v2ray.to_check("")
http_write_json(json)
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/api.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/api.lua
index 51061d51b3..a408a69f6b 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/api.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/api.lua
@@ -19,7 +19,7 @@ function get_valid_nodes()
local nodes = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks then
- if e.type == "V2ray" and (e.protocol == "_balancing" or e.protocol == "_shunt") then
+ if e.protocol and (e.protocol == "_balancing" or e.protocol == "_shunt") then
e.remarks_name = "%s:[%s] " % {i18n.translatef(e.type .. e.protocol), e.remarks}
e.node_type = "special"
nodes[#nodes + 1] = e
@@ -79,19 +79,55 @@ function get_customed_path(e)
end
function is_finded(e)
- return luci.sys.exec('type -t -p "%s/%s" -p "/usr/bin/v2ray/%s" "%s"' % {get_customed_path(e), e, e, e}) ~= "" and true or false
+ return luci.sys.exec('type -t -p "%s/%s" "%s"' % {get_customed_path(e), e, e}) ~= "" and true or false
+end
+
+function get_xray_path()
+ local path = uci_get_type("global_app", "xray_file")
+ return path
+end
+
+function get_xray_version(file)
+ if file == nil then file = get_xray_path() end
+ chmod_755(file)
+ if fs.access(file) then
+ if file == get_xray_path() then
+ local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')")
+ if fs.access("/tmp/psw_" .. md5) then
+ return sys.exec("cat /tmp/psw_" .. md5)
+ else
+ local version = sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ sys.call("echo '" .. version .. "' > " .. "/tmp/psw_" .. md5)
+ return version
+ end
+ else
+ return sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ end
+ end
+ return ""
end
function get_v2ray_path()
local path = uci_get_type("global_app", "v2ray_file")
- return path .. "/v2ray"
+ return path
end
function get_v2ray_version(file)
if file == nil then file = get_v2ray_path() end
chmod_755(file)
if fs.access(file) then
- return sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ if file == get_v2ray_path() then
+ local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')")
+ if fs.access("/tmp/psw_" .. md5) then
+ return sys.exec("cat /tmp/psw_" .. md5)
+ else
+ local version = sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ sys.call("echo '" .. version .. "' > " .. "/tmp/psw_" .. md5)
+ return version
+ end
+ else
+ return sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ end
end
return ""
end
@@ -105,7 +141,18 @@ function get_trojan_go_version(file)
if file == nil then file = get_trojan_go_path() end
chmod_755(file)
if fs.access(file) then
- return sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ if file == get_trojan_go_path() then
+ local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')")
+ if fs.access("/tmp/psw_" .. md5) then
+ return sys.exec("cat /tmp/psw_" .. md5)
+ else
+ local version = sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ sys.call("echo '" .. version .. "' > " .. "/tmp/psw_" .. md5)
+ return version
+ end
+ else
+ return sys.exec("echo -n $(%s -version | awk '{print $2}' | sed -n 1P)" % file)
+ end
end
return ""
end
@@ -119,7 +166,18 @@ function get_kcptun_version(file)
if file == nil then file = get_kcptun_path() end
chmod_755(file)
if fs.access(file) then
- return sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ if file == get_kcptun_path() then
+ local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')")
+ if fs.access("/tmp/psw_" .. md5) then
+ return sys.exec("cat /tmp/psw_" .. md5)
+ else
+ local version = sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ sys.call("echo '" .. version .. "' > " .. "/tmp/psw_" .. md5)
+ return version
+ end
+ else
+ return sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ end
end
return ""
end
@@ -133,11 +191,38 @@ function get_brook_version(file)
if file == nil then file = get_brook_path() end
chmod_755(file)
if fs.access(file) then
- return sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ if file == get_brook_path() then
+ local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')")
+ if fs.access("/tmp/psw_" .. md5) then
+ return sys.exec("cat /tmp/psw_" .. md5)
+ else
+ local version = sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ sys.call("echo '" .. version .. "' > " .. "/tmp/psw_" .. md5)
+ return version
+ end
+ else
+ return sys.exec("echo -n $(%s -v | awk '{print $3}')" % file)
+ end
end
return ""
end
+function get_free_space(dir)
+ if dir == nil then dir = "/" end
+ if sys.call("df -k " .. dir .. " >/dev/null") == 0 then
+ return tonumber(sys.exec("echo -n $(df -k " .. dir .. " | awk 'NR>1' | awk '{print $4}')"))
+ end
+ return 0
+end
+
+function get_file_space(file)
+ if file == nil then return 0 end
+ if fs.access(file) then
+ return tonumber(sys.exec("echo -n $(du -k " .. file .. " | awk '{print $1}')"))
+ end
+ return 0
+end
+
function _unpack(t, i)
i = i or 1
if t[i] ~= nil then return t[i], _unpack(t, i + 1) end
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/brook.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/brook.lua
index 3051858f9c..4213ccb7b5 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/brook.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/brook.lua
@@ -8,6 +8,13 @@ local api = require "luci.model.cbi.passwall.api.api"
local brook_api = "https://api.github.com/repos/txthinking/brook/releases/latest"
function to_check(arch)
+ local app_path = api.get_brook_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Brook")
+ }
+ end
if not arch or arch == "" then arch = api.auto_get_arch() end
local file_tree, sub_version = api.get_file_info(arch)
@@ -15,8 +22,7 @@ function to_check(arch)
if file_tree == "" then
return {
code = 1,
- error = i18n.translate(
- "Can't determine ARCH, or ARCH not supported.")
+ error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
}
end
@@ -66,6 +72,13 @@ function to_check(arch)
end
function to_download(url)
+ local app_path = api.get_brook_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Brook")
+ }
+ end
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
@@ -88,13 +101,20 @@ function to_download(url)
end
function to_move(file)
+ local app_path = api.get_brook_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Brook")
+ }
+ end
if not file or file == "" or not fs.access(file) then
sys.call("/bin/rm -rf /tmp/brook_download.*")
return {code = 1, error = i18n.translate("Client file is required.")}
end
- local version = api.get_brook_version(file)
- if version == "" then
+ local new_version = api.get_brook_version(file)
+ if new_version == "" then
sys.call("/bin/rm -rf /tmp/brook_download.*")
return {
code = 1,
@@ -102,30 +122,29 @@ function to_move(file)
}
end
- local client_file = api.get_brook_path()
- local client_file_bak
+ local app_path_bak
- if fs.access(client_file) then
- client_file_bak = client_file .. ".bak"
- api.exec("/bin/mv", {"-f", client_file, client_file_bak})
+ if fs.access(app_path) then
+ app_path_bak = app_path .. ".bak"
+ api.exec("/bin/mv", {"-f", app_path, app_path_bak})
end
- local result = api.exec("/bin/mv", {"-f", file, client_file}, nil, api.command_timeout) == 0
+ local result = api.exec("/bin/mv", {"-f", file, app_path}, nil, api.command_timeout) == 0
- if not result or not fs.access(client_file) then
+ if not result or not fs.access(app_path) then
sys.call("/bin/rm -rf /tmp/brook_download.*")
- if client_file_bak then
- api.exec("/bin/mv", {"-f", client_file_bak, client_file})
+ if app_path_bak then
+ api.exec("/bin/mv", {"-f", app_path_bak, app_path})
end
return {
code = 1,
- error = i18n.translatef("Can't move new file to path: %s", client_file)
+ error = i18n.translatef("Can't move new file to path: %s", app_path)
}
end
- api.exec("/bin/chmod", {"755", client_file})
+ api.exec("/bin/chmod", {"755", app_path})
- if client_file_bak then api.exec("/bin/rm", {"-f", client_file_bak}) end
+ if app_path_bak then api.exec("/bin/rm", {"-f", app_path_bak}) end
sys.call("/bin/rm -rf /tmp/brook_download.*")
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_v2ray.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_v2ray.lua
index 583428ef34..0b06599d2f 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_v2ray.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_v2ray.lua
@@ -56,10 +56,14 @@ function gen_outbound(node, tag, relay_port)
node.address = "127.0.0.1"
end
node.stream_security = "none"
- end
-
- if node.transport == "mkcp" or node.transport == "quic" then
- node.stream_security = "none"
+ else
+ if node.tls and node.tls == "1" then
+ node.stream_security = "tls"
+ end
+
+ if node.transport == "mkcp" or node.transport == "quic" then
+ node.stream_security = "none"
+ end
end
result = {
@@ -73,10 +77,6 @@ function gen_outbound(node, tag, relay_port)
streamSettings = (node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan") and {
network = node.transport,
security = node.stream_security,
- xtlsSettings = (node.stream_security == "xtls") and {
- serverName = node.tls_serverName,
- allowInsecure = (node.tls_allowInsecure == "1") and true or false
- } or nil,
tlsSettings = (node.stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or false
@@ -265,7 +265,10 @@ if node then
end
end
- routing = {domainStrategy = "IPOnDemand", rules = rules}
+ routing = {
+ domainStrategy = node.domainStrategy or "AsIs",
+ rules = rules
+ }
elseif node.protocol == "_balancing" then
if node.balancing_node then
@@ -277,7 +280,7 @@ if node then
if outbound then table.insert(outbounds, outbound) end
end
routing = {
- domainStrategy = "IPOnDemand",
+ domainStrategy = node.domainStrategy or "AsIs",
balancers = {{tag = "balancer", selector = nodes}},
rules = {
{type = "field", network = "tcp,udp", balancerTag = "balancer"}
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray.lua
new file mode 100644
index 0000000000..24653d59fd
--- /dev/null
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray.lua
@@ -0,0 +1,318 @@
+module("luci.model.cbi.passwall.api.gen_xray", package.seeall)
+local ucursor = require"luci.model.uci".cursor()
+local sys = require "luci.sys"
+local json = require "luci.jsonc"
+local appname = "passwall"
+local inbounds = {}
+local outbounds = {}
+local routing = nil
+
+local node_section = arg[1] or "nil"
+local proto = arg[2]
+local redir_port = arg[3]
+local socks_proxy_port = arg[4]
+local node = ucursor:get_all(appname, node_section)
+local network = proto
+local new_port
+
+local function get_new_port()
+ if new_port then
+ new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port %s tcp)", appname, new_port + 1)))
+ else
+ new_port = tonumber(sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port auto tcp)", appname)))
+ end
+ return new_port
+end
+
+function gen_outbound(node, tag, relay_port)
+ local result = nil
+ if node then
+ local node_id = node[".name"]
+ if tag == nil then
+ tag = node_id
+ end
+ if node.type ~= "Xray" then
+ if node.type == "Socks" then
+ node.protocol = "socks"
+ node.transport = "tcp"
+ else
+ local node_type = (proto and proto ~= "nil") and proto or "socks"
+ new_port = get_new_port()
+ node.port = new_port
+ sys.call(string.format('/usr/share/%s/app.sh run_socks "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s"> /dev/null',
+ appname,
+ node_id,
+ "127.0.0.1",
+ new_port,
+ string.format("/var/etc/%s/v2_%s_%s.json", appname, node_type, node_id),
+ "0",
+ "nil",
+ "4",
+ relay_port and tostring(relay_port) or ""
+ )
+ )
+ node.protocol = "socks"
+ node.transport = "tcp"
+ node.address = "127.0.0.1"
+ end
+ node.stream_security = "none"
+ else
+ if node.tls and node.tls == "1" then
+ node.stream_security = "tls"
+ if node.xtls and node.xtls == "1" then
+ node.stream_security = "xtls"
+ end
+ end
+
+ if node.transport == "mkcp" or node.transport == "quic" then
+ node.stream_security = "none"
+ end
+ end
+
+ result = {
+ tag = tag,
+ protocol = node.protocol,
+ mux = (node.stream_security ~= "xtls") and {
+ enabled = (node.mux == "1") and true or false,
+ concurrency = (node.mux_concurrency) and tonumber(node.mux_concurrency) or 8
+ } or nil,
+ -- 底层传输配置
+ streamSettings = (node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan") and {
+ network = node.transport,
+ security = node.stream_security,
+ xtlsSettings = (node.stream_security == "xtls") and {
+ serverName = node.tls_serverName,
+ allowInsecure = (node.tls_allowInsecure == "1") and true or false
+ } or nil,
+ tlsSettings = (node.stream_security == "tls") and {
+ serverName = node.tls_serverName,
+ allowInsecure = (node.tls_allowInsecure == "1") and true or false
+ } or nil,
+ tcpSettings = (node.transport == "tcp" and node.protocol ~= "socks") and {
+ header = {
+ type = node.tcp_guise,
+ request = (node.tcp_guise == "http") and {
+ path = node.tcp_guise_http_path or {"/"},
+ headers = {
+ Host = node.tcp_guise_http_host or {}
+ }
+ } or nil
+ }
+ } or nil,
+ kcpSettings = (node.transport == "mkcp") and {
+ mtu = tonumber(node.mkcp_mtu),
+ tti = tonumber(node.mkcp_tti),
+ uplinkCapacity = tonumber(node.mkcp_uplinkCapacity),
+ downlinkCapacity = tonumber(node.mkcp_downlinkCapacity),
+ congestion = (node.mkcp_congestion == "1") and true or false,
+ readBufferSize = tonumber(node.mkcp_readBufferSize),
+ writeBufferSize = tonumber(node.mkcp_writeBufferSize),
+ seed = (node.mkcp_seed and node.mkcp_seed ~= "") and node.mkcp_seed or nil,
+ header = {type = node.mkcp_guise}
+ } or nil,
+ wsSettings = (node.transport == "ws") and {
+ path = node.ws_path or "",
+ headers = (node.ws_host ~= nil) and
+ {Host = node.ws_host} or nil
+ } or nil,
+ httpSettings = (node.transport == "h2") and
+ {path = node.h2_path, host = node.h2_host} or
+ nil,
+ dsSettings = (node.transport == "ds") and
+ {path = node.ds_path} or nil,
+ quicSettings = (node.transport == "quic") and {
+ security = node.quic_security,
+ key = node.quic_key,
+ header = {type = node.quic_guise}
+ } or nil
+ } or nil,
+ settings = {
+ vnext = (node.protocol == "vmess" or node.protocol == "vless") and {
+ {
+ address = node.address,
+ port = tonumber(node.port),
+ users = {
+ {
+ id = node.uuid,
+ alterId = tonumber(node.alter_id),
+ level = node.level and tonumber(node.level) or 0,
+ security = (node.protocol == "vmess") and node.security or nil,
+ encryption = node.encryption or "none",
+ flow = node.flow or nil
+ }
+ }
+ }
+ } or nil,
+ servers = (node.protocol == "socks" or node.protocol == "http" or node.protocol == "shadowsocks" or node.protocol == "trojan") and {
+ {
+ address = node.address,
+ port = tonumber(node.port),
+ method = node.method or nil,
+ password = node.password or "",
+ users = (node.username and node.password) and
+ {{user = node.username, pass = node.password}} or nil
+ }
+ } or nil
+ }
+ }
+ end
+ return result
+end
+
+if node then
+ if socks_proxy_port ~= "nil" then
+ table.insert(inbounds, {
+ listen = "0.0.0.0",
+ port = tonumber(socks_proxy_port),
+ protocol = "socks",
+ settings = {auth = "noauth", udp = true, ip = "127.0.0.1"}
+ })
+ network = "tcp,udp"
+ end
+
+ if redir_port ~= "nil" then
+ table.insert(inbounds, {
+ port = tonumber(redir_port),
+ protocol = "dokodemo-door",
+ settings = {network = proto, followRedirect = true},
+ sniffing = {enabled = true, destOverride = {"http", "tls"}}
+ })
+ if proto == "tcp" and node.tcp_socks == "1" then
+ table.insert(inbounds, {
+ listen = "0.0.0.0",
+ port = tonumber(node.tcp_socks_port),
+ protocol = "socks",
+ settings = {
+ auth = node.tcp_socks_auth,
+ accounts = (node.tcp_socks_auth == "password") and {
+ {
+ user = node.tcp_socks_auth_username,
+ pass = node.tcp_socks_auth_password
+ }
+ } or nil,
+ udp = true
+ }
+ })
+ end
+ end
+
+ if node.protocol == "_shunt" then
+ local rules = {}
+ ucursor:foreach(appname, "shunt_rules", function(e)
+ local name = e[".name"]
+ local _node_id = node[name] or nil
+ if _node_id and _node_id ~= "nil" then
+ local _node = ucursor:get_all(appname, _node_id)
+ local is_proxy = node[name .. "_proxy"]
+ local relay_port
+ if is_proxy and is_proxy == "1" then
+ new_port = get_new_port()
+ relay_port = new_port
+ table.insert(inbounds, {
+ tag = "proxy_" .. name,
+ listen = "127.0.0.1",
+ port = new_port,
+ protocol = "dokodemo-door",
+ settings = {network = "tcp,udp", address = _node.address, port = tonumber(_node.port)}
+ })
+ if _node.tls_serverName == nil then
+ _node.tls_serverName = _node.address
+ end
+ _node.address = "127.0.0.1"
+ _node.port = new_port
+ end
+ local _outbound = gen_outbound(_node, name, relay_port)
+ if _outbound then
+ table.insert(outbounds, _outbound)
+ if is_proxy and is_proxy == "1" then
+ table.insert(rules, {
+ type = "field",
+ inboundTag = {"proxy_" .. name},
+ outboundTag = "default"
+ })
+ end
+ if e.domain_list then
+ local _domain = {}
+ string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
+ table.insert(_domain, w)
+ end)
+ table.insert(rules, {
+ type = "field",
+ outboundTag = name,
+ domain = _domain
+ })
+ end
+ if e.ip_list then
+ local _ip = {}
+ string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
+ table.insert(_ip, w)
+ end)
+ table.insert(rules, {
+ type = "field",
+ outboundTag = name,
+ ip = _ip
+ })
+ end
+ end
+ end
+ end)
+
+ local default_node_id = node.default_node or nil
+ if default_node_id and default_node_id ~= "nil" then
+ local default_node = ucursor:get_all(appname, default_node_id)
+ local default_outbound = gen_outbound(default_node, "default")
+ if default_outbound then
+ table.insert(outbounds, default_outbound)
+ local rule = {
+ type = "field",
+ outboundTag = "default",
+ network = network
+ }
+ table.insert(rules, rule)
+ end
+ end
+
+ routing = {
+ domainStrategy = node.domainStrategy or "AsIs",
+ rules = rules
+ }
+
+ elseif node.protocol == "_balancing" then
+ if node.balancing_node then
+ local nodes = node.balancing_node
+ local length = #nodes
+ for i = 1, length do
+ local node = ucursor:get_all(appname, nodes[i])
+ local outbound = gen_outbound(node)
+ if outbound then table.insert(outbounds, outbound) end
+ end
+ routing = {
+ domainStrategy = node.domainStrategy or "AsIs",
+ balancers = {{tag = "balancer", selector = nodes}},
+ rules = {
+ {type = "field", network = "tcp,udp", balancerTag = "balancer"}
+ }
+ }
+ end
+ else
+ local outbound = gen_outbound(node)
+ if outbound then table.insert(outbounds, outbound) end
+ end
+
+ -- 额外传出连接
+ table.insert(outbounds, {protocol = "freedom", tag = "direct", settings = {keep = ""}})
+
+ local xray = {
+ log = {
+ -- error = string.format("/var/etc/passwall/%s.log", node[".name"]),
+ loglevel = "warning"
+ },
+ -- 传入连接
+ inbounds = inbounds,
+ -- 传出连接
+ outbounds = outbounds,
+ -- 路由
+ routing = routing
+ }
+ print(json.stringify(xray, 1))
+end
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray_proto.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray_proto.lua
new file mode 100644
index 0000000000..6d6582f61c
--- /dev/null
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/gen_xray_proto.lua
@@ -0,0 +1,80 @@
+local json = require "luci.jsonc"
+local inbounds = {}
+local outbounds = {}
+local routing = nil
+
+local local_proto = arg[1]
+local local_address = arg[2]
+local local_port = arg[3]
+local server_proto = arg[4]
+local server_address = arg[5]
+local server_port = arg[6]
+local server_username = arg[7] or "nil"
+local server_password = arg[8] or "nil"
+
+function gen_outbound(proto, address, port, username, password)
+ local result = {
+ protocol = proto,
+ streamSettings = {
+ network = "tcp",
+ security = "none"
+ },
+ settings = {
+ servers = {
+ {
+ address = address,
+ port = tonumber(port),
+ users = (username ~= "nil" and password ~= "nil") and {
+ {
+ user = username,
+ pass = password
+ }
+ } or nil
+ }
+ }
+ }
+ }
+ return result
+end
+
+if local_proto ~= "nil" and local_address ~= "nil" and local_port ~= "nil" then
+ local inbound = {
+ listen = local_address,
+ port = tonumber(local_port),
+ protocol = local_proto,
+ settings = {
+ accounts = nil
+ }
+ }
+ if local_proto == "socks" then
+ inbound.settings.auth = "noauth"
+ inbound.settings.udp = true
+ elseif local_proto == "http" then
+ inbound.settings.allowTransparent = false
+ end
+ table.insert(inbounds, inbound)
+end
+
+if server_proto ~= "nil" and server_address ~= "nil" and server_port ~= "nil" then
+ local outbound = gen_outbound(server_proto, server_address, server_port, server_username, server_password)
+ if outbound then table.insert(outbounds, outbound) end
+end
+
+-- 额外传出连接
+table.insert(outbounds, {
+ protocol = "freedom", tag = "direct", settings = {keep = ""}
+})
+
+local xray = {
+ log = {
+ -- error = string.format("/var/etc/passwall/%s.log", node[".name"]),
+ loglevel = "warning"
+ },
+ -- 传入连接
+ inbounds = inbounds,
+ -- 传出连接
+ outbounds = outbounds,
+ -- 路由
+ routing = routing
+}
+print(json.stringify(xray, 1))
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/kcptun.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/kcptun.lua
index 8ad20f894f..867875a120 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/kcptun.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/kcptun.lua
@@ -7,30 +7,14 @@ local api = require "luci.model.cbi.passwall.api.api"
local kcptun_api = "https://api.github.com/repos/xtaci/kcptun/releases/latest"
-function get_kcptun_file_path()
- return api.uci_get_type("global_app", "kcptun_client_file")
-end
-
-function get_kcptun_version(file)
- if file == nil then file = get_kcptun_file_path() end
-
- if file and file ~= "" then
- if not fs.access(file, "rwx", "rx", "rx") then
- fs.chmod(file, 755)
- end
-
- local info = util.trim(sys.exec("%s -v 2>/dev/null" % file))
-
- if info ~= "" then
- local tb = util.split(info, "%s+", nil, true)
- return tb[1] == "kcptun" and tb[3] or ""
- end
- end
-
- return ""
-end
-
function to_check(arch)
+ local app_path = api.get_kcptun_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Kcptun")
+ }
+ end
if not arch or arch == "" then arch = api.auto_get_arch() end
local file_tree, sub_version = api.get_file_info(arch)
@@ -38,8 +22,7 @@ function to_check(arch)
if file_tree == "" then
return {
code = 1,
- error = i18n.translate(
- "Can't determine ARCH, or ARCH not supported.")
+ error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
}
end
@@ -52,12 +35,9 @@ function to_check(arch)
}
end
+ local now_version = api.get_kcptun_version()
local remote_version = json.tag_name:match("[^v]+")
-
- local client_file = get_kcptun_file_path()
-
- local needs_update = api.compare_versions(get_kcptun_version(client_file),
- "<", remote_version)
+ local needs_update = api.compare_versions(now_version, "<", remote_version)
local html_url, download_url
if needs_update then
@@ -73,24 +53,30 @@ function to_check(arch)
if needs_update and not download_url then
return {
code = 1,
- now_version = get_kcptun_version(client_file),
+ now_version = now_version,
version = remote_version,
html_url = html_url,
- error = i18n.translate(
- "New version found, but failed to get new version download url.")
+ error = i18n.translate("New version found, but failed to get new version download url.")
}
end
return {
code = 0,
update = needs_update,
- now_version = get_kcptun_version(client_file),
+ now_version = now_version,
version = remote_version,
url = {html = html_url, download = download_url}
}
end
function to_download(url)
+ local app_path = api.get_kcptun_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Kcptun")
+ }
+ end
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
@@ -113,6 +99,13 @@ function to_download(url)
end
function to_extract(file, subfix)
+ local app_path = api.get_kcptun_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Kcptun")
+ }
+ end
if not file or file == "" or not fs.access(file) then
return {code = 1, error = i18n.translate("File path required.")}
end
@@ -157,47 +150,50 @@ function to_extract(file, subfix)
end
function to_move(file)
+ local app_path = api.get_kcptun_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Kcptun")
+ }
+ end
if not file or file == "" or not fs.access(file) then
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
return {code = 1, error = i18n.translate("Client file is required.")}
end
- local version = get_kcptun_version(file)
- if version == "" then
+ local new_version = api.get_kcptun_version(file)
+ if new_version == "" then
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
return {
code = 1,
- error = i18n.translate(
- "The client file is not suitable for current device.")
+ error = i18n.translate("The client file is not suitable for current device.")
}
end
- local client_file = get_kcptun_file_path()
- local client_file_bak
+ local app_path_bak
- if fs.access(client_file) then
- client_file_bak = client_file .. ".bak"
- api.exec("/bin/mv", {"-f", client_file, client_file_bak})
+ if fs.access(app_path) then
+ app_path_bak = app_path .. ".bak"
+ api.exec("/bin/mv", {"-f", app_path, app_path_bak})
end
- local result = api.exec("/bin/mv", {"-f", file, client_file}, nil,
- api.command_timeout) == 0
+ local result = api.exec("/bin/mv", {"-f", file, app_path}, nil, api.command_timeout) == 0
- if not result or not fs.access(client_file) then
+ if not result or not fs.access(app_path) then
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
- if client_file_bak then
- api.exec("/bin/mv", {"-f", client_file_bak, client_file})
+ if app_path_bak then
+ api.exec("/bin/mv", {"-f", app_path_bak, app_path})
end
return {
code = 1,
- error = i18n.translatef("Can't move new file to path: %s",
- client_file)
+ error = i18n.translatef("Can't move new file to path: %s", app_path)
}
end
- api.exec("/bin/chmod", {"755", client_file})
+ api.exec("/bin/chmod", {"755", app_path})
- if client_file_bak then api.exec("/bin/rm", {"-f", client_file_bak}) end
+ if app_path_bak then api.exec("/bin/rm", {"-f", app_path_bak}) end
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/trojan_go.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/trojan_go.lua
index 0ea54d4e75..f6a4ca3d4d 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/trojan_go.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/trojan_go.lua
@@ -3,12 +3,18 @@ local fs = require "nixio.fs"
local sys = require "luci.sys"
local util = require "luci.util"
local i18n = require "luci.i18n"
-local ipkg = require("luci.model.ipkg")
local api = require "luci.model.cbi.passwall.api.api"
local trojan_go_api = api.uci_get_type("global_app", "trojan_go_latest", "https://api.github.com/repos/trojan-gfw/trojan-go/releases/latest")
function to_check(arch)
+ local app_path = api.get_trojan_go_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Trojan-GO")
+ }
+ end
if not arch or arch == "" then arch = api.auto_get_arch() end
local file_tree, sub_version = api.get_file_info(arch)
@@ -16,8 +22,7 @@ function to_check(arch)
if file_tree == "" then
return {
code = 1,
- error = i18n.translate(
- "Can't determine ARCH, or ARCH not supported.")
+ error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
}
end
@@ -59,8 +64,7 @@ function to_check(arch)
now_version = now_version,
version = remote_version,
html_url = html_url,
- error = i18n.translate(
- "New version found, but failed to get new version download url.") .. " [linux-" .. file_tree .. ".zip]"
+ error = i18n.translate("New version found, but failed to get new version download url.") .. " [linux-" .. file_tree .. ".zip]"
}
end
@@ -74,6 +78,13 @@ function to_check(arch)
end
function to_download(url)
+ local app_path = api.get_trojan_go_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Trojan-GO")
+ }
+ end
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
@@ -96,10 +107,19 @@ function to_download(url)
end
function to_extract(file, subfix)
- local isinstall_unzip = ipkg.installed("unzip")
- if isinstall_unzip == nil then
- ipkg.update()
- ipkg.install("unzip")
+ local app_path = api.get_trojan_go_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Trojan-GO")
+ }
+ end
+ if sys.exec("echo -n $(opkg list-installed | grep -c unzip)") ~= "1" then
+ api.exec("/bin/rm", {"-f", file})
+ return {
+ code = 1,
+ error = i18n.translate("Not installed unzip, Can't unzip!")
+ }
end
if not file or file == "" or not fs.access(file) then
@@ -121,29 +141,35 @@ function to_extract(file, subfix)
end
function to_move(file)
+ local app_path = api.get_trojan_go_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Trojan-GO")
+ }
+ end
if not file or file == "" then
sys.call("/bin/rm -rf /tmp/trojan-go_extract.*")
return {code = 1, error = i18n.translate("Client file is required.")}
end
- local client_file = api.get_trojan_go_path()
- local client_file_bak
+ local app_path_bak
- if fs.access(client_file) then
- client_file_bak = client_file .. ".bak"
- api.exec("/bin/mv", {"-f", client_file, client_file_bak})
+ if fs.access(app_path) then
+ app_path_bak = app_path .. ".bak"
+ api.exec("/bin/mv", {"-f", app_path, app_path_bak})
end
- local result = api.exec("/bin/mv", { "-f", file .. "/trojan-go", client_file }, nil, api.command_timeout) == 0
+ local result = api.exec("/bin/mv", { "-f", file .. "/trojan-go", app_path }, nil, api.command_timeout) == 0
sys.call("/bin/rm -rf /tmp/trojan-go_extract.*")
- if not result or not fs.access(client_file) then
+ if not result or not fs.access(app_path) then
return {
code = 1,
- error = i18n.translatef("Can't move new file to path: %s", client_file)
+ error = i18n.translatef("Can't move new file to path: %s", app_path)
}
end
- api.exec("/bin/chmod", {"-R", "755", client_file})
+ api.exec("/bin/chmod", {"-R", "755", app_path})
return {code = 0}
end
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/v2ray.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/v2ray.lua
index e5339acba2..60841d6bcb 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/v2ray.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/v2ray.lua
@@ -3,26 +3,19 @@ local fs = require "nixio.fs"
local sys = require "luci.sys"
local util = require "luci.util"
local i18n = require "luci.i18n"
-local ipkg = require("luci.model.ipkg")
local api = require "luci.model.cbi.passwall.api.api"
local v2ray_api = "https://api.github.com/repos/v2fly/v2ray-core/releases/latest"
local is_armv7 = false
-function get_v2ray_file_path()
- return api.uci_get_type("global_app", "v2ray_file")
-end
-
-function get_v2ray_version()
- if get_v2ray_file_path() and get_v2ray_file_path() ~= "" then
- if fs.access(get_v2ray_file_path() .. "/v2ray") then
- return sys.exec("echo -n $(" .. get_v2ray_file_path() .. "/v2ray -version | awk '{print $2}' | sed -n 1P" .. ")")
- end
- end
- return ""
-end
-
function to_check(arch)
+ local app_path = api.get_v2ray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "V2ray")
+ }
+ end
if not arch or arch == "" then arch = api.auto_get_arch() end
local file_tree, sub_version = api.get_file_info(arch)
@@ -31,8 +24,7 @@ function to_check(arch)
if file_tree == "" then
return {
code = 1,
- error = i18n.translate(
- "Can't determine ARCH, or ARCH not supported.")
+ error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
}
end
@@ -48,8 +40,9 @@ function to_check(arch)
}
end
+ local now_version = api.get_v2ray_version()
local remote_version = json.tag_name:match("[^v]+")
- local needs_update = api.compare_versions(get_v2ray_version(), "<", remote_version)
+ local needs_update = api.compare_versions(now_version, "<", remote_version)
local html_url, download_url
if needs_update then
@@ -65,24 +58,30 @@ function to_check(arch)
if needs_update and not download_url then
return {
code = 1,
- now_version = get_v2ray_version(),
+ now_version = now_version,
version = remote_version,
html_url = html_url,
- error = i18n.translate(
- "New version found, but failed to get new version download url.")
+ error = i18n.translate("New version found, but failed to get new version download url.")
}
end
return {
code = 0,
update = needs_update,
- now_version = get_v2ray_version(),
+ now_version = now_version,
version = remote_version,
url = {html = html_url, download = download_url}
}
end
function to_download(url)
+ local app_path = api.get_v2ray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "V2ray")
+ }
+ end
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
@@ -105,16 +104,26 @@ function to_download(url)
end
function to_extract(file, subfix)
- local isinstall_unzip = ipkg.installed("unzip")
- if isinstall_unzip == nil then
- ipkg.update()
- ipkg.install("unzip")
+ local app_path = api.get_v2ray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "V2ray")
+ }
end
if not file or file == "" or not fs.access(file) then
return {code = 1, error = i18n.translate("File path required.")}
end
+ if sys.exec("echo -n $(opkg list-installed | grep -c unzip)") ~= "1" then
+ api.exec("/bin/rm", {"-f", file})
+ return {
+ code = 1,
+ error = i18n.translate("Not installed unzip, Can't unzip!")
+ }
+ end
+
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
local tmp_dir = util.trim(util.exec("mktemp -d -t v2ray_extract.XXXXXX"))
@@ -130,37 +139,35 @@ function to_extract(file, subfix)
end
function to_move(file)
+ local app_path = api.get_v2ray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "V2ray")
+ }
+ end
if not file or file == "" then
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
return {code = 1, error = i18n.translate("Client file is required.")}
end
- local client_file = get_v2ray_file_path()
-
- sys.call("mkdir -p " .. client_file)
-
if not arch or arch == "" then arch = api.auto_get_arch() end
local file_tree, sub_version = api.get_file_info(arch)
- if sub_version == "7" then is_armv7 = true end
+ local t = ""
+ sys.call("/etc/init.d/passwall stop")
local result = nil
- if is_armv7 and is_armv7 == true then
- result = api.exec("/bin/mv", {
- "-f", file .. "/v2ray_armv7", file .. "/v2ctl_armv7", client_file
- }, nil, api.command_timeout) == 0
- else
- result = api.exec("/bin/mv", {
- "-f", file .. "/v2ray", file .. "/v2ctl", client_file
- }, nil, api.command_timeout) == 0
- end
+ if sub_version and sub_version == "7" then t = "_armv7" end
+ result = api.exec("/bin/mv", { "-f", file .. "/v2ray" .. t, app_path }, nil, api.command_timeout) == 0
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
- if not result or not fs.access(client_file) then
+ if not result or not fs.access(app_path) then
return {
code = 1,
- error = i18n.translatef("Can't move new file to path: %s", client_file)
+ error = i18n.translatef("Can't move new file to path: %s", app_path)
}
end
-
- api.exec("/bin/chmod", {"-R", "755", client_file})
+
+ api.chmod_755(app_path)
+ sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
return {code = 0}
end
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/xray.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/xray.lua
new file mode 100644
index 0000000000..0666d4dc00
--- /dev/null
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/api/xray.lua
@@ -0,0 +1,173 @@
+module("luci.model.cbi.passwall.api.xray", package.seeall)
+local fs = require "nixio.fs"
+local sys = require "luci.sys"
+local util = require "luci.util"
+local i18n = require "luci.i18n"
+local api = require "luci.model.cbi.passwall.api.api"
+
+local xray_api = "https://api.github.com/repos/XTLS/Xray-core/releases/latest"
+local is_armv7 = false
+
+function to_check(arch)
+ local app_path = api.get_xray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Xray")
+ }
+ end
+ if not arch or arch == "" then arch = api.auto_get_arch() end
+
+ local file_tree, sub_version = api.get_file_info(arch)
+ if sub_version == "7" then is_armv7 = true end
+
+ if file_tree == "" then
+ return {
+ code = 1,
+ error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
+ }
+ end
+
+ if file_tree == "amd64" then file_tree = "64" end
+ if file_tree == "386" then file_tree = "32" end
+
+ local json = api.get_api_json(xray_api)
+
+ if json.tag_name == nil then
+ return {
+ code = 1,
+ error = i18n.translate("Get remote version info failed.")
+ }
+ end
+
+ local now_version = api.get_xray_version()
+ local remote_version = json.tag_name:match("[^v]+")
+ local needs_update = api.compare_versions(now_version, "<", remote_version)
+ local html_url, download_url
+
+ if needs_update then
+ html_url = json.html_url
+ for _, v in ipairs(json.assets) do
+ if v.name and v.name:match("linux%-" .. file_tree) then
+ download_url = v.browser_download_url
+ break
+ end
+ end
+ end
+
+ if needs_update and not download_url then
+ return {
+ code = 1,
+ now_version = now_version,
+ version = remote_version,
+ html_url = html_url,
+ error = i18n.translate("New version found, but failed to get new version download url.")
+ }
+ end
+
+ return {
+ code = 0,
+ update = needs_update,
+ now_version = now_version,
+ version = remote_version,
+ url = {html = html_url, download = download_url}
+ }
+end
+
+function to_download(url)
+ local app_path = api.get_xray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Xray")
+ }
+ end
+ if not url or url == "" then
+ return {code = 1, error = i18n.translate("Download url is required.")}
+ end
+
+ sys.call("/bin/rm -f /tmp/xray_download.*")
+
+ local tmp_file = util.trim(util.exec("mktemp -u -t xray_download.XXXXXX"))
+
+ local result = api.exec(api.curl, {api._unpack(api.curl_args), "-o", tmp_file, url}, nil, api.command_timeout) == 0
+
+ if not result then
+ api.exec("/bin/rm", {"-f", tmp_file})
+ return {
+ code = 1,
+ error = i18n.translatef("File download failed or timed out: %s", url)
+ }
+ end
+
+ return {code = 0, file = tmp_file}
+end
+
+function to_extract(file, subfix)
+ local app_path = api.get_xray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Xray")
+ }
+ end
+
+ if not file or file == "" or not fs.access(file) then
+ return {code = 1, error = i18n.translate("File path required.")}
+ end
+
+ if sys.exec("echo -n $(opkg list-installed | grep -c unzip)") ~= "1" then
+ api.exec("/bin/rm", {"-f", file})
+ return {
+ code = 1,
+ error = i18n.translate("Not installed unzip, Can't unzip!")
+ }
+ end
+
+ sys.call("/bin/rm -rf /tmp/xray_extract.*")
+ local tmp_dir = util.trim(util.exec("mktemp -d -t xray_extract.XXXXXX"))
+
+ local output = {}
+ api.exec("/usr/bin/unzip", {"-o", file, "-d", tmp_dir},
+ function(chunk) output[#output + 1] = chunk end)
+
+ local files = util.split(table.concat(output))
+
+ api.exec("/bin/rm", {"-f", file})
+
+ return {code = 0, file = tmp_dir}
+end
+
+function to_move(file)
+ local app_path = api.get_xray_path() or ""
+ if app_path == "" then
+ return {
+ code = 1,
+ error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", "Xray")
+ }
+ end
+ if not file or file == "" then
+ sys.call("/bin/rm -rf /tmp/xray_extract.*")
+ return {code = 1, error = i18n.translate("Client file is required.")}
+ end
+
+ if not arch or arch == "" then arch = api.auto_get_arch() end
+ local file_tree, sub_version = api.get_file_info(arch)
+ local t = ""
+ sys.call("/etc/init.d/passwall stop")
+ local result = nil
+ if sub_version and sub_version == "7" then t = "_armv7" end
+ result = api.exec("/bin/mv", { "-f", file .. "/xray" .. t, app_path }, nil, api.command_timeout) == 0
+ sys.call("/bin/rm -rf /tmp/xray_extract.*")
+ if not result or not fs.access(app_path) then
+ return {
+ code = 1,
+ error = i18n.translatef("Can't move new file to path: %s", app_path)
+ }
+ end
+
+ api.chmod_755(app_path)
+ sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
+
+ return {code = 0}
+end
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
index 8a1713a769..dbbad8e5b0 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
@@ -9,39 +9,39 @@ s = m:section(TypedSection, "global_app", translate("App Update"),
translate("Please confirm that your firmware supports FPU.") ..
"")
s.anonymous = true
+s:append(Template(appname .. "/app_update/xray_version"))
s:append(Template(appname .. "/app_update/v2ray_version"))
s:append(Template(appname .. "/app_update/trojan_go_version"))
s:append(Template(appname .. "/app_update/kcptun_version"))
s:append(Template(appname .. "/app_update/brook_version"))
----- V2ray Path
-o = s:option(Value, "v2ray_file", translate("V2ray Path"), translatef("if you want to run from memory, change the path, such as %s, Then save the application and update it manually.", "/tmp/v2ray/"))
-o.default = "/usr/bin/v2ray/"
+o = s:option(Value, "xray_file", translatef("%s App Path", "Xray"))
+o.default = "/usr/bin/xray"
o.rmempty = false
----- Trojan-Go Path
-o = s:option(Value, "trojan_go_file", translate("Trojan-Go Path"), translatef("if you want to run from memory, change the path, such as %s, Then save the application and update it manually.", "/tmp/trojan-go"))
+o = s:option(Value, "v2ray_file", translatef("%s App Path", "V2ray"))
+o.default = "/usr/bin/v2ray"
+o.rmempty = false
+
+o = s:option(Value, "trojan_go_file", translatef("%s App Path", "Trojan-Go"))
o.default = "/usr/bin/trojan-go"
o.rmempty = false
-o = s:option(Value, "trojan_go_latest", translate("Trojan-Go Version API"), translate("alternate API URL for version checking"))
+o = s:option(Value, "trojan_go_latest", translatef("Trojan-Go Version API"), translate("alternate API URL for version checking"))
o.default = "https://api.github.com/repos/peter-tank/trojan-go/releases/latest"
----- Kcptun client Path
-o = s:option(Value, "kcptun_client_file", translate("Kcptun Client Path"), translatef("if you want to run from memory, change the path, such as %s, Then save the application and update it manually.", "/tmp/kcptun-client"))
+o = s:option(Value, "kcptun_client_file", translatef("%s Client App Path", "Kcptun"))
o.default = "/usr/bin/kcptun-client"
o.rmempty = false
---[[
-o = s:option(Button, "_check_kcptun", translate("Manually update"), translatef("Make sure there is enough space to install %s", "kcptun"))
-o.template = appname .. "/kcptun"
-o.inputstyle = "apply"
-o.btnclick = "onBtnClick_kcptun(this);"
-o.id = "_kcptun-check_btn"]] --
-
----- Brook Path
-o = s:option(Value, "brook_file", translate("Brook Path"), translatef("if you want to run from memory, change the path, such as %s, Then save the application and update it manually.", "/tmp/brook"))
+o = s:option(Value, "brook_file", translatef("%s App Path", "Brook"))
o.default = "/usr/bin/brook"
o.rmempty = false
+o = s:option(DummyValue, "tips", " ")
+o.rawhtml = true
+o.cfgvalue = function(t, n)
+ return string.format('%s', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually."))
+end
+
return m
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/auto_switch.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/auto_switch.lua
index 2e7006202b..e9baecd5ec 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/auto_switch.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/auto_switch.lua
@@ -39,6 +39,8 @@ for i = 1, tcp_node_num, 1 do
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
end
+
+ o = s:option(Flag, "restore_switch" .. i, "TCP " .. i .. " " .. translate("Restore Switch"), translate("When detects main node is available, switch back to the main node."))
end
return m
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index 0c89f015c9..9788ef6dbd 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -76,17 +76,17 @@ o.rmempty = false
---- TCP Node
local tcp_node_num = tonumber(m:get("@global_other[0]", "tcp_node_num") or 1)
for i = 1, tcp_node_num, 1 do
+ o = s:taboption("Main", ListValue, "tcp_node" .. i, translate("TCP Node") .. " " .. i)
if i == 1 then
- o = s:taboption("Main", ListValue, "tcp_node" .. i, translate("TCP Node"))
- o.description = translate("For proxy specific list.")
-
+ o.title = translate("TCP Node")
+ o.description = translate("For proxy specific list.") .. o.description
if tonumber(m:get("@auto_switch[0]", "enable") or 0) == 1 then
- local now_node = luci.sys.exec(string.format("[ -f '/var/etc/%s/id/TCP_%s' ] && echo -n $(cat /var/etc/%s/id/TCP_%s)", appname, i, appname, i))
- if now_node and now_node ~= "" then
- local e = uci:get_all(appname, now_node)
+ local current_node = luci.sys.exec(string.format("[ -f '/var/etc/%s/id/TCP_%s' ] && echo -n $(cat /var/etc/%s/id/TCP_%s)", appname, i, appname, i))
+ if current_node and current_node ~= "" and current_node ~= "nil" then
+ local e = uci:get_all(appname, current_node)
if e then
local remarks = ""
- if e.type == "V2ray" and (e.protocol == "_balancing" or e.protocol == "_shunt") then
+ if e.protocol and (e.protocol == "_balancing" or e.protocol == "_shunt") then
remarks = "%s:[%s] " % {translatef(e.type .. e.protocol), e.remarks}
else
if e.use_kcp and e.use_kcp == "1" then
@@ -95,12 +95,10 @@ for i = 1, tcp_node_num, 1 do
remarks = "%s:[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
end
end
- o.description = o.description .. "
" ..translatef("Current node: %s", remarks)
+ o.description = translate("For proxy specific list.") .. "
" .. translatef("Current node: %s", '' .. remarks .. '')
end
end
end
- else
- o = s:taboption("Main", ListValue, "tcp_node" .. i, translate("TCP Node") .. " " .. i)
end
o:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
@@ -109,16 +107,14 @@ end
---- UDP Node
local udp_node_num = tonumber(m:get("@global_other[0]", "udp_node_num") or 1)
for i = 1, udp_node_num, 1 do
+ o = s:taboption("Main", ListValue, "udp_node" .. i, translate("UDP Node") .. " " .. i)
+ o:value("nil", translate("Close"))
if i == 1 then
- o = s:taboption("Main", ListValue, "udp_node" .. i, translate("UDP Node"))
- o.description = translate("For proxy game network, DNS hijack etc.") .. translate(" The selected server will not use Kcptun.")
- o:value("nil", translate("Close"))
+ o.title = translate("UDP Node")
+ o.description = translate("For proxy game network, DNS hijack etc.") .. o.description .. "
" .. translate("The selected server will not use Kcptun.")
o:value("tcp_", translate("Same as the tcp node"))
--o:value("tcp", translate("Same as the tcp node"))
--o:value("tcp_", translate("Same as the tcp node") .. "(" .. translate("New process") .. ")")
- else
- o = s:taboption("Main", ListValue, "udp_node" .. i, translate("UDP Node") .. " " .. i)
- o:value("nil", translate("Close"))
end
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
end
@@ -334,7 +330,7 @@ o.default = 9050
o.datatype = "port"
o.rmempty = false
-if api.is_finded("v2ray") then
+if api.is_finded("xray") or api.is_finded("v2ray") then
o = s:option(Value, "http_port", "HTTP" .. translate("Listen Port") .. " " .. translate("0 is not use"))
o.default = 0
o.datatype = "port"
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
index d2ddedfd4b..69a3c8af89 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
@@ -47,7 +47,10 @@ o:depends("balancing_enable", 1)
-- [[ Balancing Settings ]]--
s = m:section(TypedSection, "haproxy_config", "",
- "" .. translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.").."")
+ "" ..
+ translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") ..
+ "\n" .. translate("Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!") ..
+ "")
s.template = "cbi/tblsection"
s.sortable = true
s.anonymous = true
diff --git a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
index a14a6f2838..02c785f935 100644
--- a/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
+++ b/package/lienol/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
@@ -79,6 +79,10 @@ end
if api.is_finded("ssr-redir") then
type:value("SSR", translate("ShadowsocksR"))
end
+if api.is_finded("xray") then
+ type:value("Xray", translate("Xray"))
+ type.description = translate("Xray is currently directly compatible with V2ray and used.")
+end
if api.is_finded("v2ray") then
type:value("V2ray", translate("V2ray"))
end
@@ -110,6 +114,7 @@ protocol:value("trojan", translate("Trojan"))
protocol:value("_balancing", translate("Balancing"))
protocol:value("_shunt", translate("Shunt"))
protocol:depends("type", "V2ray")
+protocol:depends("type", "Xray")
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
@@ -128,7 +133,7 @@ balancing_node:depends("protocol", "_balancing")
-- 分流
uci:foreach(appname, "shunt_rules", function(e)
- o = s:option(ListValue, e[".name"], translate(e.remarks))
+ o = s:option(ListValue, e[".name"], '' .. translate(e.remarks) .. "")
o:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o:depends("protocol", "_shunt")
@@ -138,11 +143,29 @@ uci:foreach(appname, "shunt_rules", function(e)
o:depends("protocol", "_shunt")
end)
+shunt_tips = s:option(DummyValue, "shunt_tips", " ")
+shunt_tips.rawhtml = true
+shunt_tips.cfgvalue = function(t, n)
+ return string.format('%s', translate("No shunt rules? Click me to go to add."))
+end
+shunt_tips:depends("protocol", "_shunt")
+
default_node = s:option(ListValue, "default_node", translate("Default") .. " " .. translate("Node"))
default_node:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do default_node:value(v.id, v.remarks) end
default_node:depends("protocol", "_shunt")
+domainStrategy = s:option(ListValue, "domainStrategy", translate("Domain Strategy"))
+domainStrategy:value("AsIs")
+domainStrategy:value("IPIfNonMatch")
+domainStrategy:value("IPOnDemand")
+domainStrategy.description = "