* Add factory class to request export template types
* Add some test code to show/hide options depending on supported functions
* Use our normal form type to construct the UI
* Use stored ip/hostname when available or determine target based on ip address, the previous hostname resolution type will be replaced.
* List configured templates using /api/openvpn/export/templates/
This commit is contained in:
Ad Schellevis 2018-10-15 18:22:13 +02:00
parent 9f675d4078
commit ba645c25a6
11 changed files with 499 additions and 1 deletions

View File

@ -30,6 +30,10 @@ namespace OPNsense\OpenVPN\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Config;
use \OPNsense\Core\Backend;
use \OPNsense\OpenVPN\Export;
use \OPNsense\OpenVPN\ExportFactory;
/**
* Class ExportController handles client export functions
@ -37,6 +41,51 @@ use \OPNsense\Core\Config;
*/
class ExportController extends ApiControllerBase
{
/**
* @var null|Export model object to work on
*/
private $modelHandle = null;
/**
* @var array list of configured interfaces (addresses)
*/
private $physicalInterfaces = array();
/**
* Get (or create) model object
* @return Export
* @throws \OPNsense\Base\ModelException when unable to create model
*/
private function getModel()
{
if ($this->modelHandle == null) {
$this->modelHandle = new Export();
}
return $this->modelHandle;
}
/**
* collect (and store) configured interfaces by name [lan, wan, optX]
* @return mixed
* @throws \Exception when unable to contact configd
*/
private function getInterfaces()
{
if (empty($this->physicalInterfaces)) {
$ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true);
$config = Config::getInstance()->object();
if ($config->interfaces->count() > 0) {
foreach ($config->interfaces->children() as $key => $node) {
$this->physicalInterfaces[(string)$key] = array();
if (!empty($ifconfig[(string)($node->if)])){
$this->physicalInterfaces[(string)$key] = $ifconfig[(string)($node->if)];
}
}
}
}
return $this->physicalInterfaces;
}
/**
* find configured servers
* @param bool $active only active servers
@ -55,6 +104,32 @@ class ExportController extends ApiControllerBase
}
}
/**
* Determine configured hostname for selected server
* @param $vpnid server handle
* @return string hostname
* @throws \OPNsense\Base\ModelException when unable to create model
*/
private function configuredHostname($vpnid)
{
$result = "";
$allInterfaces = $this->getInterfaces();
$serverModel = $this->getModel()->getServer($vpnid);
$server = $this->findServer($vpnid);
if (!empty((string)$serverModel->hostname)) {
$result = (string)$serverModel->hostname;
} elseif (!empty($allInterfaces[(string)$server->interface])) {
if (strstr((string)$server->protocol, "6") !== false) {
if (!empty($allInterfaces[(string)$server->interface]['ipv6'])) {
$result = $allInterfaces[(string)$server->interface]['ipv6'][0]['ipaddr'];
}
} elseif (!empty($allInterfaces[(string)$server->interface]['ipv4'])) {
$result = $allInterfaces[(string)$server->interface]['ipv4'][0]['ipaddr'];
}
}
return $result;
}
/**
* find server by vpnid
* @param string $vpnid reference
@ -70,12 +145,15 @@ class ExportController extends ApiControllerBase
return null;
}
/**
* list providers
* @return array list of configured openvpn providers (servers)
* @throws \Exception when unable to contact configd
*/
public function providersAction()
{
$result = array();
foreach ($this->servers() as $server) {
$vpnid = (string)$server->vpnid;
@ -86,6 +164,7 @@ class ExportController extends ApiControllerBase
// relevant properties
$result[$vpnid]["mode"] = (string)$server->mode;
$result[$vpnid]["vpnid"] = $vpnid;
$result[$vpnid]["hostname"] = $this->configuredHostname($vpnid);
}
return $result;
}
@ -132,6 +211,15 @@ class ExportController extends ApiControllerBase
*/
public function templatesAction()
{
return array();
$result = array();
$factory = new ExportFactory();
foreach ($factory->listProviders() as $key => $provider) {
$result[$key] = array(
"name" => $provider['handle']->getName(),
"supportedOptions" => $provider['handle']->supportedOptions()
);
}
return $result;
}
}

View File

@ -45,5 +45,6 @@ class ExportController extends BaseIndexController
public function indexAction()
{
$this->view->pick('OPNsense/OpenVPN/export');
$this->view->exportForm = $this->getForm("export_options");
}
}

View File

@ -0,0 +1,40 @@
<form>
<field>
<id>openvpn_export.servers</id>
<label>Remote Access Server</label>
<type>dropdown</type>
<help><![CDATA[Select an OpenVPN server to export profiles for.]]></help>
</field>
<field>
<id>openvpn_export.template</id>
<label>Export type</label>
<type>dropdown</type>
<help><![CDATA[File format to export.]]></help>
</field>
<field>
<id>openvpn_export.hostname</id>
<label>Hostname</label>
<type>text</type>
<help>
Address(es) or hostname(s) to which this client should connect to, use comma's to provide more then one
</help>
</field>
<field>
<id>openvpn_export.testxx1</id>
<label>TestXX1</label>
<style>export_option</style>
<type>text</type>
</field>
<field>
<id>openvpn_export.testxx2</id>
<label>TestXX2</label>
<style>export_option</style>
<type>text</type>
</field>
<field>
<id>openvpn_export.testxx3</id>
<label>TestXX3</label>
<style>export_option</style>
<type>text</type>
</field>
</form>

