diff options
Diffstat (limited to 'applications/luci-app-travelmate/luasrc')
17 files changed, 1060 insertions, 55 deletions
diff --git a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua index 27c19c4e52..493a387c3e 100644 --- a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua +++ b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua @@ -1,11 +1,41 @@ --- Licensed to the public under the Apache License 2.0. +-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 module("luci.controller.travelmate", package.seeall) +local util = require("luci.util") +local i18n = require("luci.i18n") +local templ = require("luci.template") + function index() if not nixio.fs.access("/etc/config/travelmate") then return end + entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false + entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true + entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true + entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 30).leaf = true + entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100) + entry({"admin", "services", "travelmate", "advanced", "configuration"}, form("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true + entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, form("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true + entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, form("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true + entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, form("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true + + entry({"admin", "services", "travelmate", "apqr"}, template("travelmate/ap_qr")).leaf = true + entry({"admin", "services", "travelmate", "wifiscan"}, template("travelmate/wifi_scan")).leaf = true + entry({"admin", "services", "travelmate", "wifiadd"}, form("travelmate/wifi_add", {hideresetbtn=true, hidesavebtn=true})).leaf = true + entry({"admin", "services", "travelmate", "wifiedit"}, form("travelmate/wifi_edit", {hideresetbtn=true, hidesavebtn=true})).leaf = true + entry({"admin", "services", "travelmate", "wifidelete"}, form("travelmate/wifi_delete", {hideresetbtn=true, hidesavebtn=true})).leaf = true + entry({"admin", "services", "travelmate", "wifiorder"}, form("travelmate/wifi_order", {hideresetbtn=true, hidesavebtn=true})).leaf = true +end - entry({"admin", "services", "travelmate"}, cbi("travelmate"), _("Travelmate"), 60) +function logread() + local logfile = "" + + if nixio.fs.access("/var/log/messages") then + logfile = util.trim(util.exec("grep -F 'travelmate-' /var/log/messages")) + elseif nixio.fs.access("/sbin/logread") then + logfile = util.trim(util.exec("logread -e 'travelmate-'")) + end + templ.render("travelmate/logread", {title = i18n.translate("Travelmate Logfile"), content = logfile}) end diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate.lua deleted file mode 100644 index fa44d4b523..0000000000 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate.lua +++ /dev/null @@ -1,53 +0,0 @@ --- Licensed to the public under the Apache License 2.0. - -m = Map("travelmate", translate("Travelmate"), - translate("Configuration of the Travelmate package to enable travel router functionality. ") .. [[</p>]] .. - translate("Brief advice: Create a wwan interface, configure it to use dhcp and " .. - "add it to the wan zone in firewall. Create the wifi interfaces to be used ('client' mode, " .. - "assigned to wwan network, left as disabled). Travelmate will try " .. - "to connect to the known wifi client interfaces in the defined order. ") .. - [[<a href="https://github.com/openwrt/packages/tree/master/net/travelmate/files/README.md" target="_blank">]] - .. translate("Link to detailed advice") - .. [[</a>]] ) - --- General options - -s = m:section(NamedSection, "global", "travelmate", translate("Global options")) - -o = s:option(Flag, "trm_enabled", translate("Enable Travelmate")) -o.rmempty = false -o.default = 0 - -o = s:option(Value, "trm_maxwait", translate("Max. timeout in seconds for wlan interface reload"), - translate("Default 20, range 10-60")) -o.rmempty = false -o.default = 20 -o.datatype = "range(10,60)" - -o = s:option(Value, "trm_maxretry", translate("Max. number of connection retries to an uplink"), - translate("Default 3, range 1-10")) -o.rmempty = false -o.default = 3 -o.datatype = "range(1,10)" - --- Extra options - -e = m:section(NamedSection, "global", "travelmate", translate("Extra options")) - -a = e:option(Flag, "trm_debug", translate("Debug logging")) -a.rmempty = true -a.default = a.disabled - -a = e:option(Value, "trm_iface", translate("Restrict reload trigger to certain interface(s)"), - translate("Space separated list of wwan interfaces that trigger reload action. To disable reload trigger set it to 'false'. Default: empty")) -a.rmempty = true -a.default = "" -a.datatype = "uciname" - -a = e:option(Flag, "trm_iw", translate("Use iw for scanning"), - translate("Disable this if you want to use iwinfo instead of iw")) -a.rmempty = true -a.default = a.enabled - -return m - diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua new file mode 100644 index 0000000000..e5a048fa88 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua @@ -0,0 +1,37 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local util = require("luci.util") +local trminput = "/etc/config/firewall" + +if not nixio.fs.access(trminput) then + m = SimpleForm("error", nil, translate("Input file not found, please check your configuration.")) + return m +end + +m = SimpleForm("input", nil) +m:append(Template("travelmate/config_css")) +m.submit = translate("Save") +m.reset = false + +s = m:section(SimpleSection, nil, + translate("This form allows you to modify the content of the main firewall configuration file (/etc/config/firewall).")) + +f = s:option(TextValue, "data") +f.rows = 20 +f.rmempty = true + +function f.cfgvalue() + return nixio.fs.readfile(trminput) or "" +end + +function f.write(self, section, data) + return nixio.fs.writefile(trminput, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n") +end + +function s.handle(self, state, data) + return true +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua new file mode 100644 index 0000000000..0096d6a8c2 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua @@ -0,0 +1,37 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local util = require("luci.util") +local trminput = "/etc/config/network" + +if not nixio.fs.access(trminput) then + m = SimpleForm("error", nil, translate("Input file not found, please check your configuration.")) + return m +end + +m = SimpleForm("input", nil) +m:append(Template("travelmate/config_css")) +m.submit = translate("Save") +m.reset = false + +s = m:section(SimpleSection, nil, + translate("This form allows you to modify the content of the main network configuration file (/etc/config/network).")) + +f = s:option(TextValue, "data") +f.rows = 20 +f.rmempty = true + +function f.cfgvalue() + return nixio.fs.readfile(trminput) or "" +end + +function f.write(self, section, data) + return nixio.fs.writefile(trminput, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n") +end + +function s.handle(self, state, data) + return true +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua new file mode 100644 index 0000000000..7ef9920a08 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua @@ -0,0 +1,37 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local util = require("luci.util") +local trminput = "/etc/config/wireless" + +if not nixio.fs.access(trminput) then + m = SimpleForm("error", nil, translate("Input file not found, please check your configuration.")) + return m +end + +m = SimpleForm("input", nil) +m:append(Template("travelmate/config_css")) +m.submit = translate("Save") +m.reset = false + +s = m:section(SimpleSection, nil, + translate("This form allows you to modify the content of the main wireless configuration file (/etc/config/wireless).")) + +f = s:option(TextValue, "data") +f.rows = 20 +f.rmempty = true + +function f.cfgvalue() + return nixio.fs.readfile(trminput) or "" +end + +function f.write(self, section, data) + return nixio.fs.writefile(trminput, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n") +end + +function s.handle(self, state, data) + return true +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua new file mode 100644 index 0000000000..8a20ab9cce --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua @@ -0,0 +1,39 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local util = require("luci.util") +local trminput = "/etc/config/travelmate" + +if not nixio.fs.access(trminput) then + m = SimpleForm("error", nil, translate("Input file not found, please check your configuration.")) + m.reset = false + m.submit = false + return m +end + +m = SimpleForm("input", nil) +m:append(Template("travelmate/config_css")) +m.submit = translate("Save") +m.reset = false + +s = m:section(SimpleSection, nil, + translate("This form allows you to modify the content of the main travelmate configuration file (/etc/config/travelmate).")) + +f = s:option(TextValue, "data") +f.rows = 20 +f.rmempty = true + +function f.cfgvalue() + return nixio.fs.readfile(trminput) or "" +end + +function f.write(self, section, data) + return nixio.fs.writefile(trminput, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n") +end + +function s.handle(self, state, data) + return true +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua new file mode 100644 index 0000000000..a1dcbc638c --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua @@ -0,0 +1,193 @@ +-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local uci = require("luci.model.uci").cursor() +local json = require("luci.jsonc") +local util = require("luci.util") +local nw = require("luci.model.network").init() +local fw = require("luci.model.firewall").init() +local dump = util.ubus("network.interface", "dump", {}) +local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" +local trminput = uci:get("travelmate", "global", "trm_rtfile") or "/tmp/trm_runtime.json" +local uplink = uci:get("network", trmiface) or "" +local parse = json.parse(fs.readfile(trminput) or "") + +m = Map("travelmate", translate("Travelmate"), + translate("Configuration of the travelmate package to to enable travel router functionality. ") + .. translatef("For further information " + .. "<a href=\"%s\" target=\"_blank\">" + .. "see online documentation</a>", "https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md")) +m:chain("network") +m:chain("firewall") +m.apply_on_parse = true + +function m.on_apply(self) + luci.sys.call("env -i /etc/init.d/travelmate restart >/dev/null 2>&1") + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate")) +end + +-- Interface Wizard + +if uplink == "" then + ds = m:section(NamedSection, "global", "travelmate", translate("Interface Wizard")) + o = ds:option(Value, "trm_iface", translate("Create Uplink interface"), + translate("Create a new wireless wan uplink interface, configure it to use dhcp and ") + .. translate("add it to the wan zone of the firewall.<br />") + .. translate("This step has only to be done once.")) + o.datatype = "and(uciname,rangelength(3,15))" + o.default = trmiface + o.rmempty = false + + function o.validate(self, value) + if value then + local nwnet = nw:get_network(value) + local zone = fw:get_zone("wan") + local fwnet = fw:get_zone_by_network(value) + if not nwnet then + nwnet = nw:add_network(value, { proto = "dhcp" }) + end + if zone and not fwnet then + fwnet = zone:add_network(value) + end + end + return value + end + return m +end + +-- Main travelmate options + +s = m:section(NamedSection, "global", "travelmate") + +o1 = s:option(Flag, "trm_enabled", translate("Enable travelmate")) +o1.default = o1.disabled +o1.rmempty = false + +o2 = s:option(Flag, "trm_captive", translate("Captive Portal Detection"), + translate("Check the internet availability, log captive portal redirections and keep the uplink connection 'alive'.")) +o2.default = o2.enabled +o2.rmempty = false + +o3 = s:option(ListValue, "trm_iface", translate("Uplink / Trigger interface"), + translate("Name of the used uplink interface.")) +if dump then + local i, v + for i, v in ipairs(dump.interface) do + if v.interface ~= "loopback" and v.interface ~= "lan" then + o3:value(v.interface) + end + end +end +o3.default = trmiface +o3.rmempty = false + +if fs.access("/usr/bin/qrencode") then + btn = s:option(Button, "btn", translate("View AP QR-Codes"), + translate("Connect your Android or iOS devices to your router's WiFi using the shown QR code.")) + btn.inputtitle = translate("QR-Codes") + btn.inputstyle = "apply" + btn.disabled = false + + function btn.write() + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate", "apqr")) + end +end + +-- Runtime information + +ds = m:section(NamedSection, "global", "travelmate", translate("Runtime Information")) + +dv1 = ds:option(DummyValue, "status", translate("Travelmate Status (Quality)")) +dv1.template = "travelmate/runtime" +if parse ~= nil then + dv1.value = parse.data.travelmate_status or translate("n/a") +else + dv1.value = translate("n/a") +end + +dv2 = ds:option(DummyValue, "travelmate_version", translate("Travelmate Version")) +dv2.template = "travelmate/runtime" +if parse ~= nil then + dv2.value = parse.data.travelmate_version or translate("n/a") +else + dv2.value = translate("n/a") +end + +dv3 = ds:option(DummyValue, "station_id", translate("Station ID (SSID/BSSID)")) +dv3.template = "travelmate/runtime" +if parse ~= nil then + dv3.value = parse.data.station_id or translate("n/a") +else + dv3.value = translate("n/a") +end + +dv4 = ds:option(DummyValue, "station_interface", translate("Station Interface")) +dv4.template = "travelmate/runtime" +if parse ~= nil then + dv4.value = parse.data.station_interface or translate("n/a") +else + dv4.value = translate("n/a") +end + +dv5 = ds:option(DummyValue, "station_radio", translate("Station Radio")) +dv5.template = "travelmate/runtime" +if parse ~= nil then + dv5.value = parse.data.station_radio or translate("n/a") +else + dv5.value = translate("n/a") +end + +dv6 = ds:option(DummyValue, "last_rundate", translate("Last rundate")) +dv6.template = "travelmate/runtime" +if parse ~= nil then + dv6.value = parse.data.last_rundate or translate("n/a") +else + dv6.value = translate("n/a") +end + +-- Extra options + +e = m:section(NamedSection, "global", "travelmate", translate("Extra options"), +translate("Options for further tweaking in case the defaults are not suitable for you.")) + +e1 = e:option(Flag, "trm_debug", translate("Enable verbose debug logging")) +e1.default = e1.disabled +e1.rmempty = false + +e2 = e:option(Value, "trm_radio", translate("Radio selection"), + translate("Restrict travelmate to a dedicated radio, e.g. 'radio0'.")) +e2.datatype = "and(uciname,rangelength(6,6))" +e2.rmempty = true + +e3 = e:option(Value, "trm_triggerdelay", translate("Trigger Delay"), + translate("Additional trigger delay in seconds before travelmate processing begins.")) +e3.datatype = "range(1,60)" +e3.default = 2 +e3.rmempty = false + +e4 = e:option(Value, "trm_maxretry", translate("Connection Limit"), + translate("Retry limit to connect to an uplink.")) +e4.default = 3 +e4.datatype = "range(1,10)" +e4.rmempty = false + +e5 = e:option(Value, "trm_minquality", translate("Signal Quality Threshold"), + translate("Minimum signal quality threshold as percent for conditional uplink (dis-) connections.")) +e5.default = 35 +e5.datatype = "range(20,80)" +e5.rmempty = false + +e6 = e:option(Value, "trm_maxwait", translate("Interface Timeout"), + translate("How long should travelmate wait for a successful wlan uplink connection.")) +e6.default = 30 +e6.datatype = "range(20,40)" +e6.rmempty = false + +e7 = e:option(Value, "trm_timeout", translate("Overall Timeout"), + translate("Overall retry timeout in seconds.")) +e7.default = 60 +e7.datatype = "range(30,300)" +e7.rmempty = false + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua new file mode 100644 index 0000000000..83011e9dd5 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua @@ -0,0 +1,183 @@ +-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local uci = require("luci.model.uci").cursor() +local http = require("luci.http") +local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" +local encr_psk = {"psk", "psk2", "psk-mixed"} +local encr_wpa = {"wpa", "wpa2", "wpa-mixed"} + +m = SimpleForm("add", translate("Add Wireless Uplink Configuration")) +m.submit = translate("Save") +m.cancel = translate("Back to overview") +m.reset = false + +function m.on_cancel() + http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) +end + +m.hidden = { + device = http.formvalue("device"), + ssid = http.formvalue("ssid"), + bssid = http.formvalue("bssid"), + wep = http.formvalue("wep"), + wpa_suites = http.formvalue("wpa_suites"), + wpa_version = http.formvalue("wpa_version") +} + +if m.hidden.ssid == "" then + wssid = m:field(Value, "ssid", translate("SSID (hidden)")) +else + wssid = m:field(Value, "ssid", translate("SSID")) +end +wssid.datatype = "rangelength(1,32)" +wssid.default = m.hidden.ssid or "" + +nobssid = m:field(Flag, "no_bssid", translate("Ignore BSSID")) +if m.hidden.ssid == "" then + nobssid.default = nobssid.disabled +else + nobssid.default = nobssid.enabled +end + +bssid = m:field(Value, "bssid", translate("BSSID"), + translatef("The BSSID information '%s' is optional and only required for hidden networks", m.hidden.bssid or "")) +bssid:depends("no_bssid", 0) +bssid.datatype = "macaddr" +bssid.default = m.hidden.bssid or "" + +if (tonumber(m.hidden.wep) or 0) == 1 then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("wep", "WEP") + encr:value("wep+open", "WEP Open System") + encr:value("wep+mixed", "WEP mixed") + encr:value("wep+shared", "WEP Shared Key") + encr.default = "wep+open" + + wkey = m:field(Value, "key", translate("WEP-Passphrase")) + wkey.password = true + wkey.datatype = "wepkey" +elseif (tonumber(m.hidden.wpa_version) or 0) > 0 then + if m.hidden.wpa_suites == "PSK" or m.hidden.wpa_suites == "PSK2" then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("psk", "WPA PSK") + encr:value("psk-mixed", "WPA/WPA2 mixed") + encr:value("psk2", "WPA2 PSK") + encr.default = encr_psk[tonumber(m.hidden.wpa_version)] or "psk2" + + ciph = m:field(ListValue, "cipher", translate("Cipher")) + ciph:value("auto", translate("Automatic")) + ciph:value("ccmp", translate("Force CCMP (AES)")) + ciph:value("tkip", translate("Force TKIP")) + ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)")) + ciph.default = "auto" + + wkey = m:field(Value, "key", translate("WPA-Passphrase")) + wkey.password = true + wkey.datatype = "wpakey" + elseif m.hidden.wpa_suites == "802.1X" then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("wpa", "WPA Enterprise") + encr:value("wpa-mixed", "WPA/WPA2 Enterprise mixed") + encr:value("wpa2", "WPA2 Enterprise") + encr.default = encr_wpa[tonumber(m.hidden.wpa_version)] or "wpa2" + + ciph = m:field(ListValue, "cipher", translate("Cipher")) + ciph:value("auto", translate("Automatic")) + ciph:value("ccmp", translate("Force CCMP (AES)")) + ciph:value("tkip", translate("Force TKIP")) + ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)")) + ciph.default = "auto" + + eaptype = m:field(ListValue, "eap_type", translate("EAP-Method")) + eaptype:value("tls", "TLS") + eaptype:value("ttls", "TTLS") + eaptype:value("peap", "PEAP") + eaptype:value("fast", "FAST") + eaptype.default = "peap" + + authentication = m:field(ListValue, "auth", translate("Authentication")) + authentication:value("PAP") + authentication:value("CHAP") + authentication:value("MSCHAP") + authentication:value("MSCHAPV2") + authentication:value("EAP-GTC") + authentication:value("EAP-MD5") + authentication:value("EAP-MSCHAPV2") + authentication:value("EAP-TLS") + authentication:value("auth=PAP") + authentication:value("auth=MSCHAPV2") + authentication.default = "EAP-MSCHAPV2" + + ident = m:field(Value, "identity", translate("Identity")) + + wkey = m:field(Value, "password", translate("Password")) + wkey.password = true + wkey.datatype = "wpakey" + + cacert = m:field(Value, "ca_cert", translate("Path to CA-Certificate")) + cacert.rmempty = true + + clientcert = m:field(Value, "client_cert", translate("Path to Client-Certificate")) + clientcert:depends("eap_type","tls") + clientcert.rmempty = true + + privkey = m:field(Value, "priv_key", translate("Path to Private Key")) + privkey:depends("eap_type","tls") + privkey.rmempty = true + + privkeypwd = m:field(Value, "priv_key_pwd", translate("Password of Private Key")) + privkeypwd:depends("eap_type","tls") + privkeypwd.datatype = "wpakey" + privkeypwd.password = true + privkeypwd.rmempty = true + end +end + +function wssid.write(self, section, value) + newsection = uci:section("wireless", "wifi-iface", nil, { + mode = "sta", + network = trmiface, + device = m.hidden.device, + ssid = wssid:formvalue(section), + bssid = bssid:formvalue(section), + disabled = "1" + }) + + if (tonumber(m.hidden.wep) or 0) == 1 then + uci:set("wireless", newsection, "encryption", encr:formvalue(section)) + uci:set("wireless", newsection, "key", wkey:formvalue(section) or "") + elseif (tonumber(m.hidden.wpa_version) or 0) > 0 then + if m.hidden.wpa_suites == "PSK" or m.hidden.wpa_suites == "PSK2" then + if ciph:formvalue(section) ~= "auto" then + uci:set("wireless", newsection, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section)) + else + uci:set("wireless", newsection, "encryption", encr:formvalue(section)) + end + uci:set("wireless", newsection, "key", wkey:formvalue(section) or "") + elseif m.hidden.wpa_suites == "802.1X" then + if ciph:formvalue(section) ~= "auto" then + uci:set("wireless", newsection, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section)) + else + uci:set("wireless", newsection, "encryption", encr:formvalue(section)) + end + uci:set("wireless", newsection, "eap_type", eaptype:formvalue(section)) + uci:set("wireless", newsection, "auth", authentication:formvalue(section)) + uci:set("wireless", newsection, "identity", ident:formvalue(section) or "") + uci:set("wireless", newsection, "password", wkey:formvalue(section) or "") + uci:set("wireless", newsection, "ca_cert", cacert:formvalue(section) or "") + uci:set("wireless", newsection, "client_cert", clientcert:formvalue(section) or "") + uci:set("wireless", newsection, "priv_key", privkey:formvalue(section) or "") + uci:set("wireless", newsection, "priv_key_pwd", privkeypwd:formvalue(section) or "") + end + else + uci:set("wireless", newsection, "encryption", "none") + end + uci:save("wireless") + uci:commit("wireless") + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1") + http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua new file mode 100644 index 0000000000..0a7678f7ed --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua @@ -0,0 +1,14 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local uci = require("luci.model.uci").cursor() +local http = require("luci.http") +local cfg = http.formvalue("cfg") + +if cfg ~= nil then + uci:delete("wireless", cfg) + uci:save("wireless") + uci:commit("wireless") + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1") +end +http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua new file mode 100644 index 0000000000..f3ad762594 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua @@ -0,0 +1,169 @@ +-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local fs = require("nixio.fs") +local uci = require("luci.model.uci").cursor() +local http = require("luci.http") + +m = SimpleForm("edit", translate("Edit Wireless Uplink Configuration")) +m.submit = translate("Save") +m.cancel = translate("Back to overview") +m.reset = false + +function m.on_cancel() + http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) +end + +m.hidden = { + cfg = http.formvalue("cfg") +} + +local s = uci:get_all("wireless", m.hidden.cfg) +if s ~= nil then + wssid = m:field(Value, "ssid", translate("SSID")) + wssid.datatype = "rangelength(1,32)" + wssid.default = s.ssid or "" + + bssid = m:field(Value, "bssid", translate("BSSID")) + bssid.datatype = "macaddr" + bssid.default = s.bssid or "" + + s.cipher = "auto" + if string.match(s.encryption, '\+') and not string.match(s.encryption, '^wep') then + s.pos = string.find(s.encryption, '\+') + s.cipher = string.sub(s.encryption, s.pos + 1) + s.encryption = string.sub(s.encryption, 0, s.pos - 1) + end + + if s.encryption and s.encryption ~= "none" then + if string.match(s.encryption, '^wep') then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("wep", "WEP") + encr:value("wep+open", "WEP Open System") + encr:value("wep+mixed", "WEP mixed") + encr:value("wep+shared", "WEP Shared Key") + encr.default = s.encryption + + wkey = m:field(Value, "key", translate("Passphrase")) + wkey.datatype = "wepkey" + elseif string.match(s.encryption, '^psk') then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("psk", "WPA PSK") + encr:value("psk-mixed", "WPA/WPA2 mixed") + encr:value("psk2", "WPA2 PSK") + encr.default = s.encryption + + ciph = m:field(ListValue, "cipher", translate("Cipher")) + ciph:value("auto", translate("Automatic")) + ciph:value("ccmp", translate("Force CCMP (AES)")) + ciph:value("tkip", translate("Force TKIP")) + ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)")) + ciph.default = s.cipher + + wkey = m:field(Value, "key", translate("Passphrase")) + wkey.datatype = "wpakey" + elseif string.match(s.encryption, '^wpa') then + encr = m:field(ListValue, "encryption", translate("Encryption")) + encr:value("wpa", "WPA Enterprise") + encr:value("wpa-mixed", "WPA/WPA2 Enterprise mixed") + encr:value("wpa2", "WPA2 Enterprise") + encr.default = s.encryption + + ciph = m:field(ListValue, "cipher", translate("Cipher")) + ciph:value("auto", translate("Automatic")) + ciph:value("ccmp", translate("Force CCMP (AES)")) + ciph:value("tkip", translate("Force TKIP")) + ciph:value("tkip+ccmp", translate("Force TKIP and CCMP (AES)")) + ciph.default = s.cipher + + eaptype = m:field(ListValue, "eap_type", translate("EAP-Method")) + eaptype:value("tls", "TLS") + eaptype:value("ttls", "TTLS") + eaptype:value("peap", "PEAP") + eaptype:value("fast", "FAST") + eaptype.default = s.eap_type or "peap" + + authentication = m:field(ListValue, "auth", translate("Authentication")) + authentication:value("PAP") + authentication:value("CHAP") + authentication:value("MSCHAP") + authentication:value("MSCHAPV2") + authentication:value("EAP-GTC") + authentication:value("EAP-MD5") + authentication:value("EAP-MSCHAPV2") + authentication:value("EAP-TLS") + authentication:value("auth=PAP") + authentication:value("auth=MSCHAPV2") + authentication.default = s.auth or "EAP-MSCHAPV2" + + ident = m:field(Value, "identity", translate("Identity")) + ident.default = s.identity or "" + + wkey = m:field(Value, "password", translate("Passphrase")) + wkey.datatype = "wpakey" + + cacert = m:field(Value, "ca_cert", translate("Path to CA-Certificate")) + cacert.rmempty = true + cacert.default = s.ca_cert or "" + + clientcert = m:field(Value, "client_cert", translate("Path to Client-Certificate")) + clientcert:depends("eap_type","tls") + clientcert.rmempty = true + clientcert.default = s.client_cert or "" + + privkey = m:field(Value, "priv_key", translate("Path to Private Key")) + privkey:depends("eap_type","tls") + privkey.rmempty = true + privkey.default = s.priv_key or "" + + privkeypwd = m:field(Value, "priv_key_pwd", translate("Password of Private Key")) + privkeypwd:depends("eap_type","tls") + privkeypwd.datatype = "wpakey" + privkeypwd.password = true + privkeypwd.rmempty = true + privkeypwd.default = s.priv_key_pwd or "" + end + wkey.password = true + wkey.default = s.key or s.password + end +else + m.on_cancel() +end + +function wssid.write(self, section, value) + uci:set("wireless", m.hidden.cfg, "ssid", wssid:formvalue(section)) + uci:set("wireless", m.hidden.cfg, "bssid", bssid:formvalue(section)) + if s.encryption and s.encryption ~= "none" then + if string.match(s.encryption, '^wep') then + uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section)) + uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section) or "") + elseif string.match(s.encryption, '^psk') then + if ciph:formvalue(section) ~= "auto" then + uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section)) + else + uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section)) + end + uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section) or "") + elseif string.match(s.encryption, '^wpa') then + if ciph:formvalue(section) ~= "auto" then + uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section) .. "+" .. ciph:formvalue(section)) + else + uci:set("wireless", m.hidden.cfg, "encryption", encr:formvalue(section)) + end + uci:set("wireless", m.hidden.cfg, "eap_type", eaptype:formvalue(section)) + uci:set("wireless", m.hidden.cfg, "auth", authentication:formvalue(section)) + uci:set("wireless", m.hidden.cfg, "identity", ident:formvalue(section) or "") + uci:set("wireless", m.hidden.cfg, "password", wkey:formvalue(section) or "") + uci:set("wireless", m.hidden.cfg, "ca_cert", cacert:formvalue(section) or "") + uci:set("wireless", m.hidden.cfg, "client_cert", clientcert:formvalue(section) or "") + uci:set("wireless", m.hidden.cfg, "priv_key", privkey:formvalue(section) or "") + uci:set("wireless", m.hidden.cfg, "priv_key_pwd", privkeypwd:formvalue(section) or "") + end + end + uci:save("wireless") + uci:commit("wireless") + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1") + m.on_cancel() +end + +return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua new file mode 100644 index 0000000000..6eb4c72063 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua @@ -0,0 +1,36 @@ +-- Copyright 2017 Dirk Brenken (dev@brenken.org) +-- This is free software, licensed under the Apache License, Version 2.0 + +local http = require("luci.http") +local cfg = http.formvalue("cfg") +local dir = http.formvalue("dir") +local uci = require("luci.model.uci").cursor() +local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" + +if cfg ~= nil then + local section = "" + local idx = "" + local idx_change = "" + local changed = "" + uci:foreach("wireless", "wifi-iface", function(s) + local iface = s.network or "" + if iface == trmiface then + section = s['.name'] + if cfg == section then + idx = s['.index'] + else + idx_change = s['.index'] + end + if (dir == "up" and idx ~= "" and idx_change ~= "" and idx_change < idx) or + (dir == "down" and idx ~= "" and idx_change ~= "" and idx_change > idx) then + changed = uci:reorder("wireless", cfg, idx_change) + idx = "" + end + end + end) + if changed ~= "" then + uci:save("wireless") + uci:commit("wireless") + end +end +http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm new file mode 100644 index 0000000000..a92dbe1469 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm @@ -0,0 +1,65 @@ +<%# +Copyright 2018 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%+header%> + +<div class="cbi-map"> + <div class="cbi-map-descr"> + <%=translate("Here you'll find the QR codes from all of your configured Access Points. It allows you to connect your Android or iOS devices to your router's WiFi using the QR code shown below.")%> + </div> +<%- + local write = io.write + local uci = require("luci.model.uci").cursor() + + uci:foreach("wireless", "wifi-iface", function(s) + local device = s.device or "" + local mode = s.mode or "" + local ssid = s.ssid or "" + local enc = s.encryption or "" + local key = s.key or "" + local hidden = s.hidden or "false" + local disabled = s.disabled or "" + local wep_slots = {s.key1 or "", s.key2 or "", s.key3 or "", s.key4 or ""} + + if device and mode == "ap" and disabled ~= "1" then + if string.match(enc, '^psk') then + enc = "WPA" + elseif string.match(enc, '^wep') then + enc = "WEP" + if tonumber(key) then + key = wep_slots[tonumber(key)] + end + elseif enc == "none" then + enc = "nopass" + key = "nokey" + else + enc = "" + end + if hidden == "1" then + hidden = "true" + end + if ssid and enc and key then + local e_ssid = string.gsub(ssid,"[\"\\';:, ]",[[\\\%1]]) + local e_key = string.gsub(key,"[\"\\';:, ]",[[\\\%1]]) + local qrcode = "" + qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'") +-%> + <fieldset class="cbi-section"> + <legend>AP on <%=device%> with SSID "<%=ssid%>"</legend> + <h3 name="content"><%=qrcode%></h3> + </fieldset> +<%- + end + end + end) +%> +</div> +<div class="cbi-page-actions right"> + <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/tab_from_cbi')%>" method="post"> + <input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>"/> + </form> +</div> + +<%+footer%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/config_css.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/config_css.htm new file mode 100644 index 0000000000..2233a15e31 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/config_css.htm @@ -0,0 +1,13 @@ +<style type="text/css"> + textarea + { + border: 1px solid #cccccc; + padding: 5px; + font-size: 12px; + font-family: monospace; + resize: none; + white-space: pre; + overflow-wrap: normal; + overflow-x: scroll; + } +</style> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/logread.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/logread.htm new file mode 100644 index 0000000000..c40bdeeb59 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/logread.htm @@ -0,0 +1,20 @@ +<%# +Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%+header%> + +<div class="cbi-map"> + <div class="cbi-section"> + <div class="cbi-section-descr"><%:This form shows the syslog output, pre-filtered for travelmate related messages only.%></div> + <textarea id="logread_id" style="width: 100%; height: 450px; border: 1px solid #cccccc; padding: 5px; font-size: 12px; font-family: monospace; resize: none;" readonly="readonly" wrap="off" rows="<%=content:cmatch("\n")+2%>"><%=content:pcdata()%></textarea> + </div> +</div> + +<script type="text/javascript"> + var textarea = document.getElementById('logread_id'); + textarea.scrollTop = textarea.scrollHeight; +</script> + +<%+footer%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/runtime.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/runtime.htm new file mode 100644 index 0000000000..7e93efab91 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/runtime.htm @@ -0,0 +1,10 @@ +<%# +Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%+cbi/valueheader%> + +<input name="runtime" id="runtime" type="text" class="cbi-input-text" style="outline:none;border:none;box-shadow:none;background:transparent;color:#0069d6;font-weight:bold;line-height:30px;height:30px;width:50em;" value="<%=self:cfgvalue(section)%>" disabled="disabled" /> + +<%+cbi/valuefooter%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm new file mode 100644 index 0000000000..74542a9ca5 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm @@ -0,0 +1,78 @@ +<%# +Copyright 2017-2018 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%- + local write = io.write + local uci = require("luci.model.uci").cursor() + local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" +-%> + +<%+header%> + + +<div class="cbi-map"> +<div class="cbi-map-descr"> + <%=translatef("Provides an overview of all configured uplinks for the travelmate interface (%s). You can edit, delete or re-order existing uplinks or scan for a new one. The currently used uplink is emphasized in blue.", trmiface)%> +</div> + +<div class="cbi-section"> + <div class="table cbi-section-table"> + <div class="tr cbi-section-table-titles"> + <div class="th left"><%:Device%></div> + <div class="th left"><%:SSID%></div> + <div class="th left"><%:BSSID%></div> + <div class="th left"><%:Encryption%></div> + <div class="th center"> </div> + </div> +<% + uci:foreach("wireless", "wifi-iface", function(s) + local iface = s.network or "" + if iface == trmiface then + local section = s['.name'] or "" + local device = s.device or "-" + local ssid = s.ssid or "-" + local bssid = s.bssid or "-" + local encryption = s.encryption or "-" + local disabled = s.disabled or "" + local style = "text-align:left;color:#000000" + if disabled == "0" then + style = "text-align:left;color:#0069d6;font-weight:bold" + end +%> + <div class="tr cbi-section-table-row cbi-rowstyle-1" style="<%=style%>"> + <div class="td" style="<%=style%>"><%=device%></div> + <div class="td" style="<%=style%>"><%=ssid%></div> + <div class="td" style="<%=style%>"><%=bssid%></div> + <div class="td" style="<%=style%>"><%=encryption%></div> + <div class="td cbi-section-actions"> + <input class="cbi-button cbi-button-up" type="button" value="<%:Up%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&dir=up'" alt="<%:Move up%>" title="<%:Move up%>"/> + <input class="cbi-button cbi-button-down" type="button" value="<%:Down%>" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&dir=down'" alt="<%:Move down%>" title="<%:Move down%>"/> + <input type="button" class="cbi-button cbi-button-edit" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifiedit')%>?cfg=<%=section%>'" title="<%:Edit this Uplink%>" value="<%:Edit%>"/> + <input type="button" class="cbi-button cbi-button-remove" onclick="location.href='<%=luci.dispatcher.build_url('admin/services/travelmate/wifidelete')%>?cfg=<%=section%>'" title="<%:Delete this Uplink%>" value="<%:Delete%>"/> + </div> + </div> +<% + end + end) +%> + </div> +</div> +<div class="cbi-page-actions right"> +<% + uci:foreach("wireless", "wifi-device", function(s) + local device = s[".name"] +%> + <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiscan')%>" method="post"> + <input type="hidden" name="device" value="<%=device%>"/> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="submit" class="cbi-button cbi-button-action important" title="<%:Find and join network on%> <%=device%>" value="<%:Scan%> <%=device%>"/> + </form> +<% + end) +%> +</div> +</div> + +<%+footer%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm new file mode 100644 index 0000000000..8a417d69c2 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm @@ -0,0 +1,97 @@ +<%# +Copyright 2017 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%- + local sys = require("luci.sys") + local utl = require("luci.util") + local dev = luci.http.formvalue("device") + local iw = luci.sys.wifi.getiwinfo(dev) + local wpa_label = {translate("WPA"), translate("WPA2"), translate("WPA/WPA2")} + + if not iw then + luci.http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) + end + + function format_wifi_encryption(info) + if info.wep == true then + return translate("WEP") + elseif info.wpa > 0 then + return "%s (%s/%s)" %{wpa_label[info.wpa], table.concat(info.auth_suites), table.concat(info.group_ciphers)} + elseif info.enabled then + return translate("Unknown") + else + return translate("Open") + end + end + + function percent_wifi_signal(info) + local qc = info.quality or 0 + local qm = info.quality_max or 0 + if info.bssid and qc > 0 and qm > 0 then + return math.floor((100 / qm) * qc) + else + return 0 + end + end +-%> + +<%+header%> + + +<div class="cbi-map"> +<h2 name="content"><%:Wireless Scan%></h2> + <div class="cbi-section"> + <div class="table cbi-section-table"> + <div class="tr cbi-section-table-titles"> + <div class="th left"><%:Uplink SSID%></div> + <div class="th left"><%:Uplink BSSID%></div> + <div class="th left"><%:Encryption%></div> + <div class="th left"><%:Signal strength%></div> + </div> + <% for i, net in ipairs(iw.scanlist or { }) do %> + <div class="tr cbi-section-table-row cbi-rowstyle-1"> + <div class="td left"> + <%=net.ssid and utl.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%> + </div> + <div class="td left"> + <%=net.bssid and utl.pcdata(net.bssid)%> + </div> + <div class="td left"> + <%=format_wifi_encryption(net.encryption)%> + </div> + <div class="td left"> + <%=percent_wifi_signal(net)%> % + </div> + <div class="td cbi-section-actions"> + <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiadd')%>" method="post"> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>"/> + <input type="hidden" name="ssid" value="<%=utl.pcdata(net.ssid)%>"/> + <input type="hidden" name="bssid" value="<%=utl.pcdata(net.bssid)%>"/> + <input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>"/> + <% if net.encryption.wpa then %> + <input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>"/> + <% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>"/><% end %> + <% end %> + <input class="cbi-button cbi-button-apply" type="submit" value="<%:Add Uplink%>"/> + </form> + </div> + </div> + <% end %> + </div> + </div> +<div class="cbi-page-actions right"> + <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/stations')%>" method="get"> + <input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>"/> + </form> + <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/wifiscan')%>" method="post"> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>"/> + <input class="cbi-button cbi-input-find" type="submit" value="<%:Repeat scan%>"/> + </form> +</div> +</div> + +<%+footer%> |