luci: optimize app_update
* luci: optimize app_update code structure abstract the components update info into a module. Signed-off-by: nftbty <nftbty@gmail.com> * luci: app_update add chinadns-ng & fix hysteria Signed-off-by: nftbty <nftbty@gmail.com> * luci: app_update optimize match_file_name generating. - Update `auto_get_arch()`, and the generation of `match_file_name`. - The function `to_check()`,`to_download()`,`to_extract()`,`to_move()` moved into api.lua, some functions in api.lua used by the 4 functions are no longer need to be public anymore, so add `local` before them. Signed-off-by: nftbty <nftbty@gmail.com> --------- Signed-off-by: nftbty <nftbty@gmail.com>
This commit is contained in:
parent
8d2fcefe66
commit
5e84915db1
@ -8,11 +8,6 @@ local ucic = luci.model.uci.cursor()
|
||||
local http = require "luci.http"
|
||||
local util = require "luci.util"
|
||||
local i18n = require "luci.i18n"
|
||||
local brook = require("luci.passwall.brook")
|
||||
local v2ray = require("luci.passwall.v2ray")
|
||||
local xray = require("luci.passwall.xray")
|
||||
local trojan_go = require("luci.passwall.trojan_go")
|
||||
local hysteria = require("luci.passwall.hysteria")
|
||||
|
||||
function index()
|
||||
appname = require "luci.passwall.api".appname
|
||||
@ -72,16 +67,14 @@ function index()
|
||||
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
||||
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
|
||||
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).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, "v2ray_check"}, call("v2ray_check")).leaf = true
|
||||
entry({"admin", "services", appname, "v2ray_update"}, call("v2ray_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, "trojan_go_check"}, call("trojan_go_check")).leaf = true
|
||||
entry({"admin", "services", appname, "trojan_go_update"}, call("trojan_go_update")).leaf = true
|
||||
entry({"admin", "services", appname, "hysteria_check"}, call("hysteria_check")).leaf = true
|
||||
entry({"admin", "services", appname, "hysteria_update"}, call("hysteria_update")).leaf = true
|
||||
|
||||
--[[Components update]]
|
||||
local coms = require "luci.passwall.com"
|
||||
local com
|
||||
for com, _ in pairs(coms) do
|
||||
entry({"admin", "services", appname, "check_" .. com}, call("com_check", com)).leaf = true
|
||||
entry({"admin", "services", appname, "update_" .. com}, call("com_update", com)).leaf = true
|
||||
end
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
@ -410,94 +403,21 @@ function server_clear_log()
|
||||
luci.sys.call("echo '' > /tmp/log/passwall_server.log")
|
||||
end
|
||||
|
||||
function brook_check()
|
||||
local json = brook.to_check("")
|
||||
function com_check(comname)
|
||||
local json = api.to_check("",comname)
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function brook_update()
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "move" then
|
||||
json = brook.to_move(http.formvalue("file"))
|
||||
else
|
||||
json = brook.to_download(http.formvalue("url"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function v2ray_check()
|
||||
local json = v2ray.to_check("")
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function v2ray_update()
|
||||
function com_update(comname)
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "extract" then
|
||||
json = v2ray.to_extract(http.formvalue("file"), http.formvalue("subfix"))
|
||||
json = api.to_extract(comname, http.formvalue("file"), http.formvalue("subfix"))
|
||||
elseif task == "move" then
|
||||
json = v2ray.to_move(http.formvalue("file"))
|
||||
json = api.to_move(comname, http.formvalue("file"))
|
||||
else
|
||||
json = v2ray.to_download(http.formvalue("url"), http.formvalue("size"))
|
||||
json = api.to_download(comname, http.formvalue("url"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
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"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function trojan_go_check()
|
||||
local json = trojan_go.to_check("")
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function trojan_go_update()
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "extract" then
|
||||
json = trojan_go.to_extract(http.formvalue("file"), http.formvalue("subfix"))
|
||||
elseif task == "move" then
|
||||
json = trojan_go.to_move(http.formvalue("file"))
|
||||
else
|
||||
json = trojan_go.to_download(http.formvalue("url"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function hysteria_check()
|
||||
local json = hysteria.to_check("")
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function hysteria_update()
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "move" then
|
||||
json = hysteria.to_move(http.formvalue("file"))
|
||||
else
|
||||
json = hysteria.to_download(http.formvalue("url"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
|
@ -9,31 +9,15 @@ s = m:section(TypedSection, "global_app", translate("App Update"),
|
||||
translate("Please confirm that your firmware supports FPU.") ..
|
||||
"</font>")
|
||||
s.anonymous = true
|
||||
s:append(Template(appname .. "/app_update/v2ray_version"))
|
||||
s:append(Template(appname .. "/app_update/xray_version"))
|
||||
s:append(Template(appname .. "/app_update/trojan_go_version"))
|
||||
s:append(Template(appname .. "/app_update/brook_version"))
|
||||
s:append(Template(appname .. "/app_update/hysteria_version"))
|
||||
s:append(Template(appname .. "/app_update/app_version"))
|
||||
|
||||
o = s:option(Value, "v2ray_file", translatef("%s App Path", "V2ray"))
|
||||
o.default = "/usr/bin/v2ray"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "xray_file", translatef("%s App Path", "Xray"))
|
||||
o.default = "/usr/bin/xray"
|
||||
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, "brook_file", translatef("%s App Path", "Brook"))
|
||||
o.default = "/usr/bin/brook"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "hysteria_file", translatef("%s App Path", "Hysteria"))
|
||||
o.default = "/usr/bin/hysteria"
|
||||
o.rmempty = false
|
||||
local k, v
|
||||
local com = require "luci.passwall.com"
|
||||
for k, v in pairs(com) do
|
||||
o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name))
|
||||
o.default = v.default_path or ("/usr/bin/"..k)
|
||||
o.rmempty = false
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "tips", " ")
|
||||
o.rawhtml = true
|
||||
|
@ -1,4 +1,5 @@
|
||||
module("luci.passwall.api", package.seeall)
|
||||
local com = require "luci.passwall.com"
|
||||
fs = require "nixio.fs"
|
||||
sys = require "luci.sys"
|
||||
uci = require"luci.model.uci".cursor()
|
||||
@ -10,8 +11,8 @@ i18n = require "luci.i18n"
|
||||
appname = "passwall"
|
||||
curl_args = { "-skfL", "--connect-timeout 3", "--retry 3", "-m 60" }
|
||||
command_timeout = 300
|
||||
LEDE_BOARD = nil
|
||||
DISTRIB_TARGET = nil
|
||||
OPENWRT_ARCH = nil
|
||||
DISTRIB_ARCH = nil
|
||||
|
||||
LOG_FILE = "/tmp/log/" .. appname .. ".log"
|
||||
CACHE_PATH = "/tmp/etc/" .. appname .. "_tmp"
|
||||
@ -35,20 +36,20 @@ function exec_call(cmd)
|
||||
end
|
||||
|
||||
function base64Decode(text)
|
||||
local raw = text
|
||||
if not text then return '' end
|
||||
text = text:gsub("%z", "")
|
||||
text = text:gsub("%c", "")
|
||||
text = text:gsub("_", "/")
|
||||
text = text:gsub("-", "+")
|
||||
local mod4 = #text % 4
|
||||
text = text .. string.sub('====', mod4 + 1)
|
||||
local result = nixio.bin.b64decode(text)
|
||||
if result then
|
||||
return result:gsub("%z", "")
|
||||
else
|
||||
return raw
|
||||
end
|
||||
local raw = text
|
||||
if not text then return '' end
|
||||
text = text:gsub("%z", "")
|
||||
text = text:gsub("%c", "")
|
||||
text = text:gsub("_", "/")
|
||||
text = text:gsub("-", "+")
|
||||
local mod4 = #text % 4
|
||||
text = text .. string.sub('====', mod4 + 1)
|
||||
local result = nixio.bin.b64decode(text)
|
||||
if result then
|
||||
return result:gsub("%z", "")
|
||||
else
|
||||
return raw
|
||||
end
|
||||
end
|
||||
|
||||
function curl_base(url, file, args)
|
||||
@ -56,7 +57,7 @@ function curl_base(url, file, args)
|
||||
if file then
|
||||
args[#args + 1] = "-o " .. file
|
||||
end
|
||||
local cmd = string.format('curl %s "%s"', table_join(args), url)
|
||||
local cmd = string.format('curl %s "%s"', table_join(args), url)
|
||||
return exec_call(cmd)
|
||||
end
|
||||
|
||||
@ -163,7 +164,7 @@ function strToTable(str)
|
||||
if str == nil or type(str) ~= "string" then
|
||||
return {}
|
||||
end
|
||||
|
||||
|
||||
return loadstring("return " .. str)()
|
||||
end
|
||||
|
||||
@ -360,7 +361,7 @@ function uci_get_type_id(id, config, default)
|
||||
return value
|
||||
end
|
||||
|
||||
function chmod_755(file)
|
||||
local function chmod_755(file)
|
||||
if file and file ~= "" then
|
||||
if not fs.access(file, "rwx", "rx", "rx") then
|
||||
fs.chmod(file, 755)
|
||||
@ -387,13 +388,13 @@ function clone(org)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local res = {}
|
||||
copy(org, res)
|
||||
return res
|
||||
end
|
||||
|
||||
function get_bin_version_cache(file, cmd)
|
||||
local function get_bin_version_cache(file, cmd)
|
||||
sys.call("mkdir -p /tmp/etc/passwall_tmp")
|
||||
if fs.access(file) then
|
||||
chmod_755(file)
|
||||
@ -411,62 +412,17 @@ function get_bin_version_cache(file, cmd)
|
||||
return ""
|
||||
end
|
||||
|
||||
function get_v2ray_path()
|
||||
local path = uci_get_type("global_app", "v2ray_file")
|
||||
function get_app_path(app_name)
|
||||
local path = uci_get_type("global_app", app_name:gsub("%-","_") .. "_file")
|
||||
return path
|
||||
end
|
||||
|
||||
function get_v2ray_version(file)
|
||||
if file == nil then file = get_v2ray_path() end
|
||||
local cmd = "version | awk '{print $2}' | sed -n 1P"
|
||||
return get_bin_version_cache(file, cmd)
|
||||
function get_app_version(app_name, file)
|
||||
if file == nil then file = get_app_path(app_name) end
|
||||
return get_bin_version_cache(file, com[app_name].cmd_version)
|
||||
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
|
||||
local cmd = "-version | awk '{print $2}' | sed -n 1P"
|
||||
return get_bin_version_cache(file, cmd)
|
||||
end
|
||||
|
||||
function get_trojan_go_path()
|
||||
local path = uci_get_type("global_app", "trojan_go_file")
|
||||
return path
|
||||
end
|
||||
|
||||
function get_trojan_go_version(file)
|
||||
if file == nil then file = get_trojan_go_path() end
|
||||
local cmd = "-version | awk '{print $2}' | sed -n 1P"
|
||||
return get_bin_version_cache(file, cmd)
|
||||
end
|
||||
|
||||
function get_brook_path()
|
||||
local path = uci_get_type("global_app", "brook_file")
|
||||
return path
|
||||
end
|
||||
|
||||
function get_brook_version(file)
|
||||
if file == nil then file = get_brook_path() end
|
||||
local cmd = "-v | awk '{print $3}'"
|
||||
return get_bin_version_cache(file, cmd)
|
||||
end
|
||||
|
||||
function get_hysteria_path()
|
||||
local path = uci_get_type("global_app", "hysteria_file")
|
||||
return path
|
||||
end
|
||||
|
||||
function get_hysteria_version(file)
|
||||
if file == nil then file = get_hysteria_path() end
|
||||
local cmd = "-v | awk '{print $3}'"
|
||||
return get_bin_version_cache(file, cmd)
|
||||
end
|
||||
|
||||
function is_file(path)
|
||||
local function is_file(path)
|
||||
if path and #path > 1 then
|
||||
if sys.exec('[ -f "%s" ] && echo -n 1' % path) == "1" then
|
||||
return true
|
||||
@ -475,7 +431,7 @@ function is_file(path)
|
||||
return nil
|
||||
end
|
||||
|
||||
function is_dir(path)
|
||||
local function is_dir(path)
|
||||
if path and #path > 1 then
|
||||
if sys.exec('[ -d "%s" ] && echo -n 1' % path) == "1" then
|
||||
return true
|
||||
@ -484,7 +440,7 @@ function is_dir(path)
|
||||
return nil
|
||||
end
|
||||
|
||||
function get_final_dir(path)
|
||||
local function get_final_dir(path)
|
||||
if is_dir(path) then
|
||||
return path
|
||||
else
|
||||
@ -492,7 +448,7 @@ function get_final_dir(path)
|
||||
end
|
||||
end
|
||||
|
||||
function get_free_space(dir)
|
||||
local function get_free_space(dir)
|
||||
if dir == nil then dir = "/" end
|
||||
if sys.call("df -k " .. dir .. " >/dev/null 2>&1") == 0 then
|
||||
return tonumber(sys.exec("echo -n $(df -k " .. dir .. " | awk 'NR>1' | awk '{print $4}')"))
|
||||
@ -500,7 +456,7 @@ function get_free_space(dir)
|
||||
return 0
|
||||
end
|
||||
|
||||
function get_file_space(file)
|
||||
local 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}')"))
|
||||
@ -524,7 +480,7 @@ function table_join(t, s)
|
||||
return str
|
||||
end
|
||||
|
||||
function exec(cmd, args, writer, timeout)
|
||||
local function exec(cmd, args, writer, timeout)
|
||||
local os = require "os"
|
||||
local nixio = require "nixio"
|
||||
|
||||
@ -569,7 +525,7 @@ function exec(cmd, args, writer, timeout)
|
||||
end
|
||||
end
|
||||
|
||||
function compare_versions(ver1, comp, ver2)
|
||||
local function compare_versions(ver1, comp, ver2)
|
||||
local table = table
|
||||
|
||||
if not ver1 then ver1 = "" end
|
||||
@ -595,27 +551,37 @@ function compare_versions(ver1, comp, ver2)
|
||||
return not (comp == "<" or comp == ">")
|
||||
end
|
||||
|
||||
function auto_get_arch()
|
||||
local function auto_get_arch()
|
||||
local arch = nixio.uname().machine or ""
|
||||
if fs.access("/usr/lib/os-release") then
|
||||
LEDE_BOARD = sys.exec("echo -n $(grep 'LEDE_BOARD' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}')")
|
||||
if not OPENWRT_ARCH and fs.access("/usr/lib/os-release") then
|
||||
OPENWRT_ARCH = sys.exec("echo -n $(grep 'OPENWRT_ARCH' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}')")
|
||||
if OPENWRT_ARCH == "" then OPENWRT_ARCH = nil end
|
||||
end
|
||||
if fs.access("/etc/openwrt_release") then
|
||||
DISTRIB_TARGET = sys.exec("echo -n $(grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}')")
|
||||
if not DISTRIB_ARCH and fs.access("/etc/openwrt_release") then
|
||||
DISTRIB_ARCH = sys.exec("echo -n $(grep 'DISTRIB_ARCH' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}')")
|
||||
if DISTRIB_ARCH == "" then DISTRIB_ARCH = nil end
|
||||
end
|
||||
|
||||
if arch == "mips" then
|
||||
if LEDE_BOARD and LEDE_BOARD ~= "" then
|
||||
if string.match(LEDE_BOARD, "ramips") == "ramips" then
|
||||
arch = "ramips"
|
||||
else
|
||||
arch = sys.exec("echo '" .. LEDE_BOARD .. "' | grep -oE 'ramips|ar71xx'")
|
||||
if arch:match("^i[%d]86$") then
|
||||
arch = "x86"
|
||||
elseif arch:match("armv5") then -- armv5l
|
||||
arch = "armv5"
|
||||
elseif arch:match("armv6") then
|
||||
arch = "armv6"
|
||||
elseif arch:match("armv7") then -- armv7l
|
||||
arch = "armv7"
|
||||
end
|
||||
|
||||
if OPENWRT_ARCH or DISTRIB_ARCH then
|
||||
if arch == "mips" then
|
||||
if OPENWRT_ARCH and OPENWRT_ARCH:match("mipsel") == "mipsel"
|
||||
or DISTRIB_ARCH and DISTRIB_ARCH:match("mipsel") == "mipsel" then
|
||||
arch = "mipsel"
|
||||
end
|
||||
elseif DISTRIB_TARGET and DISTRIB_TARGET ~= "" then
|
||||
if string.match(DISTRIB_TARGET, "ramips") == "ramips" then
|
||||
arch = "ramips"
|
||||
else
|
||||
arch = sys.exec("echo '" .. DISTRIB_TARGET .. "' | grep -oE 'ramips|ar71xx'")
|
||||
elseif arch == "armv7" then
|
||||
if OPENWRT_ARCH and not OPENWRT_ARCH:match("vfp") and not OPENWRT_ARCH:match("neon")
|
||||
or DISTRIB_ARCH and not DISTRIB_ARCH:match("vfp") and not DISTRIB_ARCH:match("neon") then
|
||||
arch = "armv5"
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -623,44 +589,59 @@ function auto_get_arch()
|
||||
return util.trim(arch)
|
||||
end
|
||||
|
||||
function get_file_info(arch)
|
||||
local file_tree = ""
|
||||
local sub_version = ""
|
||||
local default_file_tree = {
|
||||
x86_64 = "amd64",
|
||||
x86 = "386",
|
||||
aarch64 = "arm64",
|
||||
mips = "mips",
|
||||
mipsel = "mipsle",
|
||||
armv5 = "arm.*5",
|
||||
armv6 = "arm.*6[^4]*",
|
||||
armv7 = "arm.*7",
|
||||
armv8 = "arm64"
|
||||
}
|
||||
|
||||
if arch == "x86_64" then
|
||||
file_tree = "amd64"
|
||||
elseif arch == "aarch64" then
|
||||
file_tree = "arm64"
|
||||
elseif arch == "ramips" then
|
||||
file_tree = "mipsle"
|
||||
elseif arch == "ar71xx" then
|
||||
file_tree = "mips"
|
||||
elseif arch:match("^i[%d]86$") then
|
||||
file_tree = "386"
|
||||
elseif arch:match("^armv[5-8]") then
|
||||
file_tree = "arm"
|
||||
sub_version = arch:match("[5-8]")
|
||||
if LEDE_BOARD and string.match(LEDE_BOARD, "bcm53xx") == "bcm53xx" then
|
||||
sub_version = "5"
|
||||
elseif DISTRIB_TARGET and string.match(DISTRIB_TARGET, "bcm53xx") ==
|
||||
"bcm53xx" then
|
||||
sub_version = "5"
|
||||
end
|
||||
sub_version = "5"
|
||||
end
|
||||
|
||||
return file_tree, sub_version
|
||||
end
|
||||
|
||||
function get_api_json(url)
|
||||
local function get_api_json(url)
|
||||
local jsonc = require "luci.jsonc"
|
||||
local return_code, content = curl_logic(url, nil, curl_args)
|
||||
if return_code ~= 0 or content == "" then return {} end
|
||||
return jsonc.parse(content) or {}
|
||||
end
|
||||
|
||||
function common_to_check(api_url, local_version, match_file_name)
|
||||
local json = get_api_json(api_url)
|
||||
local function check_path(app_name)
|
||||
local path = get_app_path(app_name) or ""
|
||||
if path == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("You did not fill in the %s path. Please save and apply then update manually.", app_name)
|
||||
}
|
||||
end
|
||||
return {
|
||||
code = 0,
|
||||
app_path = path
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch, app_name)
|
||||
local result = check_path(app_name)
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = auto_get_arch() end
|
||||
|
||||
local file_tree = com[app_name].file_tree[arch] or default_file_tree[arch] or ""
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
local local_version = get_app_version(app_name)
|
||||
local match_file_name = string.format(com[app_name].match_fmt_str, file_tree)
|
||||
local json = get_api_json(com[app_name]:get_url())
|
||||
|
||||
if #json > 0 then
|
||||
json = json[1]
|
||||
@ -710,4 +691,143 @@ function common_to_check(api_url, local_version, match_file_name)
|
||||
html_url = json.html_url,
|
||||
data = asset
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function to_download(app_name, url, size)
|
||||
local result = check_path(app_name)
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/".. app_name .."_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t ".. app_name .."_download.XXXXXX"))
|
||||
|
||||
if size then
|
||||
local kb1 = get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = curl_logic(url, tmp_file, curl_args)
|
||||
result = return_code == 0
|
||||
|
||||
if not result then
|
||||
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, zip = com[app_name].zipped }
|
||||
end
|
||||
|
||||
function to_extract(app_name, file, subfix)
|
||||
local result = check_path(app_name)
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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
|
||||
exec("/bin/rm", {"-f", file})
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Not installed unzip, Can't unzip!")
|
||||
}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/".. app_name .."_extract.*")
|
||||
|
||||
local new_file_size = get_file_space(file)
|
||||
local tmp_free_size = get_free_space("/tmp")
|
||||
if tmp_free_size <= 0 or tmp_free_size <= new_file_size then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t ".. app_name .."_extract.XXXXXX"))
|
||||
|
||||
local output = {}
|
||||
exec("/usr/bin/unzip", {"-o", file, app_name, "-d", tmp_dir},
|
||||
function(chunk) output[#output + 1] = chunk end)
|
||||
|
||||
local files = util.split(table.concat(output))
|
||||
|
||||
exec("/bin/rm", {"-f", file})
|
||||
|
||||
return {code = 0, file = tmp_dir}
|
||||
end
|
||||
|
||||
function to_move(app_name,file)
|
||||
local result = check_path(app_name)
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
local app_path = result.app_path
|
||||
local bin_path = file
|
||||
local cmd_rm_tmp = "/bin/rm -rf /tmp/" .. app_name .. "_download.*"
|
||||
if fs.stat(file, "type") == "dir" then
|
||||
bin_path = file .. "/" .. app_name
|
||||
cmd_rm_tmp = "/bin/rm -rf /tmp/" .. app_name .. "_extract.*"
|
||||
end
|
||||
|
||||
if not file or file == "" then
|
||||
sys.call(cmd_rm_tmp)
|
||||
return {code = 1, error = i18n.translate("Client file is required.")}
|
||||
end
|
||||
|
||||
local new_version = get_app_version(app_name, bin_path)
|
||||
if new_version == "" then
|
||||
sys.call(cmd_rm_tmp)
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")..app_name.."__"..bin_path
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*'.. app_name ..'" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = get_file_space(bin_path)
|
||||
local final_dir = get_final_dir(app_path)
|
||||
local final_dir_free_size = get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call(cmd_rm_tmp)
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = exec("/bin/mv", { "-f", bin_path, app_path }, nil, command_timeout) == 0
|
||||
|
||||
sys.call(cmd_rm_tmp)
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
||||
|
@ -1,135 +0,0 @@
|
||||
module("luci.passwall.brook", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local util = api.util
|
||||
local i18n = api.i18n
|
||||
|
||||
local pre_release_url = "https://api.github.com/repos/txthinking/brook/releases?per_page=1"
|
||||
local release_url = "https://api.github.com/repos/txthinking/brook/releases/latest"
|
||||
local api_url = release_url
|
||||
local app_path = api.get_brook_path() or ""
|
||||
|
||||
function check_path()
|
||||
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
|
||||
return {
|
||||
code = 0
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = api.auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = api.get_file_info(arch)
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
return api.common_to_check(api_url, api.get_brook_version(), "linux_" .. file_tree .. sub_version)
|
||||
end
|
||||
|
||||
function to_download(url, size)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/brook_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t brook_download.XXXXXX"))
|
||||
|
||||
if size then
|
||||
local kb1 = api.get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = api.curl_logic(url, tmp_file, api.curl_args)
|
||||
result = return_code == 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_move(file)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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 new_version = api.get_brook_version(file)
|
||||
if new_version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/brook_download.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*brook" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = api.get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = api.get_file_space(file)
|
||||
local final_dir = api.get_final_dir(app_path)
|
||||
local final_dir_free_size = api.get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call("/bin/rm -rf /tmp/brook_download.*")
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = api.exec("/bin/mv", {"-f", file, app_path}, nil, api.command_timeout) == 0
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/brook_download.*")
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
99
luci-app-passwall/luasrc/passwall/com.lua
Normal file
99
luci-app-passwall/luasrc/passwall/com.lua
Normal file
@ -0,0 +1,99 @@
|
||||
local _M = {}
|
||||
|
||||
local function gh_release_url(self)
|
||||
return "https://api.github.com/repos/" .. self.repo .. "/releases/latest"
|
||||
end
|
||||
|
||||
local function gh_pre_release_url(self)
|
||||
return "https://api.github.com/repos/" .. self.repo .. "/releases?per_page=1"
|
||||
end
|
||||
|
||||
_M.brook = {
|
||||
name = "Brook",
|
||||
repo = "txthinking/brook",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-v | awk '{print $3}'",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/brook",
|
||||
match_fmt_str = "linux_%s$",
|
||||
file_tree = {}
|
||||
}
|
||||
|
||||
_M.hysteria = {
|
||||
name = "Hysteria",
|
||||
repo = "HyNetwork/hysteria",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-v | awk '{print $3}'",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/hysteria",
|
||||
match_fmt_str = "linux%%-%s$",
|
||||
file_tree = {
|
||||
armv6 = "arm",
|
||||
armv7 = "arm"
|
||||
}
|
||||
}
|
||||
|
||||
_M["trojan-go"] = {
|
||||
name = "Trojan-Go",
|
||||
repo = "p4gefau1t/trojan-go",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-version | awk '{print $2}' | sed -n 1P",
|
||||
zipped = true,
|
||||
default_path = "/usr/bin/trojan-go",
|
||||
match_fmt_str = "linux%%-%s%%.zip",
|
||||
file_tree = {
|
||||
aarch64 = "armv8",
|
||||
armv8 = "armv8",
|
||||
mips = "mips%-hardfloat",
|
||||
mipsel = "mipsle%-hardfloat"
|
||||
}
|
||||
}
|
||||
|
||||
_M.v2ray = {
|
||||
name = "V2ray",
|
||||
repo = "v2fly/v2ray-core",
|
||||
get_url = gh_pre_release_url,
|
||||
cmd_version = "version | awk '{print $2}' | sed -n 1P",
|
||||
zipped = true,
|
||||
default_path = "/usr/bin/v2ray",
|
||||
match_fmt_str = "linux%%-%s",
|
||||
file_tree = {
|
||||
x86_64 = "64",
|
||||
x86 = "32",
|
||||
mips = "mips32",
|
||||
mipsel = "mips32le"
|
||||
}
|
||||
}
|
||||
|
||||
_M.xray = {
|
||||
name = "Xray",
|
||||
repo = "XTLS/Xray-core",
|
||||
get_url = gh_pre_release_url,
|
||||
cmd_version = _M.v2ray.cmd_version,
|
||||
zipped = true,
|
||||
default_path = "/usr/bin/xray",
|
||||
match_fmt_str = _M.v2ray.match_fmt_str,
|
||||
file_tree = _M.v2ray.file_tree
|
||||
}
|
||||
|
||||
_M["chinadns-ng"] = {
|
||||
name = "ChinaDNS-NG",
|
||||
repo = "zfl9/chinadns-ng",
|
||||
get_url = gh_pre_release_url,
|
||||
cmd_version = "-V | awk '{print $2}'",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/chinadns-ng",
|
||||
match_fmt_str = "%s$",
|
||||
file_tree = {
|
||||
x86_64 = "x86_64",
|
||||
x86 = "i686",
|
||||
mipsel = "mipsel",
|
||||
aarch64 = "aarch64",
|
||||
armv5 = "arm%-eabi",
|
||||
armv6 = "armv6%-eabihf",
|
||||
armv7 = "armv7l%-eabihf",
|
||||
armv8 = "aarch64"
|
||||
}
|
||||
}
|
||||
|
||||
return _M
|
@ -1,135 +0,0 @@
|
||||
module("luci.passwall.hysteria", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local util = api.util
|
||||
local i18n = api.i18n
|
||||
|
||||
local pre_release_url = "https://api.github.com/repos/HyNetwork/hysteria/releases?per_page=1"
|
||||
local release_url = "https://api.github.com/repos/HyNetwork/hysteria/releases/latest"
|
||||
local api_url = release_url
|
||||
local app_path = api.get_hysteria_path() or ""
|
||||
|
||||
function check_path()
|
||||
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.", "hysteria")
|
||||
}
|
||||
end
|
||||
return {
|
||||
code = 0
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = api.auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = api.get_file_info(arch)
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
return api.common_to_check(api_url, api.get_hysteria_version(), "linux%-" .. file_tree .. sub_version)
|
||||
end
|
||||
|
||||
function to_download(url, size)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/hysteria_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t hysteria_download.XXXXXX"))
|
||||
|
||||
if size then
|
||||
local kb1 = api.get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = api.curl_logic(url, tmp_file, api.curl_args)
|
||||
result = return_code == 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_move(file)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not file or file == "" or not fs.access(file) then
|
||||
sys.call("/bin/rm -rf /tmp/hysteria_download.*")
|
||||
return {code = 1, error = i18n.translate("Client file is required.")}
|
||||
end
|
||||
|
||||
local new_version = api.get_hysteria_version(file)
|
||||
if new_version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/hysteria_download.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*hysteria" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = api.get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = api.get_file_space(file)
|
||||
local final_dir = api.get_final_dir(app_path)
|
||||
local final_dir_free_size = api.get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call("/bin/rm -rf /tmp/hysteria_download.*")
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = api.exec("/bin/mv", {"-f", file, app_path}, nil, api.command_timeout) == 0
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/hysteria_download.*")
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
@ -18,7 +18,7 @@ local ip6t_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ip6t_bi
|
||||
local nft_flag = api.is_finded("fw4") and "1" or "0"
|
||||
|
||||
local function log(...)
|
||||
local f, err = io.open(LOG_APP_FILE, "a")
|
||||
local f, err = io.open(LOG_APP_FILE, "a")
|
||||
if f and err == nil then
|
||||
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
|
||||
f:write(str .. "\n")
|
||||
@ -91,12 +91,12 @@ local function start()
|
||||
end
|
||||
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
|
||||
cmd(string.format("touch %s", LOG_APP_FILE))
|
||||
if nft_flag == "0" then
|
||||
if nft_flag == "0" then
|
||||
ipt("-N PSW-SERVER")
|
||||
ipt("-I INPUT -j PSW-SERVER")
|
||||
ip6t("-N PSW-SERVER")
|
||||
ip6t("-I INPUT -j PSW-SERVER")
|
||||
else
|
||||
else
|
||||
cmd("nft add chain inet fw4 PSW-SERVER\n")
|
||||
cmd("nft insert rule inet fw4 input position 0 counter jump PSW-SERVER")
|
||||
end
|
||||
@ -144,10 +144,10 @@ local function start()
|
||||
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
|
||||
elseif type == "V2ray" then
|
||||
config = require(require_dir .. "util_xray").gen_config_server(user)
|
||||
bin = ln_run(api.get_v2ray_path(), "v2ray", "run -c " .. config_file, log_path)
|
||||
bin = ln_run(api.get_app_path("v2ray"), "v2ray", "run -c " .. config_file, log_path)
|
||||
elseif type == "Xray" then
|
||||
config = require(require_dir .. "util_xray").gen_config_server(user)
|
||||
bin = ln_run(api.get_xray_path(), "xray", "run -c " .. config_file, log_path)
|
||||
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
|
||||
elseif type == "Trojan" then
|
||||
config = require(require_dir .. "util_trojan").gen_config_server(user)
|
||||
bin = ln_run("/usr/sbin/trojan", "trojan", "-c " .. config_file, log_path)
|
||||
@ -156,7 +156,7 @@ local function start()
|
||||
bin = ln_run("/usr/sbin/trojan-plus", "trojan-plus", "-c " .. config_file, log_path)
|
||||
elseif type == "Trojan-Go" then
|
||||
config = require(require_dir .. "util_trojan").gen_config_server(user)
|
||||
bin = ln_run(api.get_trojan_go_path(), "trojan-go", "-config " .. config_file, log_path)
|
||||
bin = ln_run(api.get_app_path("trojan-go"), "trojan-go", "-config " .. config_file, log_path)
|
||||
elseif type == "Brook" then
|
||||
local brook_protocol = user.protocol
|
||||
local brook_password = user.password
|
||||
@ -165,10 +165,10 @@ local function start()
|
||||
if brook_protocol == "wsserver" and brook_path then
|
||||
brook_path_arg = " --path " .. brook_path
|
||||
end
|
||||
bin = ln_run(api.get_brook_path(), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path)
|
||||
bin = ln_run(api.get_app_path("brook"), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path)
|
||||
elseif type == "Hysteria" then
|
||||
config = require(require_dir .. "util_hysteria").gen_config_server(user)
|
||||
bin = ln_run(api.get_hysteria_path(), "hysteria", "-c " .. config_file .. " server", log_path)
|
||||
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
|
||||
end
|
||||
|
||||
if next(config) then
|
||||
@ -193,7 +193,7 @@ local function start()
|
||||
ipt(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
ip6t(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
end
|
||||
else
|
||||
else
|
||||
cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto tcp tcp dport {%s} accept', port))
|
||||
if udp_forward == 1 then
|
||||
cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto udp udp dport {%s} accept', port))
|
||||
@ -214,7 +214,7 @@ local function stop()
|
||||
ip6t("-D INPUT -j PSW-SERVER 2>/dev/null")
|
||||
ip6t("-F PSW-SERVER 2>/dev/null")
|
||||
ip6t("-X PSW-SERVER 2>/dev/null")
|
||||
else
|
||||
else
|
||||
nft_cmd="handles=$(nft -a list chain inet fw4 input | grep -E \"PSW-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done"
|
||||
cmd(nft_cmd)
|
||||
cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null")
|
||||
@ -226,7 +226,7 @@ end
|
||||
if action then
|
||||
if action == "start" then
|
||||
start()
|
||||
elseif action == "stop" then
|
||||
elseif action == "stop" then
|
||||
stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,184 +0,0 @@
|
||||
module("luci.passwall.trojan_go", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local util = api.util
|
||||
local i18n = api.i18n
|
||||
|
||||
local pre_release_url = "https://api.github.com/repos/p4gefau1t/trojan-go/releases?per_page=1"
|
||||
local release_url = "https://api.github.com/repos/p4gefau1t/trojan-go/releases/latest"
|
||||
local api_url = release_url
|
||||
local app_path = api.get_trojan_go_path() or ""
|
||||
|
||||
function check_path()
|
||||
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
|
||||
return {
|
||||
code = 0
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = api.auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = api.get_file_info(arch)
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
if file_tree == "mips" then file_tree = "mips%-hardfloat" end
|
||||
if file_tree == "mipsle" then file_tree = "mipsle%-hardfloat" end
|
||||
if file_tree == "arm64" then
|
||||
file_tree = "armv8"
|
||||
else
|
||||
if sub_version and sub_version:match("^[5-8]$") then file_tree = file_tree .. "v" .. sub_version end
|
||||
end
|
||||
|
||||
return api.common_to_check(api_url, api.get_trojan_go_version(), "linux%-" .. file_tree .. "%.zip")
|
||||
end
|
||||
|
||||
function to_download(url, size)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/trojan-go_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t trojan-go_download.XXXXXX"))
|
||||
|
||||
if size then
|
||||
local kb1 = api.get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = api.curl_logic(url, tmp_file, api.curl_args)
|
||||
result = return_code == 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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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/trojan-go_extract.*")
|
||||
|
||||
local new_file_size = api.get_file_space(file)
|
||||
local tmp_free_size = api.get_free_space("/tmp")
|
||||
if tmp_free_size <= 0 or tmp_free_size <= new_file_size then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t trojan-go_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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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 bin_path = file .. "/trojan-go"
|
||||
|
||||
local new_version = api.get_trojan_go_version(bin_path)
|
||||
if new_version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/trojan-go_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*trojan-go" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = api.get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = api.get_file_space(bin_path)
|
||||
local final_dir = api.get_final_dir(app_path)
|
||||
local final_dir_free_size = api.get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call("/bin/rm -rf /tmp/trojan-go_extract.*")
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = api.exec("/bin/mv", { "-f", bin_path, app_path }, nil, api.command_timeout) == 0
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/trojan-go_extract.*")
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
@ -568,7 +568,7 @@ function gen_config(var)
|
||||
end
|
||||
table.insert(inbounds, inbound)
|
||||
end
|
||||
|
||||
|
||||
if tcp_redir_port or udp_redir_port then
|
||||
local inbound = {
|
||||
protocol = "dokodemo-door",
|
||||
@ -576,7 +576,7 @@ function gen_config(var)
|
||||
streamSettings = {sockopt = {tproxy = "tproxy"}},
|
||||
sniffing = {enabled = sniffing and true or false, destOverride = {"http", "tls", (remote_dns_fake) and "fakedns"}, metadataOnly = false, routeOnly = route_only and true or nil, domainsExcluded = (sniffing and not route_only) and get_domain_excluded() or nil}
|
||||
}
|
||||
|
||||
|
||||
if tcp_redir_port then
|
||||
local tcp_inbound = api.clone(inbound)
|
||||
tcp_inbound.tag = "tcp_redir"
|
||||
@ -585,7 +585,7 @@ function gen_config(var)
|
||||
tcp_inbound.streamSettings.sockopt.tproxy = tcp_proxy_way
|
||||
table.insert(inbounds, tcp_inbound)
|
||||
end
|
||||
|
||||
|
||||
if udp_redir_port then
|
||||
local udp_inbound = api.clone(inbound)
|
||||
udp_inbound.tag = "udp_redir"
|
||||
@ -594,10 +594,10 @@ function gen_config(var)
|
||||
table.insert(inbounds, udp_inbound)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if node.protocol == "_shunt" then
|
||||
local rules = {}
|
||||
|
||||
|
||||
local default_node_id = node.default_node or "_direct"
|
||||
local default_outboundTag
|
||||
if default_node_id == "_direct" then
|
||||
@ -656,7 +656,7 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
uci:foreach(appname, "shunt_rules", function(e)
|
||||
local name = e[".name"]
|
||||
if name and e.remarks then
|
||||
@ -724,7 +724,7 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
if outboundTag then
|
||||
if outboundTag == "default" then
|
||||
if outboundTag == "default" then
|
||||
outboundTag = default_outboundTag
|
||||
end
|
||||
local protocols = nil
|
||||
@ -768,15 +768,15 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if default_outboundTag then
|
||||
|
||||
if default_outboundTag then
|
||||
table.insert(rules, {
|
||||
type = "field",
|
||||
outboundTag = default_outboundTag,
|
||||
network = "tcp,udp"
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
routing = {
|
||||
domainStrategy = node.domainStrategy or "AsIs",
|
||||
domainMatcher = node.domainMatcher or "hybrid",
|
||||
@ -825,19 +825,19 @@ function gen_config(var)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if remote_dns_server or remote_dns_doh_url or remote_dns_fake then
|
||||
local rules = {}
|
||||
local _remote_dns_proto = "tcp"
|
||||
local _remote_dns_host
|
||||
|
||||
|
||||
if not routing then
|
||||
routing = {
|
||||
domainStrategy = "IPOnDemand",
|
||||
rules = {}
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
dns = {
|
||||
tag = "dns-in1",
|
||||
hosts = {},
|
||||
@ -848,16 +848,16 @@ function gen_config(var)
|
||||
clientIp = (dns_client_ip and dns_client_ip ~= "") and dns_client_ip or nil,
|
||||
queryStrategy = (dns_query_strategy and dns_query_strategy ~= "") and dns_query_strategy or "UseIPv4"
|
||||
}
|
||||
|
||||
|
||||
local _remote_dns = {
|
||||
--_flag = "remote"
|
||||
}
|
||||
|
||||
|
||||
if remote_dns_tcp_server then
|
||||
_remote_dns.address = remote_dns_tcp_server
|
||||
_remote_dns.port = tonumber(remote_dns_port)
|
||||
end
|
||||
|
||||
|
||||
if remote_dns_doh_url and remote_dns_doh_host then
|
||||
if remote_dns_server and remote_dns_doh_host ~= remote_dns_server and not api.is_ip(remote_dns_doh_host) then
|
||||
dns.hosts[remote_dns_doh_host] = remote_dns_server
|
||||
@ -867,7 +867,7 @@ function gen_config(var)
|
||||
_remote_dns.port = tonumber(remote_dns_port)
|
||||
_remote_dns_proto = "doh"
|
||||
end
|
||||
|
||||
|
||||
if remote_dns_fake then
|
||||
remote_dns_server = "1.1.1.1"
|
||||
fakedns = {}
|
||||
@ -883,9 +883,9 @@ function gen_config(var)
|
||||
end
|
||||
_remote_dns.address = "fakedns"
|
||||
end
|
||||
|
||||
|
||||
table.insert(dns.servers, _remote_dns)
|
||||
|
||||
|
||||
if dns_listen_port then
|
||||
table.insert(inbounds, {
|
||||
listen = "127.0.0.1",
|
||||
@ -898,7 +898,7 @@ function gen_config(var)
|
||||
network = "tcp,udp"
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
table.insert(outbounds, {
|
||||
tag = "dns-out",
|
||||
protocol = "dns",
|
||||
@ -908,7 +908,7 @@ function gen_config(var)
|
||||
network = "tcp",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
table.insert(routing.rules, 1, {
|
||||
type = "field",
|
||||
inboundTag = {
|
||||
@ -917,7 +917,7 @@ function gen_config(var)
|
||||
outboundTag = "dns-out"
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
local default_dns_flag = "remote"
|
||||
if node_id and tcp_redir_port then
|
||||
@ -928,7 +928,7 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if dns.servers and #dns.servers > 0 then
|
||||
local dns_servers = nil
|
||||
for index, value in ipairs(dns.servers) do
|
||||
@ -1003,7 +1003,7 @@ function gen_config(var)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local default_rule_index = #routing.rules > 0 and #routing.rules or 1
|
||||
for index, value in ipairs(routing.rules) do
|
||||
if value["_flag"] == "default" then
|
||||
@ -1015,17 +1015,17 @@ function gen_config(var)
|
||||
local t = rules[#rules + 1 - index]
|
||||
table.insert(routing.rules, default_rule_index, t)
|
||||
end
|
||||
|
||||
|
||||
local dns_hosts_len = 0
|
||||
for key, value in pairs(dns.hosts) do
|
||||
dns_hosts_len = dns_hosts_len + 1
|
||||
end
|
||||
|
||||
|
||||
if dns_hosts_len == 0 then
|
||||
dns.hosts = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if inbounds or outbounds then
|
||||
local config = {
|
||||
log = {
|
||||
@ -1077,7 +1077,7 @@ function gen_config(var)
|
||||
tag = "blackhole"
|
||||
})
|
||||
return jsonc.stringify(config, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function gen_proto_config(var)
|
||||
@ -1120,7 +1120,7 @@ function gen_proto_config(var)
|
||||
end
|
||||
table.insert(inbounds, inbound)
|
||||
end
|
||||
|
||||
|
||||
if local_http_address and local_http_port then
|
||||
local inbound = {
|
||||
listen = local_http_address,
|
||||
@ -1140,7 +1140,7 @@ function gen_proto_config(var)
|
||||
end
|
||||
table.insert(inbounds, inbound)
|
||||
end
|
||||
|
||||
|
||||
if server_proto ~= "nil" and server_address ~= "nil" and server_port ~= "nil" then
|
||||
local outbound = {
|
||||
protocol = server_proto,
|
||||
@ -1165,12 +1165,12 @@ function gen_proto_config(var)
|
||||
}
|
||||
if outbound then table.insert(outbounds, outbound) end
|
||||
end
|
||||
|
||||
|
||||
-- 额外传出连接
|
||||
table.insert(outbounds, {
|
||||
protocol = "freedom", tag = "direct", settings = {keep = ""}, sockopt = {mark = 255}
|
||||
})
|
||||
|
||||
|
||||
local config = {
|
||||
log = {
|
||||
loglevel = "warning"
|
||||
|
@ -1,182 +0,0 @@
|
||||
module("luci.passwall.v2ray", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local util = api.util
|
||||
local i18n = api.i18n
|
||||
|
||||
local pre_release_url = "https://api.github.com/repos/v2fly/v2ray-core/releases?per_page=1"
|
||||
local release_url = "https://api.github.com/repos/v2fly/v2ray-core/releases/latest"
|
||||
local api_url = pre_release_url
|
||||
local app_path = api.get_v2ray_path() or ""
|
||||
|
||||
function check_path()
|
||||
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
|
||||
return {
|
||||
code = 0
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = api.auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = api.get_file_info(arch)
|
||||
|
||||
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
|
||||
if file_tree == "mipsle" then file_tree = "mips32le" end
|
||||
if file_tree == "mips" then file_tree = "mips32" end
|
||||
if file_tree == "arm" then file_tree = "arm32" end
|
||||
|
||||
return api.common_to_check(api_url, api.get_v2ray_version(), "linux%-" .. file_tree .. (sub_version ~= "" and ".+" .. sub_version or ""))
|
||||
end
|
||||
|
||||
function to_download(url, size)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/v2ray_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t v2ray_download.XXXXXX"))
|
||||
|
||||
if size then
|
||||
local kb1 = api.get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = api.curl_logic(url, tmp_file, api.curl_args)
|
||||
result = return_code == 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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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 new_file_size = api.get_file_space(file)
|
||||
local tmp_free_size = api.get_free_space("/tmp")
|
||||
if tmp_free_size <= 0 or tmp_free_size <= new_file_size then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t v2ray_extract.XXXXXX"))
|
||||
|
||||
local output = {}
|
||||
api.exec("/usr/bin/unzip", {"-o", file, "v2ray", "-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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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 bin_path = file .. "/v2ray"
|
||||
|
||||
local new_version = api.get_v2ray_version(bin_path)
|
||||
if new_version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*v2ray" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = api.get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = api.get_file_space(bin_path)
|
||||
local final_dir = api.get_final_dir(app_path)
|
||||
local final_dir_free_size = api.get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = api.exec("/bin/mv", { "-f", bin_path, app_path }, nil, api.command_timeout) == 0
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
@ -1,182 +0,0 @@
|
||||
module("luci.passwall.xray", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local util = api.util
|
||||
local i18n = api.i18n
|
||||
|
||||
local pre_release_url = "https://api.github.com/repos/XTLS/Xray-core/releases?per_page=1"
|
||||
local release_url = "https://api.github.com/repos/XTLS/Xray-core/releases/latest"
|
||||
local api_url = pre_release_url
|
||||
local app_path = api.get_xray_path() or ""
|
||||
|
||||
function check_path()
|
||||
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
|
||||
return {
|
||||
code = 0
|
||||
}
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
end
|
||||
|
||||
if not arch or arch == "" then arch = api.auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = api.get_file_info(arch)
|
||||
|
||||
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
|
||||
if file_tree == "mipsle" then file_tree = "mips32le" end
|
||||
if file_tree == "mips" then file_tree = "mips32" end
|
||||
if file_tree == "arm" then file_tree = "arm32" end
|
||||
|
||||
return api.common_to_check(api_url, api.get_xray_version(), "linux%-" .. file_tree .. (sub_version ~= "" and ".+" .. sub_version or ""))
|
||||
end
|
||||
|
||||
function to_download(url, size)
|
||||
local result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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"))
|
||||
|
||||
if size then
|
||||
local kb1 = api.get_free_space("/tmp")
|
||||
if tonumber(size) > tonumber(kb1) then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
end
|
||||
|
||||
local return_code, result = api.curl_logic(url, tmp_file, api.curl_args)
|
||||
result = return_code == 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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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 new_file_size = api.get_file_space(file)
|
||||
local tmp_free_size = api.get_free_space("/tmp")
|
||||
if tmp_free_size <= 0 or tmp_free_size <= new_file_size then
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", "/tmp")}
|
||||
end
|
||||
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t xray_extract.XXXXXX"))
|
||||
|
||||
local output = {}
|
||||
api.exec("/usr/bin/unzip", {"-o", file, "xray", "-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 result = check_path()
|
||||
if result.code ~= 0 then
|
||||
return result
|
||||
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
|
||||
|
||||
local bin_path = file .. "/xray"
|
||||
|
||||
local new_version = api.get_xray_version(bin_path)
|
||||
if new_version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/xray_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device.")
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall/.*xray" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall stop")
|
||||
end
|
||||
|
||||
local old_app_size = 0
|
||||
if fs.access(app_path) then
|
||||
old_app_size = api.get_file_space(app_path)
|
||||
end
|
||||
local new_app_size = api.get_file_space(bin_path)
|
||||
local final_dir = api.get_final_dir(app_path)
|
||||
local final_dir_free_size = api.get_free_space(final_dir)
|
||||
if final_dir_free_size > 0 then
|
||||
final_dir_free_size = final_dir_free_size + old_app_size
|
||||
if new_app_size > final_dir_free_size then
|
||||
sys.call("/bin/rm -rf /tmp/xray_extract.*")
|
||||
return {code = 1, error = i18n.translatef("%s not enough space.", final_dir)}
|
||||
end
|
||||
end
|
||||
|
||||
result = api.exec("/bin/mv", { "-f", bin_path, app_path }, nil, api.command_timeout) == 0
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/xray_extract.*")
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall restart >/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
return {code = 0}
|
||||
end
|
@ -0,0 +1,193 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local com = require "luci.passwall.com"
|
||||
local version = {}
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var appInfoList = new Array();
|
||||
var inProgressCount = 0;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
//window.onload = function () {};
|
||||
|
||||
function addPageNotice() {
|
||||
if (inProgressCount === 0) {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
inProgressCount++;
|
||||
}
|
||||
|
||||
function removePageNotice() {
|
||||
inProgressCount--;
|
||||
if (inProgressCount === 0) {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onUpdateSuccess(btn) {
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
if (inProgressCount === 0) {
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestError(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
if (errorMessage && ckeckDetailElm) {
|
||||
ckeckDetailElm.textContent = errorMessage
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick(btn, app) {
|
||||
if (appInfoList[app] === undefined) {
|
||||
checkUpdate(btn, app);
|
||||
} else {
|
||||
doUpdate(btn, app);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate(btn, app) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
if (ckeckDetailElm) {
|
||||
ckeckDetailElm.textContent = "";
|
||||
}
|
||||
XHR.get('<%=api.url("check_")%>' + app, {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice();
|
||||
if (json.code) {
|
||||
appInfoList[app] = undefined;
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
appInfoList[app] = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate(btn, app) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice();
|
||||
|
||||
var appUpdateUrl = '<%=api.url("update_")%>' + app;
|
||||
var appInfo = appInfoList[app];
|
||||
// Download file
|
||||
XHR.get(appUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: appInfo ? appInfo.data.browser_download_url : '',
|
||||
size: appInfo ? appInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice();
|
||||
onRequestError(btn, json.error);
|
||||
} else if (json.zip) {
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
XHR.get(appUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: appInfo ? appInfo.type : ''
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice();
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
move(btn, appUpdateUrl, json.file);
|
||||
}
|
||||
}, 300)
|
||||
} else {
|
||||
move(btn, appUpdateUrl, json.file);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function move(btn, url, file) {
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
XHR.get(url, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: file
|
||||
}, function (x, json) {
|
||||
removePageNotice();
|
||||
if (json.code) {
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<%for k, v in pairs(com) do
|
||||
version[k] = api.get_app_version(k)%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%=v.name%>
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<div class="cbi-value-description">
|
||||
<span>【 <%=version[k] ~="" and version[k] or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-check_btn"
|
||||
onclick="onBtnClick(this,'<%=k%>');" value="<%:Manually update%>" />
|
||||
<span id="_<%=k%>-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%end%>
|
@ -1,157 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local brook_version = api.get_brook_version()
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var brookInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function () {
|
||||
var brookCheckBtn = document.getElementById('_brook-check_btn');
|
||||
var brookDetailElm = document.getElementById('_brook-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_brook() {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_brook() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_brook(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_brook(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
if (errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick_brook(btn) {
|
||||
if (brookInfo === undefined) {
|
||||
checkUpdate_brook(btn);
|
||||
} else {
|
||||
doUpdate_brook(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_brook(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_brook();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
XHR.get('<%=api.url("brook_check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice_brook();
|
||||
|
||||
if (json.code) {
|
||||
brookInfo = undefined;
|
||||
onRequestError_brook(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
brookInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate_brook(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_brook();
|
||||
|
||||
var brookUpdateUrl = '<%=api.url("brook_update")%>';
|
||||
// Download file
|
||||
XHR.get(brookUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: brookInfo ? brookInfo.data.browser_download_url : '',
|
||||
size: brookInfo ? brookInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_brook();
|
||||
onRequestError_brook(btn, json.error);
|
||||
} else {
|
||||
btn.value = decompressioningText;
|
||||
// Move file to target dir
|
||||
XHR.get(brookUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
removePageNotice_brook();
|
||||
if (json.code) {
|
||||
onRequestError_brook(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_brook(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Brook
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<span>【 <%=brook_version ~="" and brook_version or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_brook-check_btn"
|
||||
onclick="onBtnClick_brook(this);" value="<%:Manually update%>" />
|
||||
<span id="_brook-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,157 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local hysteria_version = api.get_hysteria_version()
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var hysteriaInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function () {
|
||||
var hysteriaCheckBtn = document.getElementById('_hysteria-check_btn');
|
||||
var hysteriaDetailElm = document.getElementById('_hysteria-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_hysteria() {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_hysteria() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_hysteria(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_hysteria(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
if (errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick_hysteria(btn) {
|
||||
if (hysteriaInfo === undefined) {
|
||||
checkUpdate_hysteria(btn);
|
||||
} else {
|
||||
doUpdate_hysteria(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_hysteria(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_hysteria();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
XHR.get('<%=api.url("hysteria_check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice_hysteria();
|
||||
|
||||
if (json.code) {
|
||||
hysteriaInfo = undefined;
|
||||
onRequestError_hysteria(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
hysteriaInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate_hysteria(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_hysteria();
|
||||
|
||||
var hysteriaUpdateUrl = '<%=api.url("hysteria_update")%>';
|
||||
// Download file
|
||||
XHR.get(hysteriaUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: hysteriaInfo ? hysteriaInfo.data.browser_download_url : '',
|
||||
size: hysteriaInfo ? hysteriaInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_hysteria();
|
||||
onRequestError_hysteria(btn, json.error);
|
||||
} else {
|
||||
btn.value = decompressioningText;
|
||||
// Move file to target dir
|
||||
XHR.get(hysteriaUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
removePageNotice_hysteria();
|
||||
if (json.code) {
|
||||
onRequestError_hysteria(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_hysteria(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Hysteria
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<span>【 <%=hysteria_version ~="" and hysteria_version or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_hysteria-check_btn"
|
||||
onclick="onBtnClick_hysteria(this);" value="<%:Manually update%>" />
|
||||
<span id="_hysteria-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,173 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local trojan_go_version = api.get_trojan_go_version()
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var trojanInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function () {
|
||||
var trojanCheckBtn = document.getElementById('_trojan-check_btn');
|
||||
var trojanDetailElm = document.getElementById('_trojan-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_trojan() {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_trojan() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_trojan(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_trojan(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
if (errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick_trojan(btn) {
|
||||
if (trojanInfo === undefined) {
|
||||
checkUpdate_trojan(btn);
|
||||
} else {
|
||||
doUpdate_trojan(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_trojan(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_trojan();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
XHR.get('<%=api.url("trojan_go_check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice_trojan();
|
||||
|
||||
if (json.code) {
|
||||
trojanInfo = undefined;
|
||||
onRequestError_trojan(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
trojanInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate_trojan(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_trojan();
|
||||
|
||||
var trojanUpdateUrl = '<%=api.url("trojan_go_update")%>';
|
||||
// Download file
|
||||
XHR.get(trojanUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: trojanInfo ? trojanInfo.data.browser_download_url : '',
|
||||
size: trojanInfo ? trojanInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_trojan();
|
||||
onRequestError_trojan(btn, json.error);
|
||||
} else {
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
XHR.get(trojanUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: trojanInfo ? trojanInfo.type : ''
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_trojan();
|
||||
onRequestError_trojan(btn, json.error);
|
||||
} else {
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
XHR.get(trojanUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
removePageNotice_trojan();
|
||||
if (json.code) {
|
||||
onRequestError_trojan(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_trojan(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Trojan-Go
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<span>【 <%=trojan_go_version ~="" and trojan_go_version or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_trojan-check_btn"
|
||||
onclick="onBtnClick_trojan(this);" value="<%:Manually update%>" />
|
||||
<span id="_trojan-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,173 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local v2ray_version = api.get_v2ray_version()
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var v2rayInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function () {
|
||||
var v2rayCheckBtn = document.getElementById('_v2ray-check_btn');
|
||||
var v2rayDetailElm = document.getElementById('_v2ray-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_v2ray() {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_v2ray() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_v2ray(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_v2ray(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
if (errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick_v2ray(btn) {
|
||||
if (v2rayInfo === undefined) {
|
||||
checkUpdate_v2ray(btn);
|
||||
} else {
|
||||
doUpdate_v2ray(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_v2ray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_v2ray();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
XHR.get('<%=api.url("v2ray_check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice_v2ray();
|
||||
|
||||
if (json.code) {
|
||||
v2rayInfo = undefined;
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
v2rayInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate_v2ray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_v2ray();
|
||||
|
||||
var v2rayUpdateUrl = '<%=api.url("v2ray_update")%>';
|
||||
// Download file
|
||||
XHR.get(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: v2rayInfo ? v2rayInfo.data.browser_download_url : '',
|
||||
size: v2rayInfo ? v2rayInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
XHR.get(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: v2rayInfo ? v2rayInfo.type : ''
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
XHR.get(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
removePageNotice_v2ray();
|
||||
if (json.code) {
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_v2ray(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">V2ray
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<span>【 <%=v2ray_version ~="" and v2ray_version or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_v2ray-check_btn"
|
||||
onclick="onBtnClick_v2ray(this);" value="<%:Manually update%>" />
|
||||
<span id="_v2ray-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
@ -1,173 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local xray_version = api.get_xray_version()
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var xrayInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var manuallyUpdateText = '<%:Manually update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function () {
|
||||
var xrayCheckBtn = document.getElementById('_xray-check_btn');
|
||||
var xrayDetailElm = document.getElementById('_xray-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_xray() {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_xray() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_xray(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_xray(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = manuallyUpdateText;
|
||||
|
||||
if (errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick_xray(btn) {
|
||||
if (xrayInfo === undefined) {
|
||||
checkUpdate_xray(btn);
|
||||
} else {
|
||||
doUpdate_xray(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_xray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_xray();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
XHR.get('<%=api.url("xray_check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice_xray();
|
||||
|
||||
if (json.code) {
|
||||
xrayInfo = undefined;
|
||||
onRequestError_xray(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
xrayInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate_xray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_xray();
|
||||
|
||||
var xrayUpdateUrl = '<%=api.url("xray_update")%>';
|
||||
// Download file
|
||||
XHR.get(xrayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: xrayInfo ? xrayInfo.data.browser_download_url : '',
|
||||
size: xrayInfo ? xrayInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_xray();
|
||||
onRequestError_xray(btn, json.error);
|
||||
} else {
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
XHR.get(xrayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: xrayInfo ? xrayInfo.type : ''
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice_xray();
|
||||
onRequestError_xray(btn, json.error);
|
||||
} else {
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
XHR.get(xrayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
removePageNotice_xray();
|
||||
if (json.code) {
|
||||
onRequestError_xray(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_xray(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Xray
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<span>【 <%=xray_version ~="" and xray_version or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_xray-check_btn"
|
||||
onclick="onBtnClick_xray(this);" value="<%:Manually update%>" />
|
||||
<span id="_xray-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user