luci-app-phtunnel: add new package

This commit adds the luci PHTunnel(HSK) package.
This commit is contained in:
AmadeusGhost 2022-08-24 11:50:29 +08:00
parent ad18ab1a86
commit 082687d1e0
10 changed files with 469 additions and 0 deletions

View File

@ -0,0 +1,8 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Support for the PHTunnel
LUCI_DEPENDS:=+cgi-io +curl +luci-compat +luci-lib-json +phtunnel
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,16 @@
module("luci.controller.oray.phtunnel", package.seeall)
function index()
entry({"admin", "services", "phtunnel"}, alias("admin", "services", "phtunnel", "setup"), _("Phtunnel"))
entry({"admin", "services", "phtunnel", "setup"}, cbi("oray/phtunnel_setup"), _("Setup"), 1).leaf = true
entry({"admin", "services", "phtunnel", "status"}, template("oray/phtunnel_status"), _("Status"), 2).leaf = true
-- entry({"admin", "oray", "phtunnel", "log"}, template("oray/phtunnel_log"), _("Log"), 3).leaf = true
local node = entry({"admin", "services", "phtunnel", "inner_status"}, template("oray/phtunnel_inner_status"), nil, 4)
node.leaf = true
node.hidden = true
node = entry({"admin", "services", "phtunnel", "log_off"}, template("oray/phtunnel_log_off"), nil, 5)
node.leaf = true
node.hidden = true
end

View File

@ -0,0 +1,15 @@
m = Map("phtunnel")
m.reset = true
local s = m:section(NamedSection, "base", "base", translate("Base Setup"))
enabled = s:option(Flag, "enabled", translate("Enabled"))
enabled.rmempty = false
m.apply_on_parse = true
m.on_after_apply = function(self)
io.popen("/etc/init.d/phtunnel restart")
end
return m

View File

@ -0,0 +1,114 @@
module("luci.phtunnel", package.seeall)
require("luci.sys")
require("luci.json")
local function write_log(log)
luci.sys.exec("logger -t phtunnel_web '" .. string.gsub(log, "'", "") .. "'") --用gsub去掉单引号
end
function write_info_log(log)
write_log("[info] " .. log)
end
function write_err_log(log)
write_log("[err] " .. log)
end
function convert_status(status)
if status == 0 then
return "offline"
elseif status == 1 then
return "online"
elseif status == 2 then
return "loginning"
elseif status == 3 then
return "retry"
else
return "unknown"
end
end
--获取基本信息
function get_base_info()
local cmd = "curl -s -o- -L http://127.0.0.1:16062/ora_service/getsn"
-- write_info_log("command for get base info: " .. cmd)
local http_result = luci.sys.exec(cmd)
if http_result then
local result = luci.json.decode(http_result)
if type(result) == "table" and result.result_code == 0 and type(result.data) == "table" then
return result.result_code, result.data.device_sn, result.data.device_sn_pwd, result.data.status, result.data.public_ip
else
write_err_log("get base info failed : result=(" .. http_result .. ")")
end
else
write_err_log("get base info failed : curl")
end
end
--获取登录后帐号信息
function get_login_info()
local cmd = "curl -s -o- -L http://127.0.0.1:16062/ora_service/getmgrurl"
-- write_info_log("command for get login info: " .. cmd)
local http_result = luci.sys.exec(cmd)
if http_result then
local result = luci.json.decode(http_result)
if type(result) == "table" and result.result_code == 0 and type(result.data) == "table" then
return result.result_code, result.data.url, result.data.account
else
write_err_log("get login info failed : result=(" .. http_result .. ")")
end
else
write_err_log("get login info failed : curl")
end
end
--获取扫描信息
function get_qrimage(sn, pwd)
local post_json = { sn = sn, password = pwd }
local post_file = "/tmp/phtunnel_qrimg_post"
local f = io.open(post_file, "w")
if f then
f:write(luci.json.encode(post_json))
f:close()
local cmd = "curl -s -X POST -o- -d '@" .. post_file .. "' --header 'Content-Type: application/json' -k 'https://hsk-api.oray.com/devices/qrcode'"
-- write_info_log("command for get qrcode image : " .. cmd)
local post_data = ""
local http_result = luci.sys.exec(cmd)
os.remove(post_file)
if http_result then
local result = luci.json.decode(http_result)
if type(result) == "table" then
return result.qrcode, result.qrcodeimg, result.ttl
else
write_err_log("get qrcode image failed : result=(" .. http_result .. ")")
end
end
else
write_log("get qrcode image failed : curl")
end
end
--解绑
function unbind_account(sn, pwd)
local post_json = { sn = sn, password = pwd }
local post_file = "/tmp/phtunnel_unbind_post"
local f = io.open(post_file, "w")
if f then
f:write(luci.json.encode(post_json))
f:close()
local cmd = "curl -s -X POST -o- -d '@" .. post_file .. "' --header 'Content-Type: application/json' -k 'https://hsk-api.oray.com/devices/unbinding' -f || echo fail"
-- write_info_log("command for get unbind : " .. cmd)
local post_data = ""
local http_result = luci.sys.exec(cmd)
--os.remove(post_file)
return #http_result == 0
else
write_log("unbind account failed : curl")
end
end

View File

@ -0,0 +1,31 @@
<%
require("luci.json")
require("luci.sys")
require("luci.phtunnel")
local write_err_log = luci.phtunnel.write_err_log
local manager_url
local function main()
--登录信息查看
local login_info_code
login_info_code, manager_url = luci.phtunnel.get_login_info()
if not login_info_code then
write_err_log("get manager url failed : inner_status")
return
end
if login_info_code ~= 0 then
write_err_log("get manger url failed and code = " .. login_info_code .. " : inner_status")
return
end
end
main()
%>
{
"url" : "<%=(manager_url and manager_url or "")%>"
}

View File

@ -0,0 +1,17 @@
<%+header%>
<%
require("luci.sys")
require("luci.model.uci")
local uci = luci.model.uci.cursor()
local log_file = uci:get("phtunnel", "log", "path")
if not log_file or log_file == "" then
log_file = "/var/log/oraybox/phtunnel.log"
end
%>
<%=string.gsub(luci.sys.exec("tail -n 5000 " .. log_file), "\n", "<br/>")%>
<%+footer%>

View File

@ -0,0 +1,34 @@
<%
require("luci.phtunnel")
local ret_code = 0
local ret_msg = ""
local function main()
local base_info_code, device_sn, device_pwd, device_status, public_ip = luci.phtunnel.get_base_info()
if not base_info_code then
ret_code = 1
ret_msg = "phtunnel is not running"
return
end
if base_info_code ~= 0 then
ret_code = 2
ret_msg = "get sn failed and code = " .. base_info_code
return
end
if not luci.phtunnel.unbind_account(device_sn, device_pwd) then
ret_code = 3
ret_msg = "unbind failed"
return
end
end
main()
%>
{
"code" : "<%=ret_code%>",
"error_msg" : "<%=_(ret_msg)%>"
}

View File