View File

@ -0,0 +1,42 @@
<?php
/*
* Copyright (C) 2018 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\OpenVPN;
class ArchiveOpenVPN extends PlainOpenVPN
{
public function getName()
{
return gettext("Archive");
}
public function supportedOptions()
{
return array("testxx2");
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* Copyright (C) 2018 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\OpenVPN;
/**
* Export stub file, contains shared logic for all types
* @package OPNsense\Backup
*/
abstract class BaseExporter
{
}

View File

@ -0,0 +1,81 @@
<?php
/**
* Copyright (C) 2018 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\OpenVPN;
/**
* Class ExportFactory
* @package OPNsense\OpenVPN
*/
class ExportFactory
{
/**
* list installed backup providers
* @return array
*/
public function listProviders()
{
$providers = array();
foreach (glob(__DIR__."/*.php") as $filename) {
$pathParts = explode('/', $filename);
$vendor = $pathParts[count($pathParts)-3];
$module = $pathParts[count($pathParts)-2];
$classname = explode('.php', $pathParts[count($pathParts)-1])[0];
try {
$reflClass = new \ReflectionClass("{$vendor}\\{$module}\\{$classname}");
if ($reflClass->implementsInterface('OPNsense\\OpenVPN\\IExportProvider')
&& !$reflClass->isInterface()) {
$providers[$classname] = array(
"class" => "{$vendor}\\{$module}\\{$classname}",
"handle" => $reflClass->newInstance()
);
}
} catch (\ReflectionException $e) {
null; // skip when unable to parse
}
}
return $providers;
}
/**
* return a specific provider by class name (without namespace)
* @param string $className without namespace
* @return mixed|null
*/
public function getProvider($className)
{
$providers = $this->listProviders();
if (!empty($providers[$className])) {
return $providers[$className];
} else {
return null;
}
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* Copyright (C) 2018 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\OpenVPN;
/**
* Interface for OpenVPN export connectors
* @package OPNsense\Backup
*/
interface IExportProvider
{
/**
* @return string user friendly exporter name
*/
public function getName();
/**
* @return array list of supported options, so the user interface can hide the non supported ones
*/
public function supportedOptions();
}

View File

@ -0,0 +1,42 @@
<?php
/*
* Copyright (C) 2018 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\OpenVPN;
class PlainOpenVPN extends BaseExporter implements IExportProvider
{
public function getName()
{
return gettext("File Only");
}
public function supportedOptions()
{
return array("testxx1", "testxx3");
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Copyright (C) 2018 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\OpenVPN;
use OPNsense\Base\BaseModel;
/**
* Class Export
* @package OPNsense\OpenVPN
*/
class Export extends BaseModel
{
/**
* get or create server to store defaults
* @param $vpnid openvpn unique reference (number)
* @return mixed server object
*/
public function getServer($vpnid)
{
foreach ($this->servers->server->iterateItems() as $uuid => $server) {
if ((string)$server->vpnid == (string)$vpnid) {
return $server;
}
}
$server = $this->servers->server->add();
$server->vpnid = (string)$vpnid;
return $server;
}
}

View File

@ -0,0 +1,16 @@
<model>
<mount>//OPNsense/OpenVPNExport</mount>
<version>0.0.1</version>
<description>OpenVPN export presets</description>
<items>
<servers>
<server type="ArrayField">
<vpnid type="IntegerField">
<Required>Y</Required>
</vpnid>
<hostname type="HostnameField">
</hostname>
</server>
</servers>
</items>
</model>

View File

@ -29,10 +29,56 @@ POSSIBILITY OF SUCH DAMAGE.
<script>
$( document ).ready(function() {
/**
* Provider selection
*/
$("#openvpn_export\\.servers").change(function () {
var selected_opt = $(this).find('option:selected');
$("#openvpn_export\\.hostname").val(selected_opt.data('hostname'));
});
ajaxGet('/api/openvpn/export/providers/', {}, function(data, status){
if (status == 'success') {
$.each(data, function (idx, record) {
$("#openvpn_export\\.servers").append(
$("<option/>").val(record.vpnid)
.text(record.name)
.data('hostname', record.hostname)
);
});
$("#openvpn_export\\.servers").selectpicker('refresh');
$("#openvpn_export\\.servers").change();
}
});
/**
* Template / type selection
*/
$("#openvpn_export\\.template").change(function () {
$(".export_option").closest('tr').hide();
var selected_options = $(this).find('option:selected').data('options');
for (var i=0; i < selected_options.length; ++i) {
$("#row_openvpn_export\\."+selected_options[i]).show();
}
});
ajaxGet('/api/openvpn/export/templates/', {}, function(data, status){
if (status == 'success') {
$.each(data, function (idx, record) {
$("#openvpn_export\\.template").append(
$("<option/>").val(idx)
.text(record.name)
.data('options', record.supportedOptions)
);
});
$("#openvpn_export\\.template").selectpicker('refresh');
$("#openvpn_export\\.template").change();
}
});
});
</script>
<div class="content-box">
{{ partial("layout_partials/base_form",['fields':exportForm,'id':'frm_ExportSettings'])}}
</div>