diff options
17 files changed, 388 insertions, 138 deletions
diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua index 9a37ba802..25d1481f8 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua @@ -158,10 +158,10 @@ local knownParams = { "script_security", { 0, 1, 2, 3 }, translate("Policy level over usage of external programs and scripts") }, - { Value, - "config", - "/etc/openvpn/ovpn-file.ovpn", - translate("Local OVPN configuration file") }, + { ListValue, + "compress", + { "lzo", "lz4" }, + translate("Enable a compression algorithm") }, } }, { "Networking", { @@ -238,6 +238,10 @@ local knownParams = { "route_nopull", 0, translate("Don't pull routes automatically") }, + { Flag, + "allow_recursive_routing", + 0, + translate("Don't drop incoming tun packets with same destination as host") }, { ListValue, "mtu_disc", { "yes", "maybe", "no" }, @@ -542,6 +546,10 @@ local knownParams = { { "", "local", "def1", "local def1" }, translate("Automatically redirect default route"), { client="1" } }, + { Value, + "verify_client_cert", + { "none", "optional", "require" }, + translate("Specify whether the client is required to supply a valid certificate") }, } }, { "Cryptography", { @@ -557,7 +565,51 @@ local knownParams = { -- parse { Value, "cipher", - "BF-CBC", + { + "AES-128-CBC", + "AES-128-CFB", + "AES-128-CFB1", + "AES-128-CFB8", + "AES-128-GCM", + "AES-128-OFB", + "AES-192-CBC", + "AES-192-CFB", + "AES-192-CFB1", + "AES-192-CFB8", + "AES-192-GCM", + "AES-192-OFB", + "AES-256-CBC", + "AES-256-CFB", + "AES-256-CFB1", + "AES-256-CFB8", + "AES-256-GCM", + "AES-256-OFB", + "BF-CBC", + "BF-CFB", + "BF-OFB", + "CAST5-CBC", + "CAST5-CFB", + "CAST5-OFB", + "DES-CBC", + "DES-CFB", + "DES-CFB1", + "DES-CFB8", + "DES-EDE-CBC", + "DES-EDE-CFB", + "DES-EDE-OFB", + "DES-EDE3-CBC", + "DES-EDE3-CFB", + "DES-EDE3-CFB1", + "DES-EDE3-CFB8", + "DES-EDE3-OFB", + "DES-OFB", + "DESX-CBC", + "RC2-40-CBC", + "RC2-64-CBC", + "RC2-CBC", + "RC2-CFB", + "RC2-OFB" + }, translate("Encryption cipher for packets") }, -- parse { Value, @@ -695,6 +747,14 @@ local knownParams = { "key_direction", { 0, 1 }, translate("The key direction for 'tls-auth' and 'secret' options") }, + { Flag, + "ncp_disable", + 0, + translate("This completely disables cipher negotiation") }, + { Value, + "ncp_ciphers", + "AES-256-GCM:AES-128-GCM", + translate("Restrict the allowed ciphers to be negotiated") }, } } } diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua index 3be274dc8..3e9137bae 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua @@ -87,10 +87,6 @@ local basicParams = { "key", "/etc/easy-rsa/keys/some-client.key", translate("Local private key") }, - { Value, - "config", - "/etc/openvpn/ovpn-file.ovpn", - translate("Local OVPN configuration file") }, } diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua index 6878275d7..9d50601b1 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua @@ -1,10 +1,11 @@ -- Licensed to the public under the Apache License 2.0. -local ip = require("luci.ip") -local fs = require("nixio.fs") -local util = require("luci.util") -local uci = require("luci.model.uci").cursor() -local cfg_file = uci:get("openvpn", arg[1], "config") +local ip = require("luci.ip") +local fs = require("nixio.fs") +local util = require("luci.util") +local uci = require("luci.model.uci").cursor() +local cfg_file = uci:get("openvpn", arg[1], "config") +local auth_file = cfg_file:match("(.+)%..+").. ".auth" local m = Map("openvpn") @@ -36,25 +37,45 @@ f:append(Template("openvpn/ovpn_css")) f.submit = translate("Save") f.reset = false -s = f:section(SimpleSection, nil, translatef("This form allows you to modify the content of the OVPN config file (%s). ", cfg_file)) -file = s:option(TextValue, "data") +s = f:section(SimpleSection, nil, translatef("Section to modify the OVPN config file (%s)", cfg_file)) +file = s:option(TextValue, "data1") file.datatype = "string" file.rows = 20 -file.rmempty = true function file.cfgvalue() return fs.readfile(cfg_file) or "" end -function file.write(self, section, data) - return fs.writefile(cfg_file, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n") +function file.write(self, section, data1) + return fs.writefile(cfg_file, "\n" .. util.trim(data1:gsub("\r\n", "\n")) .. "\n") end function file.remove(self, section, value) return fs.writefile(cfg_file, "") end -function s.handle(self, state, data) +function s.handle(self, state, data1) + return true +end + +s = f:section(SimpleSection, nil, translatef("Section to add an optional 'auth-user-pass' file with your credentials (%s)", auth_file)) +file = s:option(TextValue, "data2") +file.datatype = "string" +file.rows = 5 + +function file.cfgvalue() + return fs.readfile(auth_file) or "" +end + +function file.write(self, section, data2) + return fs.writefile(auth_file, util.trim(data2:gsub("\r\n", "\n")) .. "\n") +end + +function file.remove(self, section, value) + return fs.writefile(auth_file, "") +end + +function s.handle(self, state, data2) return true end diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua index ad607ae6c..41266d860 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua @@ -69,10 +69,14 @@ function s.create(self, name) local options = uci:get_all("openvpn_recipes", recipe) for k, v in pairs(options) do if k ~= "_role" and k ~= "_description" then + if type(v) == "boolean" then + v = v and "1" or "0" + end uci:set("openvpn", name, k, v) end end uci:save("openvpn") + uci:commit("openvpn") if extedit then luci.http.redirect( self.extedit:format(name) ) end @@ -80,10 +84,23 @@ function s.create(self, name) elseif #name > 0 then self.invalid_cts = true end - return 0 end +function s.remove(self, name) + local cfg_file = "/etc/openvpn/" ..name.. ".ovpn" + local auth_file = "/etc/openvpn/" ..name.. ".auth" + if fs.access(cfg_file) then + fs.unlink(cfg_file) + end + if fs.access(auth_file) then + fs.unlink(auth_file) + end + uci:delete("openvpn", name) + uci:save("openvpn") + uci:commit("openvpn") +end + s:option( Flag, "enabled", translate("Enabled") ) local active = s:option( DummyValue, "_active", translate("Started") ) @@ -124,12 +141,30 @@ end local port = s:option( DummyValue, "port", translate("Port") ) function port.cfgvalue(self, section) local val = AbstractValue.cfgvalue(self, section) + if not val then + local file_cfg = self.map:get(section, "config") + if file_cfg and fs.access(file_cfg) then + val = sys.exec("awk '{if(match(tolower($1),/^port$/)&&match($2,/[0-9]+/)){cnt++;printf $2;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + if val == "-" then + val = sys.exec("awk '{if(match(tolower($1),/^remote$/)&&match($3,/[0-9]+/)){cnt++;printf $3;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + end + end + end return val or "-" end local proto = s:option( DummyValue, "proto", translate("Protocol") ) function proto.cfgvalue(self, section) local val = AbstractValue.cfgvalue(self, section) + if not val then + local file_cfg = self.map:get(section, "config") + if file_cfg and fs.access(file_cfg) then + val = sys.exec("awk '{if(match(tolower($1),/^proto$/)&&match(tolower($2),/^udp[46]*$|^tcp[46]*-server$|^tcp[46]*-client$/)){cnt++;printf tolower($2);exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + if val == "-" then + val = sys.exec("awk '{if(match(tolower($1),/^remote$/)&&match(tolower($4),/^udp[46]*$|^tcp[46]*-server$|^tcp[46]*-client$/)){cnt++;printf $4;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + end + end + end return val or "-" end diff --git a/applications/luci-app-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm b/applications/luci-app-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm index 09da2eb22..e75bfda90 100644 --- a/applications/luci-app-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm @@ -3,7 +3,7 @@ //<![CDATA[ function vpn_add() { - var vpn_name = div_add.querySelector("#instance_name1").value.replace(/[^\x00-\x7F]|[\s!@#$%^&*()+=\[\]{};':"\\|,<>\/?]/g,''); + var vpn_name = div_add.querySelector("#instance_name1").value.replace(/[^\x00-\x7F]|[\s!@#$%^&*()\-+=\[\]{};':"\\|,<>\/?]/g,''); var vpn_template = div_add.querySelector("#instance_template").value; var form = document.getElementsByName('cbi')[0]; @@ -31,7 +31,7 @@ function vpn_upload() { - var vpn_name = div_upload.querySelector("#instance_name2").value.replace(/[^\x00-\x7F]|[\s!@#$%^&*()+=\[\]{};':"\\|,<>\/?]/g,''); + var vpn_name = div_upload.querySelector("#instance_name2").value.replace(/[^\x00-\x7F]|[\s!@#$%^&*()\-+=\[\]{};':"\\|,<>\/?]/g,''); var vpn_file = document.getElementById("ovpn_file").value; var form = document.getElementsByName('cbi')[0]; @@ -77,10 +77,10 @@ <div class="table cbi-section-table"> <h4><%:Template based configuration%></h4> <div class="tr cbi-section-table-row" id="div_add"> - <div class="td"> + <div class="td left"> <input type="text" maxlength="20" placeholder="Instance name" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.text" id="instance_name1" /> </div> - <div class="td"> + <div class="td left"> <select id="instance_template" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.select"> <option value="" selected="selected" disabled="disabled"><%:Select template ...%></option> <%- for k, v in luci.util.kspairs(self.add_select_options) do %> @@ -88,19 +88,19 @@ <% end -%> </select> </div> - <div class="td"> + <div class="td left"> <input class="cbi-button cbi-button-add" type="submit" onclick="vpn_add(); return false;" value="<%:Add%>" title="<%:Add template based configuration%>" /><br /> </div> </div> <h4><%:OVPN configuration file upload%></h4> <div class="tr cbi-section-table-row" id="div_upload"> - <div class="td"> + <div class="td left"> <input type="text" maxlength="20" placeholder="Instance name" name="instance_name2" id="instance_name2" /> </div> - <div class="td"> + <div class="td left"> <input type="file" name="ovpn_file" id="ovpn_file" accept="application/x-openvpn-profile,.ovpn" /> </div> - <div class="td"> + <div class="td left"> <input class="cbi-button cbi-button-add" type="submit" onclick="vpn_upload(); return false;" value="<%:Upload%>" title="<%:Upload ovpn file%>" /> </div> </div> diff --git a/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm b/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm index c7062b8d7..55c0a543f 100644 --- a/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm @@ -10,12 +10,6 @@ border: 0px; text-align: left; } - .td - { - text-align: left; - border-top: 0px; - margin: 5px; - } .vpn-output { box-shadow: none; diff --git a/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm b/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm index 17beef0d3..c1fe05215 100644 --- a/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm @@ -11,17 +11,11 @@ <a href="<%=url('admin/services/openvpn')%>"><%:Overview%></a> » <%=luci.i18n.translatef("Instance \"%s\"", self.instance)%> </h3> - <% if self.mode == "file" then %> - <a href="<%=url('admin/services/openvpn/basic', self.instance)%>"><%:Switch to basic configuration%> »</a><p/> - <a href="<%=url('admin/services/openvpn/advanced', self.instance, "Service")%>"><%:Switch to advanced configuration%> »</a> - <hr /> - <% elseif self.mode == "basic" then %> + <% if self.mode == "basic" then %> <a href="<%=url('admin/services/openvpn/advanced', self.instance, "Service")%>"><%:Switch to advanced configuration%> »</a><p/> - <a href="<%=url('admin/services/openvpn/file', self.instance)%>"><%:Switch to file based configuration%> »</a> <hr /> <% elseif self.mode == "advanced" then %> <a href="<%=url('admin/services/openvpn/basic', self.instance)%>"><%:Switch to basic configuration%> »</a><p/> - <a href="<%=url('admin/services/openvpn/file', self.instance)%>"><%:Switch to file based configuration%> »</a> <hr /> <%:Configuration category%>: <% for i, c in ipairs(self.categories) do %> diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index c4066a259..d85cb5824 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -40,6 +40,28 @@ function build_url(...) return table.concat(url, "") end +function _ordered_children(node) + local name, child, children = nil, nil, {} + + for name, child in pairs(node.nodes) do + children[#children+1] = { + name = name, + node = child, + order = child.order or 100 + } + end + + table.sort(children, function(a, b) + if a.order == b.order then + return a.name < b.name + else + return a.order < b.order + end + end) + + return children +end + function node_visible(node) if node then return not ( @@ -55,15 +77,10 @@ end function node_childs(node) local rv = { } if node then - local k, v - for k, v in util.spairs(node.nodes, - function(a, b) - return (node.nodes[a].order or 100) - < (node.nodes[b].order or 100) - end) - do - if node_visible(v) then - rv[#rv+1] = k + local _, child + for _, child in ipairs(_ordered_children(node)) do + if node_visible(child.node) then + rv[#rv+1] = child.name end end end @@ -595,11 +612,9 @@ function createtree() local ctx = context local tree = {nodes={}, inreq=true} - local modi = {} ctx.treecache = setmetatable({}, {__mode="v"}) ctx.tree = tree - ctx.modifiers = modi local scope = setmetatable({}, {__index = luci.dispatcher}) @@ -609,28 +624,9 @@ function createtree() v() end - local function modisort(a,b) - return modi[a].order < modi[b].order - end - - for _, v in util.spairs(modi, modisort) do - scope._NAME = v.module - setfenv(v.func, scope) - v.func() - end - return tree end -function modifier(func, order) - context.modifiers[#context.modifiers+1] = { - func = func, - order = order or 0, - module - = getfenv(2)._NAME - } -end - function assign(path, clone, title, order) local obj = node(unpack(path)) obj.nodes = nil @@ -720,24 +716,7 @@ end -- Subdispatchers -- function _find_eligible_node(root, prefix, deep, types, descend) - local _, cur_name, cur_node - local childs = { } - - for cur_name, cur_node in pairs(root.nodes) do - childs[#childs+1] = { - node = cur_node, - name = cur_name, - order = cur_node.order or 100 - } - end - - table.sort(childs, function(a, b) - if a.order == b.order then - return a.name < b.name - else - return a.order < b.order - end - end) + local children = _ordered_children(root) if not root.leaf and deep ~= nil then local sub_path = { unpack(prefix) } @@ -746,10 +725,11 @@ function _find_eligible_node(root, prefix, deep, types, descend) deep = nil end - for _, cur_node in ipairs(childs) do - sub_path[#prefix+1] = cur_node.name + local _, child + for _, child in ipairs(children) do + sub_path[#prefix+1] = child.name - local res_path = _find_eligible_node(cur_node.node, sub_path, + local res_path = _find_eligible_node(child.node, sub_path, deep, types, true) if res_path then diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc index f26256953..a77f8d8b0 100644 --- a/modules/luci-base/luasrc/dispatcher.luadoc +++ b/modules/luci-base/luasrc/dispatcher.luadoc @@ -82,15 +82,6 @@ Build the index before if it does not exist yet. ]] ---[[ -Register a tree modifier. - -@class function -@name modifier -@param func Modifier function -@param order Modifier order value (optional) -]] - ----[[ Clone a node of the dispatching tree to another position. @class function diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/iface_status.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/iface_status.js index 1852f179f..88f48d189 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/iface_status.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/iface_status.js @@ -6,10 +6,8 @@ requestAnimationFrame(function() { L.poll(5, L.url('admin/network/iface_status', network), null, function(xhr, ifaces) { var ifc = Array.isArray(ifaces) ? ifaces[0] : null; - if (!ifc) { - alert('No ifc!'); + if (!ifc) return; - } L.itemlist(info, [ _('Device'), ifc.ifname, diff --git a/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua index 8ed39df48..9ab282c3a 100644 --- a/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua +++ b/modules/luci-mod-network/luasrc/model/cbi/admin_network/wifi.lua @@ -17,7 +17,9 @@ local acct_port, acct_secret, acct_server, anonymous_identity, ant1, ant2, privkeypwd2, r0_key_lifetime, r0kh, r1_key_holder, r1kh, reassociation_deadline, retry_timeout, ssid, st, tp, wepkey, wepslot, wmm, wpakey, wps, disassoc_low_ack, short_preamble, beacon_int, dtim_period, - wparekey, inactivitypool, maxinactivity, listeninterval + wparekey, inactivitypool, maxinactivity, listeninterval, + dae_client, dae_port, dae_port + arg[1] = arg[1] or "" @@ -755,6 +757,30 @@ acct_secret:depends({mode="ap-wds", encryption="wpa2"}) acct_secret.rmempty = true acct_secret.password = true +dae_client = s:taboption("encryption", Value, "dae_client", translate("DAE-Client")) +dae_client:depends({mode="ap", encryption="wpa"}) +dae_client:depends({mode="ap", encryption="wpa2"}) +dae_client:depends({mode="ap-wds", encryption="wpa"}) +dae_client:depends({mode="ap-wds", encryption="wpa2"}) +dae_client.rmempty = true +dae_client.datatype = "host(0)" + +dae_port = s:taboption("encryption", Value, "dae_port", translate("DAE-Port"), translatef("Default %d", 3799)) +dae_port:depends({mode="ap", encryption="wpa"}) +dae_port:depends({mode="ap", encryption="wpa2"}) +dae_port:depends({mode="ap-wds", encryption="wpa"}) +dae_port:depends({mode="ap-wds", encryption="wpa2"}) +dae_port.rmempty = true +dae_port.datatype = "port" + +dae_secret = s:taboption("encryption", Value, "dae_secret", translate("DAE-Secret")) +dae_secret:depends({mode="ap", encryption="wpa"}) +dae_secret:depends({mode="ap", encryption="wpa2"}) +dae_secret:depends({mode="ap-wds", encryption="wpa"}) +dae_secret:depends({mode="ap-wds", encryption="wpa2"}) +dae_secret.rmempty = true +dae_secret.password = true + wpakey = s:taboption("encryption", Value, "_wpa_key", translate("Key")) wpakey:depends("encryption", "psk") wpakey:depends("encryption", "psk2") @@ -872,12 +898,14 @@ if hwtype == "mac80211" or hwtype == "prism2" then ft_psk_generate_local = s:taboption("encryption", Flag, "ft_psk_generate_local", translate("Generate PMK locally"), - translate("When using a PSK, the PMK can be generated locally without inter AP communications")) + translate("When using a PSK, the PMK can be automatically generated. When enabled, the R0/R1 key options below are not applied. Disable this to use the R0 and R1 key options.")) ft_psk_generate_local:depends({ieee80211r="1"}) + ft_psk_generate_local.default = ft_psk_generate_local.enabled + ft_psk_generate_local.rmempty = false r0_key_lifetime = s:taboption("encryption", Value, "r0_key_lifetime", translate("R0 Key Lifetime"), translate("minutes")) - r0_key_lifetime:depends({ieee80211r="1", ft_psk_generate_local=""}) + r0_key_lifetime:depends({ieee80211r="1"}) r0_key_lifetime.placeholder = "10000" r0_key_lifetime.datatype = "uinteger" r0_key_lifetime.rmempty = true @@ -885,13 +913,13 @@ if hwtype == "mac80211" or hwtype == "prism2" then r1_key_holder = s:taboption("encryption", Value, "r1_key_holder", translate("R1 Key Holder"), translate("6-octet identifier as a hex string - no colons")) - r1_key_holder:depends({ieee80211r="1", ft_psk_generate_local=""}) + r1_key_holder:depends({ieee80211r="1"}) r1_key_holder.placeholder = "00004f577274" r1_key_holder.datatype = "and(hexstring,rangelength(12,12))" r1_key_holder.rmempty = true pmk_r1_push = s:taboption("encryption", Flag, "pmk_r1_push", translate("PMK R1 Push")) - pmk_r1_push:depends({ieee80211r="1", ft_psk_generate_local=""}) + pmk_r1_push:depends({ieee80211r="1"}) pmk_r1_push.placeholder = "0" pmk_r1_push.rmempty = true @@ -901,7 +929,7 @@ if hwtype == "mac80211" or hwtype == "prism2" then "<br />This list is used to map R0KH-ID (NAS Identifier) to a destination " .. "MAC address when requesting PMK-R1 key from the R0KH that the STA " .. "used during the Initial Mobility Domain Association.")) - r0kh:depends({ieee80211r="1", ft_psk_generate_local=""}) + r0kh:depends({ieee80211r="1"}) r0kh.rmempty = true r1kh = s:taboption("encryption", DynamicList, "r1kh", translate("External R1 Key Holder List"), @@ -910,7 +938,7 @@ if hwtype == "mac80211" or hwtype == "prism2" then "<br />This list is used to map R1KH-ID to a destination MAC address " .. "when sending PMK-R1 key from the R0KH. This is also the " .. "list of authorized R1KHs in the MD that can request PMK-R1 keys.")) - r1kh:depends({ieee80211r="1", ft_psk_generate_local=""}) + r1kh:depends({ieee80211r="1"}) r1kh.rmempty = true -- End of 802.11r options diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css index 394361ecd..98f6022ca 100644 --- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css +++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css @@ -174,6 +174,10 @@ a:hover { float: left; } +.nowrap { + white-space: nowrap; +} + /* Typography.less * Headings, body text, lists, code, and more for a versatile and durable typography system * ---------------------------------------------------------------------------------------- */ @@ -1020,8 +1024,9 @@ header .dropdown-menu a.hover, padding: 0 2px; list-style: none; display: flex; - background: linear-gradient(#ddd 0%, #ddd 100%) repeat-x; - background-size: 1px 1px; + flex-wrap: wrap; + background: linear-gradient(#fff 28px, #ddd 28px); + background-size: 1px 29px; background-position: left bottom; } diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/mobile.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/mobile.css index 2e1ffb035..062d274b7 100644 --- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/mobile.css +++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/mobile.css @@ -11,7 +11,6 @@ header h3 a, header .brand { background: linear-gradient(#fff 20%, #ddd 100%); background-size: 1px 34px; margin-bottom: 10px; - flex-wrap: wrap; } .tabs > li, .cbi-tabmenu > li { diff --git a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css index 48812c1c8..828365703 100644 --- a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css +++ b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css @@ -491,7 +491,7 @@ h3 { } h4 { - margin: 2rem 0 0 0; + margin: 1.5rem 0 0 0; font-size: 1.2rem; padding-bottom: 10px; } @@ -599,27 +599,6 @@ div > .table > .tbody > .tr:nth-of-type(2n) { background-color: #f9f9f9; } -/* fix progress bar */ -#swaptotal > div, -#swapfree > div, -#memfree > div, -#membuff > div, -#conns > div, -#memtotal > div { - width: 100% !important; - height: 1.2rem !important; -} - -#swaptotal > div > div, -#swapfree > div > div, -#memfree > div > div, -#membuff > div > div, -#conns > div > div, -#memtotal > div > div { - height: 100% !important; - background-color: var(--main-color, #0099CC) !important; -} - /* fix multiple table */ table table, @@ -853,6 +832,29 @@ td > table > tbody > tr > td, line-height: 1.25; } +.cbi-input-invalid, +.cbi-value-error input { + color: #f00; + border-color: #f00; +} + +.cbi-section-error { + border: 1px solid #f00; + border-radius: 3px; + background-color: #fce6e6; + padding: 5px; + margin: 18px; +} + +.cbi-section-error ul { + margin: 0 0 0 20px; +} + +.cbi-section-error ul li { + color: #f00; + font-weight: bold; +} + .cbi-value-helpicon > img { display: none; } @@ -1200,6 +1202,113 @@ td > table > tbody > tr > td, pointer-events: auto; } +#modal_overlay { + position: fixed; + top: 5rem; + bottom: 0; + left: -10000px; + right: 10000px; + background: rgba(0, 0, 0, 0.7); + z-index: 900; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + transition: opacity .125s ease-in; + opacity: 0; +} + +.modal { + width: 90%; + margin: 5em auto; + display: flex; + flex-wrap: wrap; + min-height: 32px; + max-width: 600px; + align-items: center; + border-radius: 3px; + background: #fff; + box-shadow: 0 0 3px #444; + padding: 1em 1em .5em 1em; + max-height: 2400px; + min-width: 270px; +} + +.modal > * { + flex-basis: 100%; + line-height: normal; + margin-bottom: .5em; +} + +.modal > pre, +.modal > textarea { + white-space: pre-wrap; + overflow: auto; +} + +body.modal-overlay-active { + overflow: hidden; + height: 100vh; +} + +body.modal-overlay-active #modal_overlay { + left: 0; + right: 0; + opacity: 1; +} + +#modal_overlay > .modal { + width: 90%; + margin: 5em auto; + display: flex; + flex-wrap: wrap; + min-height: 32px; + max-width: 600px; + align-items: center; + border-radius: 3px; + background: #fff; + box-shadow: 0 0 3px #444; + padding: 1em 1em 1em 1em; + max-height: 2400px; + min-width: 270px; +} + +#modal_overlay .modal > * { + flex-basis: 100%; + line-height: normal; + margin-bottom: .5em; +} + +#modal_overlay .modal > pre, +#modal_overlay .modal > textarea { + white-space: pre-wrap; + overflow: auto; +} + +body.modal-overlay-active { + overflow: hidden; + height: 100vh; +} + +body.modal-overlay-active #modal_overlay { + left: 0; + right: 0; + opacity: 1; +} + +.spinning { + position: relative; + padding-left: 32px !important; +} + +.spinning::before { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 32px; + content: " "; + background: url(../resources/icons/loading.gif) no-repeat center; + background-size: 16px; +} /* luci */ @@ -1250,6 +1359,38 @@ td > table > tbody > tr > td, min-width: 15rem; } +/* progressbar */ +.cbi-progressbar { + border: 1px solid #ccc; + border-radius: 3px; + position: relative; + min-width: 170px; + height: 20px; + margin: 0; + background: #fff; +} + +.cbi-progressbar > div { + background: var(--main-color, #0099CC); + height: 100%; + transition: width .25s ease-in; + width: 0%; +} + +.cbi-progressbar::after { + position: absolute; + bottom: 2px; + top: 2px; + right: 0; + left: 0; + text-align: center; + text-shadow: 0 0 2px #fff; + content: attr(title); + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; +} + .cbi-value-field .cbi-input-select { width: 15rem; } @@ -1660,8 +1801,14 @@ header > .container > .pull-right > * { text-decoration: none; } +label > input[type="checkbox"], +label > input[type="radio"] { + vertical-align: bottom; + margin: 0; +} + .notice { - background-color: #5BC0DE; + background-color: #5BC0DE !important; } .showSide { diff --git a/themes/luci-theme-material/htdocs/luci-static/material/favicon.ico b/themes/luci-theme-material/htdocs/luci-static/material/favicon.ico Binary files differindex b407d1845..72c311555 100755..100644 --- a/themes/luci-theme-material/htdocs/luci-static/material/favicon.ico +++ b/themes/luci-theme-material/htdocs/luci-static/material/favicon.ico diff --git a/themes/luci-theme-material/htdocs/luci-static/material/logo.png b/themes/luci-theme-material/htdocs/luci-static/material/logo.png Binary files differdeleted file mode 100755 index 459148c6b..000000000 --- a/themes/luci-theme-material/htdocs/luci-static/material/logo.png +++ /dev/null diff --git a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css index f6ea9645f..f8133833e 100644 --- a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css +++ b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css @@ -211,6 +211,7 @@ hr { -webkit-overflow-scrolling: touch; transition: opacity .125s ease-in; opacity: 0; + visibility: hidden; } .modal { @@ -250,6 +251,7 @@ body.modal-overlay-active #modal_overlay { left: 0; right: 0; opacity: 1; + visibility: visible; } .warning { |