diff options
Diffstat (limited to 'applications/luci-app-openvpn/luasrc')
8 files changed, 582 insertions, 78 deletions
diff --git a/applications/luci-app-openvpn/luasrc/controller/openvpn.lua b/applications/luci-app-openvpn/luasrc/controller/openvpn.lua index 2e48a469a1..c9a932d870 100644 --- a/applications/luci-app-openvpn/luasrc/controller/openvpn.lua +++ b/applications/luci-app-openvpn/luasrc/controller/openvpn.lua @@ -8,4 +8,47 @@ function index() entry( {"admin", "services", "openvpn"}, cbi("openvpn"), _("OpenVPN") ) entry( {"admin", "services", "openvpn", "basic"}, cbi("openvpn-basic"), nil ).leaf = true entry( {"admin", "services", "openvpn", "advanced"}, cbi("openvpn-advanced"), nil ).leaf = true + entry( {"admin", "services", "openvpn", "file"}, form("openvpn-file"), nil ).leaf = true + entry( {"admin", "services", "openvpn", "upload"}, call("ovpn_upload")) +end + +function ovpn_upload() + local fs = require("nixio.fs") + local http = require("luci.http") + local util = require("luci.util") + local uci = require("luci.model.uci").cursor() + local upload = http.formvalue("ovpn_file") + local name = http.formvalue("instance_name2") + local file = "/etc/openvpn/" ..name.. ".ovpn" + + if name and upload then + local fp + + http.setfilehandler( + function(meta, chunk, eof) + local data = util.trim(chunk:gsub("\r\n", "\n")) .. "\n" + data = util.trim(data:gsub("[\128-\255]", "")) + + if not fp and meta and meta.name == "ovpn_file" then + fp = io.open(file, "w") + end + if fp and data then + fp:write(data) + end + if fp and eof then + fp:close() + end + end + ) + + if fs.access(file) then + if not uci:get_first("openvpn", name) then + uci:set("openvpn", name, "openvpn") + uci:set("openvpn", name, "config", file) + uci:save("openvpn") + uci:commit("openvpn") + end + end + end + http.redirect(luci.dispatcher.build_url('admin/services/openvpn')) end 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 6dc43bec24..40201baceb 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua @@ -1,9 +1,7 @@ -- Copyright 2008 Steven Barth <steven@midlink.org> -- Licensed to the public under the Apache License 2.0. -require("luci.ip") -require("luci.model.uci") - +local fs = require("nixio.fs") local knownParams = { -- @@ -160,6 +158,10 @@ local knownParams = { "script_security", { 0, 1, 2, 3 }, translate("Policy level over usage of external programs and scripts") }, + { ListValue, + "compress", + { "lzo", "lz4" }, + translate("Enable a compression algorithm") }, } }, { "Networking", { @@ -236,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" }, @@ -244,6 +250,15 @@ local knownParams = { "mtu_test", 0, translate("Empirically measure MTU") }, + { ListValue, + "comp_lzo", + { "yes", "no", "adaptive" }, + translate("Use fast LZO compression") }, + { Flag, + "comp_noadapt", + 0, + translate("Don't use adaptive lzo compression"), + { comp_lzo=1 } }, { Value, "link_mtu", 1500, @@ -362,7 +377,7 @@ local knownParams = { { client="0" }, { client="" } }, { DynamicList, "push", - { "redirect-gateway" }, + { "redirect-gateway", "comp-lzo" }, translate("Push options to peer"), { client="0" }, { client="" } }, { Flag, @@ -464,7 +479,7 @@ local knownParams = { 0, translate("Accept options pushed from server"), { client="1" } }, - { Value, + { FileUpload, "auth_user_pass", "/etc/openvpn/userpass.txt", translate("Authenticate using username/password"), @@ -540,6 +555,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", { @@ -555,7 +574,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, @@ -689,10 +752,18 @@ local knownParams = { "tls_version_max", "1.2", translate("The highest supported TLS version") }, - { Value, + { ListValue, "key_direction", - "1", + { 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") }, } } } @@ -701,8 +772,10 @@ local cts = { } local params = { } local m = Map("openvpn") -local p = m:section( SimpleSection ) +m.redirect = luci.dispatcher.build_url("admin", "services", "openvpn") +m.apply_on_parse = true +local p = m:section( SimpleSection ) p.template = "openvpn/pageswitch" p.mode = "advanced" p.instance = arg[1] @@ -732,8 +805,44 @@ for _, option in ipairs(params) do option[2], option[4] ) + o.optional = true + if option[1] == DummyValue then o.value = option[3] + elseif option[1] == FileUpload then + + function o.cfgvalue(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + + if cfg_val then + return cfg_val + end + end + + function o.formvalue(self, section) + local sel_val = AbstractValue.formvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if sel_val and sel_val ~= "" then + return sel_val + end + + if txt_val and txt_val ~= "" then + return txt_val + end + end + + function o.remove(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if cfg_val and fs.access(cfg_val) and txt_val == "" then + fs.unlink(cfg_val) + end + return AbstractValue.remove(self, section) + end + elseif option[1] == Flag then + o.default = nil else if option[1] == DynamicList then function o.cfgvalue(...) @@ -742,8 +851,6 @@ for _, option in ipairs(params) do end end - o.optional = true - if type(option[3]) == "table" then if o.optional then o:value("", "-- remove --") end for _, v in ipairs(option[3]) do 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 483860c8e9..132c4d8f99 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua @@ -1,45 +1,104 @@ -- Copyright 2008 Steven Barth <steven@midlink.org> -- Licensed to the public under the Apache License 2.0. -require("luci.ip") -require("luci.model.uci") +local fs = require("nixio.fs") local basicParams = { - -- + -- -- Widget, Name, Default(s), Description -- - - { ListValue, "verb", { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, translate("Set output verbosity") }, - { Value, "nice",0, translate("Change process priority") }, - { Value,"port",1194, translate("TCP/UDP port # for both local and remote") }, - { ListValue,"dev_type",{ "tun", "tap" }, translate("Type of used device") }, - - { Value,"ifconfig","10.200.200.3 10.200.200.1", translate("Set tun/tap adapter parameters") }, - { Value,"server","10.200.200.0 255.255.255.0", translate("Configure server mode") }, - { Value,"server_bridge","192.168.1.1 255.255.255.0 192.168.1.128 192.168.1.254", translate("Configure server bridge") }, - { Flag,"nobind",0, translate("Do not bind to local address and port") }, - - { Value,"keepalive","10 60", translate("Helper directive to simplify the expression of --ping and --ping-restart in server mode configurations") }, - - { ListValue,"proto",{ "udp", "tcp-client", "tcp-server" }, translate("Use protocol") }, - - { Flag,"client",0, translate("Configure client mode") }, - { Flag,"client_to_client",0, translate("Allow client-to-client traffic") }, - { DynamicList,"remote","vpnserver.example.org", translate("Remote host name or ip address") }, - - { FileUpload,"secret","/etc/openvpn/secret.key", translate("Enable Static Key encryption mode (non-TLS)") }, - { Value,"key_direction","1", translate("The key direction for 'tls-auth' and 'secret' options") }, - { FileUpload,"pkcs12","/etc/easy-rsa/keys/some-client.pk12", translate("PKCS#12 file containing keys") }, - { FileUpload,"ca","/etc/easy-rsa/keys/ca.crt", translate("Certificate authority") }, - { FileUpload,"dh","/etc/easy-rsa/keys/dh1024.pem", translate("Diffie Hellman parameters") }, - { FileUpload,"cert","/etc/easy-rsa/keys/some-client.crt", translate("Local certificate") }, - { FileUpload,"key","/etc/easy-rsa/keys/some-client.key", translate("Local private key") }, + { ListValue, + "verb", + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, + translate("Set output verbosity") }, + { Value, + "nice", + 0, + translate("Change process priority") }, + { Value, + "port", + 1194, + translate("TCP/UDP port # for both local and remote") }, + { ListValue, + "dev_type", + { "tun", "tap" }, + translate("Type of used device") }, + { Value, + "ifconfig", + "10.200.200.3 10.200.200.1", + translate("Set tun/tap adapter parameters") }, + { Value, + "server", + "10.200.200.0 255.255.255.0", + translate("Configure server mode") }, + { Value, + "server_bridge", + "192.168.1.1 255.255.255.0 192.168.1.128 192.168.1.254", + translate("Configure server bridge") }, + { Flag, + "nobind", + 0, + translate("Do not bind to local address and port") }, + { ListValue, + "comp_lzo", + {"yes","no","adaptive"}, + translate("Use fast LZO compression") }, + { Value, + "keepalive", + "10 60", + translate("Helper directive to simplify the expression of --ping and --ping-restart in server mode configurations") }, + { ListValue, + "proto", + { "udp", "tcp-client", "tcp-server" }, + translate("Use protocol") }, + { Flag, + "client", + 0, + translate("Configure client mode") }, + { Flag, + "client_to_client", + 0, + translate("Allow client-to-client traffic") }, + { DynamicList, + "remote", + "vpnserver.example.org", + translate("Remote host name or ip address") }, + { FileUpload, + "secret", + "/etc/openvpn/secret.key", + translate("Enable Static Key encryption mode (non-TLS)") }, + { ListValue, + "key_direction", + { 0, 1 }, + translate("The key direction for 'tls-auth' and 'secret' options") }, + { FileUpload, + "pkcs12", + "/etc/easy-rsa/keys/some-client.pk12", + translate("PKCS#12 file containing keys") }, + { FileUpload, + "ca", + "/etc/easy-rsa/keys/ca.crt", + translate("Certificate authority") }, + { FileUpload, + "dh", + "/etc/easy-rsa/keys/dh1024.pem", + translate("Diffie Hellman parameters") }, + { FileUpload, + "cert", + "/etc/easy-rsa/keys/some-client.crt", + translate("Local certificate") }, + { FileUpload, + "key", + "/etc/easy-rsa/keys/some-client.key", + translate("Local private key") }, } local m = Map("openvpn") -local p = m:section( SimpleSection ) +m.redirect = luci.dispatcher.build_url("admin", "services", "openvpn") +m.apply_on_parse = true +local p = m:section( SimpleSection ) p.template = "openvpn/pageswitch" p.mode = "basic" p.instance = arg[1] @@ -52,11 +111,45 @@ for _, option in ipairs(basicParams) do option[1], option[2], option[2], option[4] ) - + o.optional = true if option[1] == DummyValue then o.value = option[3] + elseif option[1] == FileUpload then + + function o.cfgvalue(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + + if cfg_val then + return cfg_val + end + end + + function o.formvalue(self, section) + local sel_val = AbstractValue.formvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if sel_val and sel_val ~= "" then + return sel_val + end + + if txt_val and txt_val ~= "" then + return txt_val + end + end + + function o.remove(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if cfg_val and fs.access(cfg_val) and txt_val == "" then + fs.unlink(cfg_val) + end + return AbstractValue.remove(self, section) + end + elseif option[1] == Flag then + o.default = nil else if option[1] == DynamicList then function o.cfgvalue(...) @@ -85,4 +178,3 @@ for _, option in ipairs(basicParams) do end return m - diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua new file mode 100644 index 0000000000..9d50601b1f --- /dev/null +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn-file.lua @@ -0,0 +1,82 @@ +-- 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 auth_file = cfg_file:match("(.+)%..+").. ".auth" + +local m = Map("openvpn") + +local p = m:section( SimpleSection ) +p.template = "openvpn/pageswitch" +p.mode = "file" +p.instance = arg[1] + +if not cfg_file or not fs.access(cfg_file) then + local f = SimpleForm("error", nil, translatef("The OVPN config file (%s) could not be found, please check your configuration.", cfg_file or "n/a")) + f:append(Template("openvpn/ovpn_css")) + f.reset = false + f.submit = false + return m, f +end + +if fs.stat(cfg_file).size >= 102400 then + f = SimpleForm("error", nil, + translatef("The size of the OVPN config file (%s) is too large for online editing in LuCI (≥ 100 KB). ", cfg_file) + .. translate("Please edit this file directly in a terminal session.")) + f:append(Template("openvpn/ovpn_css")) + f.reset = false + f.submit = false + return m, f +end + +f = SimpleForm("cfg", nil) +f:append(Template("openvpn/ovpn_css")) +f.submit = translate("Save") +f.reset = false + +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 + +function file.cfgvalue() + return fs.readfile(cfg_file) or "" +end + +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, 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 + +return m, f diff --git a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua index e17aa4085b..41266d860e 100644 --- a/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua +++ b/applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua @@ -4,7 +4,7 @@ local fs = require "nixio.fs" local sys = require "luci.sys" local uci = require "luci.model.uci".cursor() -local testfullps = luci.sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have +local testfullps = sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid local m = Map("openvpn", translate("OpenVPN")) @@ -13,9 +13,16 @@ s.template = "cbi/tblsection" s.template_addremove = "openvpn/cbi-select-input-add" s.addremove = true s.add_select_options = { } -s.extedit = luci.dispatcher.build_url( - "admin", "services", "openvpn", "basic", "%s" -) + +local cfg = s:option(DummyValue, "config") +function cfg.cfgvalue(self, section) + local file_cfg = self.map:get(section, "config") + if file_cfg then + s.extedit = luci.dispatcher.build_url("admin", "services", "openvpn", "file", "%s") + else + s.extedit = luci.dispatcher.build_url("admin", "services", "openvpn", "basic", "%s") + end +end uci:load("openvpn_recipes") uci:foreach( "openvpn_recipes", "openvpn_recipe", @@ -61,20 +68,38 @@ function s.create(self, name) if s then local options = uci:get_all("openvpn_recipes", recipe) for k, v in pairs(options) do - uci:set("openvpn", name, k, v) + 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:delete("openvpn", name, "_role") - uci:delete("openvpn", name, "_description") uci:save("openvpn") - luci.http.redirect( self.extedit:format(name) ) + uci:commit("openvpn") + if extedit then + luci.http.redirect( self.extedit:format(name) ) + end end 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") ) @@ -106,28 +131,45 @@ function updown.cfgvalue(self, section) end function updown.write(self, section, value) if self.option == "stop" then - luci.sys.call("/etc/init.d/openvpn stop %s" % section) + sys.call("/etc/init.d/openvpn stop %s" % section) else - luci.sys.call("/etc/init.d/openvpn start %s" % section) + sys.call("/etc/init.d/openvpn start %s" % section) end luci.http.redirect( self.redirect ) end - local port = s:option( DummyValue, "port", translate("Port") ) function port.cfgvalue(self, section) local val = AbstractValue.cfgvalue(self, section) - return val or "1194" + 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) - return val or "udp" + 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 -function m.on_after_commit(self,map) - require("luci.sys").call('/etc/init.d/openvpn reload') +function m.on_after_apply(self,map) + sys.call('/etc/init.d/openvpn reload') end return m 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 0166de778e..e75bfda900 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 @@ -1,11 +1,111 @@ -<div class="cbi-section-create"> - <% if self.invalid_cts then -%><div class="cbi-section-error"><% end %> - <input type="text" class="cbi-section-create-name" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.text" /> - <select class="cbi-section-create-name" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.select"> - <%- for k, v in luci.util.kspairs(self.add_select_options) do %> - <option value="<%=k%>"><%=luci.util.pcdata(v)%></option> - <% end -%> - </select> - <input class="cbi-button cbi-button-add" type="submit" value="<%:Add%>" title="<%:Add%>" /> - <% if self.invalid_cts then %><br /><%:Invalid%></div><% end %> + +<script type="text/javascript"> +//<![CDATA[ + function vpn_add() + { + 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]; + + if (!vpn_name || !vpn_name.length) + { + return info_message(vpn_output, "<%=pcdata(translate("The 'Name' field must not be empty!"))%>", 2000); + } + + document.getElementById("instance_name1").value = vpn_name; + if (document.getElementById("cbi-openvpn-" + vpn_name) != null) + { + return info_message(vpn_output, "<%=pcdata(translate("Instance with that name already exists!"))%>", 2000); + } + + if (!vpn_template || !vpn_template.length) + { + return info_message(vpn_output, "<%=pcdata(translate("Please select a valid VPN template!"))%>", 2000); + } + + if (form) + { + form.submit(); + } + } + + function vpn_upload() + { + 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]; + + if (!vpn_name || !vpn_name.length) + { + return info_message(vpn_output, "<%=pcdata(translate("The 'Name' field must not be empty!"))%>", 2000); + } + + document.getElementById("instance_name2").value = vpn_name; + if (document.getElementById("cbi-openvpn-" + vpn_name) != null) + { + return info_message(vpn_output, "<%=pcdata(translate("Instance with that name already exists!"))%>", 2000); + } + + if (!vpn_file || !vpn_file.length) + { + return info_message(vpn_output, "<%=pcdata(translate("Please select a valid OVPN config file to upload!"))%>", 2000); + } + + if (form) + { + form.enctype = 'multipart/form-data'; + form.action = '<%=url('admin/services/openvpn/upload')%>'; + form.submit(); + } + } + + function info_message(output, msg, timeout) + { + timeout = timeout || 0; + output.innerHTML = '<em>' + msg + '</em>'; + if (timeout > 0) + { + setTimeout(function(){ output.innerHTML=""}, timeout); + } + } +//]]> +</script> + +<%+openvpn/ovpn_css%> + +<div class="cbi-section-node"> + <div class="table cbi-section-table"> + <h4><%:Template based configuration%></h4> + <div class="tr cbi-section-table-row" id="div_add"> + <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 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 %> + <option value="<%=k%>"><%=luci.util.pcdata(v)%></option> + <% end -%> + </select> + </div> + <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 left"> + <input type="text" maxlength="20" placeholder="Instance name" name="instance_name2" id="instance_name2" /> + </div> + <div class="td left"> + <input type="file" name="ovpn_file" id="ovpn_file" accept="application/x-openvpn-profile,.ovpn" /> + </div> + <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> + </div> + <div class="vpn-output"> + <span id="vpn_output"></span> + </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 new file mode 100644 index 0000000000..55c0a543fc --- /dev/null +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm @@ -0,0 +1,38 @@ +<style type="text/css"> + h4 + { + white-space: nowrap; + border-bottom: 0px; + margin: 10px 5px 5px 5px; + } + .tr + { + border: 0px; + text-align: left; + } + .vpn-output + { + box-shadow: none; + margin: 10px 5px 5px 5px; + color: #a22; + } + textarea + { + border: 1px solid #cccccc; + padding: 5px; + font-size: 12px; + font-family: monospace; + resize: none; + white-space: pre; + overflow-wrap: normal; + overflow-x: scroll; + } + a + { + line-height: 1.5; + } + hr + { + margin: 0.5em 0; + } +</style> diff --git a/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm b/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm index 8cb019b461..c1fe05215a 100644 --- a/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm @@ -4,25 +4,25 @@ Licensed to the public under the Apache License 2.0. -%> +<%+openvpn/ovpn_css%> + <div class="cbi-section"> <h3> - <a href="<%=url('admin/services/openvpn')%>"><%:Overview%></a> » + <a href="<%=url('admin/services/openvpn')%>"><%:Overview%></a> » <%=luci.i18n.translatef("Instance \"%s\"", self.instance)%> </h3> - <% if self.mode == "basic" then %> - <a href="<%=url('admin/services/openvpn/advanced', self.instance, "Service")%>"><%:Switch to advanced configuration »%></a> - <% else %> - <a href="<%=url('admin/services/openvpn/basic', self.instance)%>"><%:« Switch to basic configuration%></a> - <hr style="margin:0.5em 0" /> + <a href="<%=url('admin/services/openvpn/advanced', self.instance, "Service")%>"><%:Switch to advanced configuration%> »</a><p/> + <hr /> + <% elseif self.mode == "advanced" then %> + <a href="<%=url('admin/services/openvpn/basic', self.instance)%>"><%:Switch to basic configuration%> »</a><p/> + <hr /> <%:Configuration category%>: <% for i, c in ipairs(self.categories) do %> <% if c == self.category then %> <strong><%=translate(c)%></strong> <% else %> - <a href="<%=luci.dispatcher.build_url( - "admin", "services", "openvpn", "advanced", self.instance, c - )%>"><%=translate(c)%></a> + <a href="<%=luci.dispatcher.build_url("admin", "services", "openvpn", "advanced", self.instance, c)%>"><%=translate(c)%></a> <% end %> <% if next(self.categories, i) then %>|<% end %> <% end %> |