Compare commits
No commits in common. "4f773c0d2ff7372c4ea53d83d30c2b32b2d56a5c" and "0d69847a99ea7cb864b08f1889e441681002fbf8" have entirely different histories.
4f773c0d2f
...
0d69847a99
6 changed files with 13 additions and 311 deletions
|
@ -1,12 +0,0 @@
|
||||||
version: "3.6"
|
|
||||||
|
|
||||||
services:
|
|
||||||
zer.ooo:
|
|
||||||
image: d.xr.to/php
|
|
||||||
container_name: zer.ooo-test
|
|
||||||
volumes:
|
|
||||||
- ../:/sites/zer.ooo
|
|
||||||
working_dir: /sites/zer.ooo
|
|
||||||
ports:
|
|
||||||
- 127.0.0.1:80:80
|
|
||||||
command: ./docker/entrypoint.sh
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
echo 'extension=iconv.so' >> /etc/php/php.ini
|
|
||||||
echo 'extension=sqlite3.so' >> /etc/php/php.ini
|
|
||||||
|
|
||||||
test -d vendor || ./bin/setup_web
|
|
||||||
test -d storage/ca || mkdir storage/ca
|
|
||||||
test -f storage/ca/ca.crt || ./bin/setup
|
|
||||||
|
|
||||||
php -S 0.0.0.0:80 -t public public/index.php
|
|
|
@ -1,169 +0,0 @@
|
||||||
$(function () {
|
|
||||||
var keyLocation = $('#key-location');
|
|
||||||
var keyLocationContainer = keyLocation.parent();
|
|
||||||
var decryptKeyCheckbox = $('#decrypt-key');
|
|
||||||
var decryptKeyCheckboxContainer = decryptKeyCheckbox.parent();
|
|
||||||
var password = $('#password');
|
|
||||||
var passwordContainer = password.parent();
|
|
||||||
var embedConfiguration = $('#want-embedded');
|
|
||||||
var embedConfigurationContainer = embedConfiguration.parent();
|
|
||||||
var keyFileContent = null;
|
|
||||||
var buildConfigZip = $('#build-config-zip');
|
|
||||||
var getCertificateForm = $('#get-certificate-form');
|
|
||||||
|
|
||||||
decryptKeyCheckbox.change(function () {
|
|
||||||
if (this.checked) {
|
|
||||||
passwordContainer.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordContainer.hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleKeyFile(element) {
|
|
||||||
keyFileContent = element.target.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve zip file with post
|
|
||||||
getCertificateForm.submit(function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleZipResult(data) {
|
|
||||||
var blobUrl = URL.createObjectURL(data);
|
|
||||||
saveBlobUrl(blobUrl, 'config.zip');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEmbeddedResult(data) {
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
|
|
||||||
fileReader.onload = function() {
|
|
||||||
var text = this.result;
|
|
||||||
if (keyFileContent === null) {
|
|
||||||
saveText(text, 'server-embedded.conf');
|
|
||||||
}
|
|
||||||
|
|
||||||
var match = /<key>/.exec(text);
|
|
||||||
matchOffset = match.index + 6;
|
|
||||||
text = text.substring(0, matchOffset) + keyFileContent + text.substring(matchOffset);
|
|
||||||
|
|
||||||
if (decryptKeyCheckbox.prop('checked') === true) {
|
|
||||||
var keyPassword = password.val();
|
|
||||||
text = decryptKey(text, keyPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
saveText(text, 'server-embedded.conf');
|
|
||||||
};
|
|
||||||
|
|
||||||
fileReader.readAsText(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function decryptKey(text, keyPassword) {
|
|
||||||
var match = /<key>/.exec(text);
|
|
||||||
|
|
||||||
var keyStartOffset = match.index + 6;
|
|
||||||
|
|
||||||
match = /<\/key>/.exec(text);
|
|
||||||
|
|
||||||
var keyEndOffset = match.index;
|
|
||||||
|
|
||||||
var keyContent = text.substring(keyStartOffset, keyEndOffset);
|
|
||||||
|
|
||||||
var decryptedPrivateKey = forge.pki.decryptRsaPrivateKey(keyContent.trim(), keyPassword);
|
|
||||||
var decryptedPem = forge.pki.privateKeyToPem(decryptedPrivateKey);
|
|
||||||
|
|
||||||
return text.substring(0, keyStartOffset) + decryptedPem + text.substring(keyEndOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveText(text, fileName) {
|
|
||||||
var blob = new Blob([text], {type: 'text/plain'});
|
|
||||||
var blobUrl = URL.createObjectURL(blob);
|
|
||||||
saveBlobUrl(blobUrl, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloadElement = document.createElement("a");
|
|
||||||
document.body.appendChild(downloadElement);
|
|
||||||
downloadElement.style = "display: none";
|
|
||||||
|
|
||||||
function saveBlobUrl(url, fileName) {
|
|
||||||
downloadElement.href = url;
|
|
||||||
downloadElement.download = fileName;
|
|
||||||
downloadElement.click();
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitCertificateForm(event) {
|
|
||||||
var url = getCertificateForm.attr('action'),
|
|
||||||
method = getCertificateForm.attr('method'),
|
|
||||||
data = getCertificateForm.serialize(),
|
|
||||||
handler = handleZipResult;
|
|
||||||
|
|
||||||
if (embedConfiguration.prop('checked') === true) {
|
|
||||||
handler = handleEmbeddedResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = function () {
|
|
||||||
if (this.readyState == 4 && this.status == 200) {
|
|
||||||
//this.response is what you're looking for
|
|
||||||
handler(this.response);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.open(method, url);
|
|
||||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.send(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildConfigZip.on('click', submitCertificateForm);
|
|
||||||
|
|
||||||
keyLocationContainer.on('show', function () {
|
|
||||||
decryptKeyCheckboxContainer.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
keyLocationContainer.on('hide', function () {
|
|
||||||
decryptKeyCheckboxContainer.hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
decryptKeyCheckboxContainer.on('show', function () {
|
|
||||||
if (decryptKeyCheckbox.prop('checked') === true) {
|
|
||||||
passwordContainer.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
decryptKeyCheckboxContainer.on('hide', function () {
|
|
||||||
passwordContainer.hide();
|
|
||||||
passwordContainer.val('');
|
|
||||||
});
|
|
||||||
|
|
||||||
function setFileSelectVisibility() {
|
|
||||||
var selectedOption = $('#certificate option:selected');
|
|
||||||
|
|
||||||
if (selectedOption.data('hasPrivateKey') != '1') {
|
|
||||||
keyLocationContainer.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyLocationContainer.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
keyLocation.change(function () {
|
|
||||||
var file = this.files[0];
|
|
||||||
var reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = handleKeyFile;
|
|
||||||
|
|
||||||
reader.readAsText(file);
|
|
||||||
});
|
|
||||||
|
|
||||||
embedConfiguration.change(function () {
|
|
||||||
if (this.checked) {
|
|
||||||
setFileSelectVisibility();
|
|
||||||
decryptKeyCheckboxContainer.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
decryptKeyCheckboxContainer.hide();
|
|
||||||
keyLocationContainer.hide();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -16,38 +16,20 @@ class Action extends Session
|
||||||
$zipFile = tempnam(sys_get_temp_dir(), '0zip');
|
$zipFile = tempnam(sys_get_temp_dir(), '0zip');
|
||||||
$zip = new \ZipArchive();
|
$zip = new \ZipArchive();
|
||||||
$zip->open($zipFile, \ZipArchive::CREATE);
|
$zip->open($zipFile, \ZipArchive::CREATE);
|
||||||
$cert = $this->post('cert');
|
|
||||||
|
|
||||||
if ($cert === null) {
|
|
||||||
$this->getResponse()
|
|
||||||
->withStatus(500)
|
|
||||||
->write('Stop messing with the form');
|
|
||||||
}
|
|
||||||
|
|
||||||
$wantEmbedded = $this->post('want-embedded');
|
|
||||||
|
|
||||||
$server = ServerQuery::create()->findOneByFingerprint($this->post('fingerprint'));
|
$server = ServerQuery::create()->findOneByFingerprint($this->post('fingerprint'));
|
||||||
$name = $server->getFqdn();
|
$name = $server->getFqdn();
|
||||||
|
|
||||||
if ($wantEmbedded !== null) {
|
|
||||||
$certModel = CertificateQuery::create()->findOneByUserAndName($this->getUser(), $cert);
|
|
||||||
$config = $this->getEmbeddedConfig($server, $certModel);
|
|
||||||
$name .= '-' . $certModel->getName() . '.' . $certModel->getSerial();
|
|
||||||
|
|
||||||
return $this->getResponse()
|
|
||||||
->withHeader('Content-Type', 'text/plain')
|
|
||||||
->withHeader('Content-Disposition', 'attachment; filename="' . $name . '-embedded.conf"')
|
|
||||||
->write($config);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$certModel = CertificateQuery::create()->findOneByUserAndName($this->getUser(), $cert);
|
|
||||||
$this->addClientCertificateData($zip, $certModel);
|
|
||||||
|
|
||||||
$name .= '-' . $certModel->getName() . '.' . $certModel->getSerial();
|
|
||||||
|
|
||||||
$this->fillZipWithCaAndConfig($zip, $server);
|
$this->fillZipWithCaAndConfig($zip, $server);
|
||||||
|
|
||||||
|
$cert = $this->post('cert');
|
||||||
|
|
||||||
|
if ($cert !== null) {
|
||||||
|
$certModel = CertificateQuery::create()->findOneByUserAndName($this->getUser(), $cert);
|
||||||
|
$this->addClientCertificateData($zip, $certModel);
|
||||||
|
|
||||||
|
$name .= '-' . $certModel->getName() . '.' . $certModel->getSerial();
|
||||||
|
}
|
||||||
|
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
$zipContents = file_get_contents($zipFile);
|
$zipContents = file_get_contents($zipFile);
|
||||||
|
@ -70,33 +52,6 @@ class Action extends Session
|
||||||
$zip->addFromString('ca.crt', file_get_contents($this->getCore()->getBaseDir() . '/storage/ca/ca.crt'));
|
$zip->addFromString('ca.crt', file_get_contents($this->getCore()->getBaseDir() . '/storage/ca/ca.crt'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Server $server
|
|
||||||
* @param Certificate $cert
|
|
||||||
* @throws \Twig_Error_Loader
|
|
||||||
* @throws \Twig_Error_Runtime
|
|
||||||
* @throws \Twig_Error_Syntax
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getEmbeddedConfig($server, $cert)
|
|
||||||
{
|
|
||||||
/** @var \Twig_Environment $twig */
|
|
||||||
$twig = $this->get('twig');
|
|
||||||
|
|
||||||
$parameters = [
|
|
||||||
'server' => $server,
|
|
||||||
'ca' => file_get_contents($this->getCore()->getBaseDir() . '/storage/ca/ca.crt'),
|
|
||||||
'cert' => $cert->getCertificate(),
|
|
||||||
'key' => '',
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($cert->hasPrivateKey()) {
|
|
||||||
$parameters['key'] = $cert->getPrivateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $twig->render('etc/openvpn-client-embedded.conf.twig', $parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Server $server
|
* @param Server $server
|
||||||
* @return string
|
* @return string
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
client
|
|
||||||
|
|
||||||
dev zerooo
|
|
||||||
dev-type tun
|
|
||||||
|
|
||||||
proto {{ server.getProtocol() }}
|
|
||||||
|
|
||||||
remote {{ server.getExternalIp() }} {{ server.getPort() }}
|
|
||||||
resolv-retry infinite
|
|
||||||
nobind
|
|
||||||
|
|
||||||
user nobody
|
|
||||||
group nogroup
|
|
||||||
|
|
||||||
persist-key
|
|
||||||
persist-tun
|
|
||||||
|
|
||||||
remote-cert-tls server
|
|
||||||
|
|
||||||
cipher AES-256-CBC
|
|
||||||
|
|
||||||
comp-lzo
|
|
||||||
|
|
||||||
<ca>
|
|
||||||
{{ ca|trim }}
|
|
||||||
</ca>
|
|
||||||
|
|
||||||
<cert>
|
|
||||||
{{ cert|trim }}
|
|
||||||
</cert>
|
|
||||||
|
|
||||||
<key>
|
|
||||||
{{ key|trim }}
|
|
||||||
</key>
|
|
|
@ -1,19 +1,8 @@
|
||||||
{% extends "panel.html.twig" %}
|
{% extends "panel.html.twig" %}
|
||||||
|
|
||||||
{% block head %}
|
|
||||||
{{ parent() }}
|
|
||||||
|
|
||||||
<script src="/js/jquery.min.js"></script>
|
|
||||||
<script src="/js/forge.min.js"></script>
|
|
||||||
<script src="/js/jszip.min.js"></script>
|
|
||||||
<script src="/js/FileSaver.min.js"></script>
|
|
||||||
<script src="/js/pages/configBuilder.js"></script>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block panel_contents %}
|
{% block panel_contents %}
|
||||||
<h1 class="title">Config builder</h1>
|
<h1 class="title">Config builder</h1>
|
||||||
<form target="_blank" action="/panel/config-builder" method="post" class="form" id="get-certificate-form">
|
<form target="_blank" action="/panel/config-builder" method="post" class="form">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label for="server">Server</label>
|
<label for="server">Server</label>
|
||||||
<select name="fingerprint" id="server">
|
<select name="fingerprint" id="server">
|
||||||
|
@ -26,29 +15,12 @@
|
||||||
<label for="certificate">Certificate</label>
|
<label for="certificate">Certificate</label>
|
||||||
<select name="cert" id="certificate">
|
<select name="cert" id="certificate">
|
||||||
{% for certificate in user.getActiveCertificates() %}
|
{% for certificate in user.getActiveCertificates() %}
|
||||||
<option value="{{ certificate.getName() }}" data-has-private-key="{{ certificate.hasPrivateKey() ? '1' : '0' }}">{{ certificate.getName() }}</option>
|
<option value="{{ certificate.getName() }}">{{ certificate.getName() }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="buttons">
|
||||||
<label for="want-embedded">Generate embedded server config</label>
|
<button type="submit">Build</button>
|
||||||
<input type="checkbox" id="want-embedded" name="want-embedded">
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="row" style="display: none">
|
|
||||||
<label for="key-location">Select key file</label>
|
|
||||||
<input type="file" id="key-location" name="key-location">
|
|
||||||
</div>
|
|
||||||
<div class="row" style="display: none">
|
|
||||||
<label for="decrypt-key">Decrypt embedded private key?</label>
|
|
||||||
<input type="checkbox" id="decrypt-key" name="decrypt-key">
|
|
||||||
</div>
|
|
||||||
<div class="row" style="display: none">
|
|
||||||
<label for="password">Password</label>
|
|
||||||
<input type="password" id="password" name="password">
|
|
||||||
</div>
|
|
||||||
<div class="buttons">
|
|
||||||
<button id="build-config-zip" type="submit">Build</button>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue