diff options
author | Dirk Brenken <dev@brenken.org> | 2018-10-20 21:22:49 +0200 |
---|---|---|
committer | Dirk Brenken <dev@brenken.org> | 2018-10-23 21:17:22 +0200 |
commit | 0b04912f8d495ea836d565f3536b59d030225cfa (patch) | |
tree | 143498433847d1e42e59dcc66652fbef2a3a4bbb /applications/luci-app-openvpn/luasrc/view/openvpn | |
parent | a0cc0769d8faf38172312a376d33aec241c19126 (diff) |
luci-app-openvpn: add ovpn upload support & more
* add the ability to upload ovpn files directly,
incl. appropriate uci entry in openvpn config
* add the ability to edit ovpn files directly ('file' mode),
beside the 'basic' and 'advanced' modes for normal setups
* client side checks to validate instance name & template selection,
incl. online error reporting
* automatically remove non-ascii characters & windows line endings
from transfered ovpn file
* change from after_commit to after_apply hook
* remove misleading default values for Port & Protocol in Overview
Signed-off-by: Dirk Brenken <dev@brenken.org>
Diffstat (limited to 'applications/luci-app-openvpn/luasrc/view/openvpn')
3 files changed, 170 insertions, 20 deletions
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..09da2eb22d 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"> + <input type="text" maxlength="20" placeholder="Instance name" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.text" id="instance_name1" /> + </div> + <div class="td"> + <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"> + <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"> + <input type="text" maxlength="20" placeholder="Instance name" name="instance_name2" id="instance_name2" /> + </div> + <div class="td"> + <input type="file" name="ovpn_file" id="ovpn_file" accept="application/x-openvpn-profile,.ovpn" /> + </div> + <div class="td"> + <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..c7062b8d7a --- /dev/null +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/ovpn_css.htm @@ -0,0 +1,44 @@ +<style type="text/css"> + h4 + { + white-space: nowrap; + border-bottom: 0px; + margin: 10px 5px 5px 5px; + } + .tr + { + border: 0px; + text-align: left; + } + .td + { + text-align: left; + border-top: 0px; + margin: 5px; + } + .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..17beef0d39 100644 --- a/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm +++ b/applications/luci-app-openvpn/luasrc/view/openvpn/pageswitch.htm @@ -4,25 +4,31 @@ 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" /> + <% 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 %> + <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 %> <% 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 %> |