@ -0,0 +1,218 @@
<%+header%>
<%
require("luci.sys")
require("luci.model.uci")
local uci = luci.model.uci.cursor()
local log_file = uci:get("phtunnel", "log", "path")
if not log_file or log_file == "" then
log_file = "/var/log/oraybox/phtunnel.log"
end
%>
<style type="text/css">
.oray_lable {
margin-right: 5px;
}
</style>
<script type="text/javascript">
function reload_this_page() {
window.location.reload()
}
function create_xml_http_request() {
var xml_http
try {
xml_http = new XMLHttpRequest()
} catch (e) {
try {
xml_http = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xml_http = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
}
}
}
return xml_http
}
function get_login_info() {
var xml_http = create_xml_http_request()
if (!xml_http) {
alert('Error : no xml http request')
return
}
var url = window.location.href.replace("phtunnel/status", "phtunnel/inner_status")
xml_http.open("GET", url)
xml_http.send(null)
xml_http.onreadystatechange = function() {
if (xml_http.readyState == 4 && xml_http.status == 200) {
if (xml_http.responseText.length > 0) {
var response_json = JSON.parse(xml_http.responseText)
if (response_json.url.length > 0)
reload_this_page()
}
}
}
}
function load_qr_img_success_process() {
document.getElementById("qrimg").innerHTML = "Scan this Image"
}
function load_qr_img_failed_process() {
document.getElementById("qrimg").innerHTML = "load qrcode image failed"
}
function log_off() {
var xml_http = create_xml_http_request()
if (!xml_http) {
alert('Error : no xml http request')
return
}
var url = window.location.href.replace("phtunnel/status", "phtunnel/log_off")
xml_http.open("GET", url)
xml_http.send(null)
xml_http.onreadystatechange = function() {
if (xml_http.readyState == 4 && xml_http.status == 200) {
if (xml_http.responseText.length > 0) {
var response_json = JSON.parse(xml_http.responseText)
if (response_json.code == 0) {
alert("log off ok")
reload_this_page()
return
}
alert("log off failed : " + response_json.error_msg)
}
}
}
}
function createInput(type, name, value) {
var input = document.createElement("input")
input.type = type
input.name = name
input.value = value
return input
}
var logpath = "<%=log_file%>";
function downloadLogFile() {
var sid = "<%=luci.dispatcher.context.authsession%>";
var scriptname = '<%=luci.http.getenv("SCRIPT_NAME")%>';
var cgi_base = scriptname.replace(/\/[^\/]+$/, '');
var form = document.createElement('form');
form.method = 'post';
form.action = '' + cgi_base + '/cgi-download';
form.enctype = 'application/x-www-form-urlencoded';
var sidInput = createInput('hidden', 'sessionid', sid);
var pathInput = createInput('hidden', 'path', logpath);
var filenameInput = createInput('hidden', 'filename', 'phtunnel.log');
form.appendChild(sidInput);
form.appendChild(pathInput);
form.appendChild(filenameInput);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
</script>
<%
require("luci.phtunnel")
local utl = require "luci.util"
local function fileExists(path)
local file = io.open(path, "rb")
if file then file:close() end
return file ~= nil
end
local function grant_download_permission()
local dsp = require "luci.dispatcher"
local sid = dsp.context.authsession
local access, _ = utl.ubus("session", "access",
{ubus_rpc_session = sid,
scope = "file",
object = log_file,
["function"] = "read"})
if type(access) == "table" and access.access == false then
local acl = {}
acl[1] = {}
acl[1][1] = log_file
acl[1][2] = "read"
utl.ubus("session", "grant", { ubus_rpc_session = sid, scope = "file", objects = acl})
end
end
local function display_download_log()
if fileExists(log_file) then
print('<a href="javascript:void(0)" onclick="downloadLogFile(this)">Download Log File</a><br/>')
grant_download_permission()
end
end
--输出二
local function display_qrimage(sn, pwd)
local qrcode, qrcodeimg, ttl = luci.phtunnel.get_qrimage(sn, pwd)
if qrcode and qrcodeimg then
print("<img src='" .. qrcodeimg .. "' onload=\"load_qr_img_success_process();setInterval(reload_this_page, " .. ((ttl and ttl or 300) * 1000) .. ")\" onerror=\"load_qr_img_failed_process()\" onabort=\"load_qr_img_failed_process()\" /><div id='qrimg'></div>")
end
end
local function main()
local base_info_code, device_sn, device_pwd, device_status, public_ip = luci.phtunnel.get_base_info()
if not base_info_code then
print("phtunnel is not running")
return
end
if base_info_code ~= 0 then
print("get sn failed and code = " .. base_info_code)
return
end
--输出基本信息
print('<b class="oray_lable">SN:</b>' .. (device_sn and device_sn or "no sn") .. "<br/>")
print('<b class="oray_lable">Device Status:</b>' .. (device_status and luci.phtunnel.convert_status(device_status) or "no status") .. "<br/>")
print('<b class="oray_lable">Public IP:</b>' .. (public_ip and public_ip or "no public ip") .. "<br/>")
--登录信息查看
local login_info_code, url, bind_account = luci.phtunnel.get_login_info()
if not login_info_code then
print("get manager url failed")
return
end
if login_info_code ~= 0 then
print("get manger url failed and code = " .. login_info_code)
return
end
if not url or url == "" then
display_qrimage(device_sn, device_pwd)
print("<script type=\"text/javascript\">setInterval(get_login_info, 3000)</script>")
return
end
print("<b>bind account</b>:<font color=red>" .. (bind_account and bind_account or "<b>*</b>") .. "</font>")
print("(<a href='#' onclick='log_off();return(false)'>log off</a>)</br>");
print("<a href='" .. (url and url or '#') .. "' target=_blank>manager link</a></br>");
end
main()
display_download_log()
%>
<%+footer%>

View File

@ -0,0 +1,8 @@
msgid "Phtunnel"
msgstr "花生壳内网穿透"
msgid "Base Setup"
msgstr "基本设置"
msgid "Setup"
msgstr "设置"

View File

@ -0,0 +1,8 @@
{
"phtunnel-luci-app": {
"description": "phtunnel luci interface",
"read": {
"cgi-io": [ "download" ]
}
}
}