diff --git a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php index 6a52e26e0..2e2cece5e 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php @@ -29,6 +29,7 @@ namespace OPNsense\OpenVPN\Api; use \OPNsense\Base\ApiControllerBase; +use \OPNsense\Base\UserException; use \OPNsense\Core\Config; use \OPNsense\Core\Backend; use \OPNsense\OpenVPN\Export; @@ -317,9 +318,10 @@ class ExportController extends ApiControllerBase if ($server !== null) { // fetch server config data $config = array(); - foreach (array('disable', 'local_port', 'protocol', 'crypto', 'digest', 'tunnel_networkv6', 'reneg-sec', - 'local_network', 'local_networkv6', 'tunnel_network', 'compression', 'passtos', 'shared_key', - 'mode', 'dev_mode', 'tls', 'client_mgmt_port') as $field) { + foreach (array('disable', 'description', 'local_port', 'protocol', 'crypto', 'digest', + 'tunnel_networkv6', 'reneg-sec', 'local_network', 'local_networkv6', + 'tunnel_network', 'compression', 'passtos', 'shared_key', 'mode', + 'dev_mode', 'tls', 'client_mgmt_port') as $field) { if (!empty($server->$field)) { $config[$field] = (string)$server->$field; } else { @@ -329,6 +331,7 @@ class ExportController extends ApiControllerBase // fetch associated certificate data, add to config $config['server_ca_chain'] = array(); $config['server_cn'] = null; + $config['server_cert_is_srv'] = null; if (!empty($server->certref)) { if (isset(Config::getInstance()->object()->cert)) { foreach (Config::getInstance()->object()->cert as $cert) { @@ -355,6 +358,24 @@ class ExportController extends ApiControllerBase } } } + if ($certref !== null) { + if (isset(Config::getInstance()->object()->cert)) { + foreach (Config::getInstance()->object()->cert as $cert) { + if (isset($cert->refid) && (string)$certref == $cert->refid) { + // certificate CN + $str_crt = base64_decode((string)$cert->crt); + $inf_crt = openssl_x509_parse($str_crt); + $config['client_cn'] = $inf_crt['subject']['CN']; + $config['client_crt'] = (string)$cert->crt; + $config['client_prv'] = (string)$cert->prv; + } + } + } + if (empty($config['client_cn'])) { + throw new UserException("Client certificate not found", gettext("OpenVPN export")); + } + } + // overlay (saved) user settings if ($this->request->hasPost('openvpn_export')) { $response = $this->storePresetsAction($vpnid); @@ -364,12 +385,16 @@ class ExportController extends ApiControllerBase $config[$key] = (string)$value; } } - // request config generation - $factory = new ExportFactory(); - $provider = $factory->getProvider($config['template']); - if ($provider !== null) { - $provider->setConfig($config); - // TODO: execute provider and fetch content + if ($response['result'] == 'ok') { + // request config generation + $factory = new ExportFactory(); + $provider = $factory->getProvider($config['template']); + if ($provider !== null) { + $provider->setConfig($config); + $response['filename'] = $provider->getFilename(); + $response['filetype'] = $provider->getFileType(); + $response['content'] = base64_encode($provider->getContent()); + } } } } diff --git a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ExportFactory.php b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ExportFactory.php index 12c342918..2c3efd559 100644 --- a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ExportFactory.php +++ b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ExportFactory.php @@ -73,7 +73,7 @@ class ExportFactory { $providers = $this->listProviders(); if (!empty($providers[$className])) { - return $providers[$className]; + return $providers[$className]['handle']; } else { return null; } diff --git a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php index 1fe41075e..8b2f44559 100644 --- a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php +++ b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php @@ -44,4 +44,19 @@ interface IExportProvider * @return array list of supported options, so the user interface can hide the non supported ones */ public function supportedOptions(); + + /** + * @return string filename + */ + public function getFilename(); + + /** + * @return string file type + */ + public function getFileType(); + + /** + * @return string|binary content data + */ + public function getContent(); } diff --git a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/PlainOpenVPN.php b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/PlainOpenVPN.php index 48b077e18..b07222090 100644 --- a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/PlainOpenVPN.php +++ b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/PlainOpenVPN.php @@ -38,4 +38,53 @@ class PlainOpenVPN extends BaseExporter implements IExportProvider { return array("testxx1", "testxx3"); } + + /** + * @return string filename + */ + public function getFilename() + { + $result = array(); + if (!empty($this->config['description'])) { + $result[] = $this->config['description']; + } else { + $result[] = "openvpn"; + } + if (!empty($this->config['client_cn'])) { + $result[] = $this->config['client_cn']; + } + return implode("_", $result) . ".ovpn"; + } + + /** + * @return string file type + */ + public function getFileType() + { + return "text/plain"; + } + + /** + * @return array + */ + protected function openvpnConfParts() + { + $conf = array(); + if (isset($this->config['dev_mode'])) { + $conf[] = "dev {$this->config['dev_mode']}"; + } + $conf[] = "persist-tun"; + $conf[] = "persist-key"; + + return $conf; + } + + /** + * @return string content + */ + public function getContent() + { + + return implode("\n", $this->openvpnConfParts()); + } } diff --git a/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt b/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt index 49cb86c52..660d1249d 100644 --- a/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt +++ b/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt @@ -106,8 +106,17 @@ POSSIBILITY OF SUCH DAMAGE. var caref = $(this).data('certref'); var vpnid = $("#openvpn_export\\.servers").find('option:selected').val(); saveFormToEndpoint("/api/openvpn/export/download/"+vpnid+"/"+caref+"/",'frm_ExportSettings', function(data){ - // TODO: error handling + download to client when successful - console.log(data); + if (data.filename !== undefined) { + var link = $('') + .attr('href','data:'+data.filetype+';charset=utf8,' + encodeURIComponent(atob(data.content))) + .attr('download', data.filename) + .appendTo('body'); + + link.ready(function() { + link.get(0).click(); + link.empty(); + }); + } }); }); }