diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php index 1b7cec164..738e5ae63 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/Api/ClientController.php @@ -130,4 +130,14 @@ class ClientController extends ApiMutableModelControllerBase { return $this->toggleBase('clients.client', $uuid); } + + public function getClientBuilderAction() + { + return $this->getBase('configbuilder', 'clients.client', null); + } + + public function addClientBuilderAction() + { + return $this->addBase('configbuilder', 'clients.client'); + } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php index 0683a6e8e..4e2f96dea 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/GeneralController.php @@ -1,6 +1,7 @@ * All rights reserved. * @@ -29,11 +30,20 @@ namespace OPNsense\Wireguard; class GeneralController extends \OPNsense\Base\IndexController { + protected function templateJSIncludes() + { + $result = parent::templateJSIncludes(); + $result[] = '/ui/js/jquery.qrcode.js'; + $result[] = '/ui/js/qrcode.js'; + return $result; + } + public function indexAction() { $this->view->generalForm = $this->getForm("general"); $this->view->formDialogEditWireguardClient = $this->getForm("dialogEditWireguardClient"); $this->view->formDialogEditWireguardServer = $this->getForm("dialogEditWireguardServer"); + $this->view->formDialogConfigBuilder = $this->getForm("dialogConfigBuilder"); $this->view->pick('OPNsense/Wireguard/general'); } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogConfigBuilder.xml b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogConfigBuilder.xml new file mode 100644 index 000000000..2a5c631f9 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Wireguard/forms/dialogConfigBuilder.xml @@ -0,0 +1,61 @@ +
+ + configbuilder.servers + + dropdown + Choose an instance to create a new peer for. + + + configbuilder.endpoint + + text + Specify how to reach the instance, usually the public address of this firewall. (e.g. my.endpoint.local:51820) + + + configbuilder.name + + text + Set the name for this peer. + + + configbuilder.pubkey + + text + Public key of this peer. You can generate the key using the private key piped to "wg pubkey". + + + configbuilder.privkey + + text + Private key of this peer, not stored on this host, only used for the configuration below. + + + configbuilder.psk + + text + Optional shared secret (PSK) for this peer. + + + configbuilder.tunneladdress + + text + List of networks allowed to pass trough the tunnel adapter. Use CIDR notation like 10.0.0.0/24. + + + configbuilder.keepalive + + text + Set persistent keepalive interval in seconds. + + + configbuilder.output + + textbox + + + + configbuilder.store_btn + info + Store the public parts of this peer and generate a keypair for the next. + +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml index 49ee50b01..2e98d1473 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Menu/Menu.xml @@ -3,8 +3,9 @@ - - + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml index b2064defa..2dba2646e 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Wireguard/Server.xml @@ -52,6 +52,7 @@ + carp @@ -66,7 +67,7 @@ Y - Choose an Peer. + Choose a peer. diff --git a/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt b/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt index 4b58d55a4..1e8f28a63 100644 --- a/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt +++ b/src/opnsense/mvc/app/views/OPNsense/Wireguard/general.volt @@ -33,8 +33,7 @@ $('.selectpicker').selectpicker('refresh'); }); - let grid_peers = $("#grid-peers").UIBootgrid( - { + let grid_peers = $("#grid-peers").UIBootgrid({ search: '/api/wireguard/client/searchClient', get: '/api/wireguard/client/getClient/', set: '/api/wireguard/client/setClient/', @@ -48,11 +47,8 @@ } return request; } - }, - - } - ); + }); grid_peers.on("loaded.rs.jquery.bootgrid", function (e){ // reload servers before grid load if ($("#server_filter > option").length == 0) { @@ -68,16 +64,14 @@ } }); - $("#grid-instances").UIBootgrid( - { - search: '/api/wireguard/server/searchServer', - get: '/api/wireguard/server/getServer/', - set: '/api/wireguard/server/setServer/', - add: '/api/wireguard/server/addServer/', - del: '/api/wireguard/server/delServer/', - toggle: '/api/wireguard/server/toggleServer/' - } - ); + $("#grid-instances").UIBootgrid({ + search: '/api/wireguard/server/searchServer', + get: '/api/wireguard/server/getServer/', + set: '/api/wireguard/server/setServer/', + add: '/api/wireguard/server/addServer/', + del: '/api/wireguard/server/delServer/', + toggle: '/api/wireguard/server/toggleServer/' + }); $("#reconfigureAct").SimpleActionButton({ @@ -110,11 +104,124 @@ } }); }) + + /** + * Quick instance filter on top + */ $("#filter_container").detach().prependTo('#grid-peers-header > .row > .actionBar > .actions'); $("#server_filter").change(function(){ $('#grid-peers').bootgrid('reload'); }); + /** + * Config maker tab hooks + */ + $("#control_label_configbuilder\\.psk").append($("#pskgen_cb_div").detach().show()); + $("#pskgen_cb").click(function(){ + ajaxGet("/api/wireguard/client/psk", {}, function(data, status){ + if (data.status && data.status === 'ok') { + $("#configbuilder\\.psk").val(data.psk).change(); + } + }); + }) + let tmp = $("#configbuilder\\.output").closest('tr'); + tmp.find('td:eq(2)').empty().append($("
")); + $("#configbuilder\\.output").css('max-width', '100%'); + $("#configbuilder\\.output").css('height', '256px'); + $("#configbuilder\\.output").change(function(){ + $('#qrcode').empty().qrcode($(this).val()); + }); + + $("#configbuilder\\.servers").change(function(){ + ajaxGet('/api/wireguard/server/getServer/' + $(this).val(), {}, function(data, status) { + if (data.server) { + let endpoint = $("#configbuilder\\.endpoint"); + endpoint + .val(data.server.endpoint) + .data('org-value', data.server.endpoint) + .data('pubkey', data.server.pubkey) + .change(); + } + }); + }); + + $("#configbuilder\\.store_btn").replaceWith($("#btn_configbuilder_save")); + + $("#btn_configbuilder_save").click(function(){ + let instance_id = $("#configbuilder\\.servers").val(); + let endpoint = $("#configbuilder\\.endpoint"); + let peer = { + configbuilder: { + enabled: '1', + name: $("#configbuilder\\.name").val(), + pubkey: $("#configbuilder\\.pubkey").val(), + psk: $("#configbuilder\\.psk").val(), + tunneladdress: $("#configbuilder\\.tunneladdress").val(), + keepalive: $("#configbuilder\\.keepalive").val(), + servers: instance_id, + } + }; + ajaxCall('/api/wireguard/client/addClientBuilder', peer, function(data, status) { + if (data.validations) { + handleFormValidation("frm_config_builder", data.validations); + } else { + if (endpoint.val() != endpoint.data('org-value')) { + let param = {'server': {'endpoint': endpoint.val()}}; + ajaxCall('/api/wireguard/server/setServer/' + instance_id, param, function(data, status){ + configbuilder_new(); + }); + } else { + configbuilder_new(); + } + } + }); + }); + $('input[id ^= "configbuilder\\."]').change(configbuilder_update_config); + $('select[id ^= "configbuilder\\."]').change(configbuilder_update_config); + + function configbuilder_new() + { + mapDataToFormUI({'frm_config_builder':"/api/wireguard/client/get_client_builder"}).done(function(data){ + formatTokenizersUI(); + $('.selectpicker').selectpicker('refresh'); + ajaxGet("/api/wireguard/server/key_pair", {}, function(data, status){ + if (data.status && data.status === 'ok') { + $("#configbuilder\\.pubkey").val(data.pubkey); + $("#configbuilder\\.privkey").val(data.privkey).change(); + } + }); + $("#configbuilder\\.tunneladdress").val("0.0.0.0/0,::/0"); + clearFormValidation("frm_config_builder"); + }); + } + + function configbuilder_update_config() + { + let rows = []; + rows.push('[Interface]'); + rows.push('PrivateKey = ' + $("#configbuilder\\.privkey").val()); + rows.push(''); + rows.push('[Peer]'); + rows.push('PublicKey = ' + $("#configbuilder\\.endpoint").data('pubkey')); + if ($("#configbuilder\\.psk").val()) { + rows.push('PresharedKey = ' + $("#configbuilder\\.psk").val()); + } + rows.push('Endpoint = ' + $("#configbuilder\\.endpoint").val()); + rows.push('AllowedIPs = ' + $("#configbuilder\\.tunneladdress").val()); + if ($("#configbuilder\\.keepalive").val()) { + rows.push('PersistentKeepalive = ' + $("#configbuilder\\.keepalive").val()); + } + $("#configbuilder\\.output").val(rows.join("\n")).change(); + } + + $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { + if (e.target.id == 'tab_configbuilder'){ + configbuilder_new(); + } else if (e.target.id == 'tab_peers') { + $('#grid-peers').bootgrid('reload'); + } + }); + // update history on tab state and implement navigation if(window.location.hash != "") { $('a[href="' + window.location.hash + '"]').click() @@ -130,12 +237,13 @@
-
+
-
+
+
+ + + + {{ partial("layout_partials/base_form",['fields':formDialogConfigBuilder,'id':'frm_config_builder'])}} +