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:
nftbty 2023-03-21 11:02:20 +08:00 committed by sbwml
parent 8d2fcefe66
commit 5e84915db1
17 changed files with 604 additions and 1939 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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%>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>