Merge remote-tracking branch 'origin/master' into dns-editor

This commit is contained in:
Michael Kaufmann (d00p)
2016-05-16 19:59:27 +02:00
13 changed files with 235 additions and 125 deletions

View File

@@ -940,7 +940,8 @@ if ($page == 'customers'
WHERE `id` = :defaultip WHERE `id` = :defaultip
"); ");
$default_ips = Settings::Get('system.defaultip'); $default_ips = Settings::Get('system.defaultip');
$srv_ip = Database::pexecute_first($srv_ip_stmt, array('defaultip' => reset(explode(',', $default_ips)))); $default_ips = explode(',', $default_ips);
$srv_ip = Database::pexecute_first($srv_ip_stmt, array('defaultip' => reset($default_ips)));
$replace_arr = array( $replace_arr = array(
'FIRSTNAME' => $firstname, 'FIRSTNAME' => $firstname,

View File

@@ -245,6 +245,8 @@ if ($page == 'domains' || $page == 'overview') {
'domainid' => $id 'domainid' => $id
)); ));
triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $log);
$log->logAction(ADM_ACTION, LOG_INFO, "deleted domain/subdomains (#" . $result['id'] . ")"); $log->logAction(ADM_ACTION, LOG_INFO, "deleted domain/subdomains (#" . $result['id'] . ")");
updateCounters(); updateCounters();
inserttask('1'); inserttask('1');
@@ -672,10 +674,6 @@ if ($page == 'domains' || $page == 'overview') {
$issubof = '0'; $issubof = '0';
} }
if ($aliasdomain != 0 && $letsencrypt != 0) {
standard_error('letsencryptdoesnotworkwithaliasdomains');
}
if ($domain == '') { if ($domain == '') {
standard_error(array( standard_error(array(
'stringisempty', 'stringisempty',
@@ -843,6 +841,9 @@ elseif (Settings::Get('system.validate_domain') && ! validateDomain($domain)) {
Database::pexecute($ins_stmt, $ins_data); Database::pexecute($ins_stmt, $ins_data);
} }
} }
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
$log->logAction(ADM_ACTION, LOG_INFO, "added domain '" . $domain . "'"); $log->logAction(ADM_ACTION, LOG_INFO, "added domain '" . $domain . "'");
inserttask('1'); inserttask('1');
@@ -1472,10 +1473,6 @@ elseif (Settings::Get('system.validate_domain') && ! validateDomain($domain)) {
$issubof = '0'; $issubof = '0';
} }
if ($aliasdomain != 0 && $letsencrypt != 0) {
standard_error('letsencryptdoesnotworkwithaliasdomains');
}
if ($serveraliasoption != '1' && $serveraliasoption != '2') { if ($serveraliasoption != '1' && $serveraliasoption != '2') {
$serveraliasoption = '0'; $serveraliasoption = '0';
} }
@@ -1802,6 +1799,15 @@ elseif (Settings::Get('system.validate_domain') && ! validateDomain($domain)) {
} }
} }
} }
if ($result['aliasdomain'] != $aliasdomain) {
// trigger when domain id for alias destination has changed: both for old and new destination
triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $log);
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
} else
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
// or when wwwserveralias or letsencrypt was changed
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
}
$log->logAction(ADM_ACTION, LOG_INFO, "edited domain #" . $id); $log->logAction(ADM_ACTION, LOG_INFO, "edited domain #" . $id);
redirectTo($filename, array( redirectTo($filename, array(

View File

@@ -171,7 +171,7 @@ if ($page == 'overview') {
eval("echo \"" . getTemplate("domains/domainlist") . "\";"); eval("echo \"" . getTemplate("domains/domainlist") . "\";");
} elseif ($action == 'delete' && $id != 0) { } elseif ($action == 'delete' && $id != 0) {
$stmt = Database::prepare("SELECT `id`, `customerid`, `domain`, `documentroot`, `isemaildomain`, `parentdomainid` FROM `" . TABLE_PANEL_DOMAINS . "` $stmt = Database::prepare("SELECT `id`, `customerid`, `domain`, `documentroot`, `isemaildomain`, `parentdomainid`, `aliasdomain` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `customerid` = :customerid WHERE `customerid` = :customerid
AND `id` = :id" AND `id` = :id"
); );
@@ -197,6 +197,8 @@ if ($page == 'overview') {
} }
} }
triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $log);
$log->logAction(USR_ACTION, LOG_INFO, "deleted subdomain '" . $idna_convert->decode($result['domain']) . "'"); $log->logAction(USR_ACTION, LOG_INFO, "deleted subdomain '" . $idna_convert->decode($result['domain']) . "'");
$stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE
`customerid` = :customerid `customerid` = :customerid
@@ -290,6 +292,7 @@ if ($page == 'overview') {
ORDER BY `d`.`domain` ASC;" ORDER BY `d`.`domain` ASC;"
); );
$aliasdomain_check = Database::pexecute_first($aliasdomain_stmt, array("id" => $aliasdomain, "customerid" => $userinfo['customerid'])); $aliasdomain_check = Database::pexecute_first($aliasdomain_stmt, array("id" => $aliasdomain, "customerid" => $userinfo['customerid']));
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
} }
if (isset($_POST['url']) && $_POST['url'] != '' && validateUrl($idna_convert->encode($_POST['url']))) { if (isset($_POST['url']) && $_POST['url'] != '' && validateUrl($idna_convert->encode($_POST['url']))) {
@@ -342,11 +345,6 @@ if ($page == 'overview') {
} }
} }
if ($aliasdomain != 0 && $letsencrypt != 0)
{
standard_error('letsencryptdoesnotworkwithaliasdomains');
}
// Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated // Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated
if ($ssl_redirect > 0 && $letsencrypt == 1) { if ($ssl_redirect > 0 && $letsencrypt == 1) {
$ssl_redirect = 2; $ssl_redirect = 2;
@@ -610,11 +608,6 @@ if ($page == 'overview') {
$letsencrypt = '0'; $letsencrypt = '0';
} }
if ($aliasdomain != 0 && $letsencrypt != 0)
{
standard_error('letsencryptdoesnotworkwithaliasdomains');
}
// We can't enable let's encrypt for wildcard - domains // We can't enable let's encrypt for wildcard - domains
if ($iswildcarddomain == '1' && $letsencrypt == '1') { if ($iswildcarddomain == '1' && $letsencrypt == '1') {
standard_error('nowildcardwithletsencrypt'); standard_error('nowildcardwithletsencrypt');
@@ -677,6 +670,17 @@ if ($page == 'overview') {
"id" => $id "id" => $id
); );
Database::pexecute($stmt, $params); Database::pexecute($stmt, $params);
if ($result['aliasdomain'] != $aliasdomain) {
// trigger when domain id for alias destination has changed: both for old and new destination
triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $log);
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
} else
if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) {
// or when wwwserveralias or letsencrypt was changed
triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $log);
}
inserttask('1'); inserttask('1');
// Using nameserver, insert a task which rebuilds the server config // Using nameserver, insert a task which rebuilds the server config

View File

@@ -62,16 +62,23 @@ class lescript
$keys = $this->generateKey(); $keys = $this->generateKey();
// Only store the accountkey in production, in staging always generate a new key // Only store the accountkey in production, in staging always generate a new key
if (Settings::Get('system.letsencryptca') == 'production') { if (Settings::Get('system.letsencryptca') == 'production') {
$upd_stmt = Database::prepare(" $upd_stmt = Database::prepare(
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `lepublickey` = :public, `leprivatekey` = :private WHERE `customerid` = :customerid; "UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `lepublickey` = :public, `leprivatekey` = :private " .
"); "WHERE `customerid` = :customerid;");
Database::pexecute($upd_stmt, array( Database::pexecute($upd_stmt,
'public' => $keys['public'], array(
'private' => $keys['private'], 'public' => $keys['public'],
'customerid' => $certrow['customerid'] 'private' => $keys['private'],
)); 'customerid' => $certrow['customerid']
));
} }
$this->accountKey = $keys['private']; $this->accountKey = $keys['private'];
$response = $this->postNewReg();
if ($this->client->getLastCode() != 201) {
throw new \RuntimeException("Account not initialized, probably due to rate limiting. Whole response: " . $response);
}
$this->postNewReg(); $this->postNewReg();
$this->log('New account certificate registered'); $this->log('New account certificate registered');
} else { } else {
@@ -83,7 +90,7 @@ class lescript
public function signDomains(array $domains, $domainkey = null, $csr = null) public function signDomains(array $domains, $domainkey = null, $csr = null)
{ {
if (! $this->accountKey) { if (! $this->accountKey) {
throw new \RuntimeException("Account not initiated"); throw new \RuntimeException("Account not initialized");
} }
$this->log('Starting certificate generation process for domains'); $this->log('Starting certificate generation process for domains');
@@ -101,13 +108,14 @@ class lescript
$this->log("Requesting challenge for $domain"); $this->log("Requesting challenge for $domain");
$response = $this->signedRequest("/acme/new-authz", array( $response = $this->signedRequest("/acme/new-authz",
"resource" => "new-authz", array(
"identifier" => array( "resource" => "new-authz",
"type" => "dns", "identifier" => array(
"value" => $domain "type" => "dns",
) "value" => $domain
)); )
));
// if response is not an array but a string, it's most likely a server-error, e.g. // if response is not an array but a string, it's most likely a server-error, e.g.
// <HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY>An error occurred while processing your request. // <HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY>An error occurred while processing your request.
@@ -121,9 +129,10 @@ class lescript
} }
// choose http-01 challenge only // choose http-01 challenge only
$challenge = array_reduce($response['challenges'], function ($v, $w) { $challenge = array_reduce($response['challenges'],
return $v ? $v : ($w['type'] == 'http-01' ? $w : false); function ($v, $w) {
}); return $v ? $v : ($w['type'] == 'http-01' ? $w : false);
});
if (! $challenge) if (! $challenge)
throw new RuntimeException("HTTP Challenge for $domain is not available. Whole response: " . json_encode($response)); throw new RuntimeException("HTTP Challenge for $domain is not available. Whole response: " . json_encode($response));
@@ -145,8 +154,7 @@ class lescript
"e" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["e"]), "e" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["e"]),
"kty" => "RSA", "kty" => "RSA",
"n" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["n"]) "n" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["n"])
) );
;
$payload = $challenge['token'] . '.' . Base64UrlSafeEncoder::encode(hash('sha256', json_encode($header), true)); $payload = $challenge['token'] . '.' . Base64UrlSafeEncoder::encode(hash('sha256', json_encode($header), true));
file_put_contents($tokenPath, $payload); file_put_contents($tokenPath, $payload);
@@ -174,12 +182,13 @@ class lescript
$this->log("Sending request to challenge"); $this->log("Sending request to challenge");
// send request to challenge // send request to challenge
$result = $this->signedRequest($challenge['uri'], array( $result = $this->signedRequest($challenge['uri'],
"resource" => "challenge", array(
"type" => "http-01", "resource" => "challenge",
"keyAuthorization" => $payload, "type" => "http-01",
"token" => $challenge['token'] "keyAuthorization" => $payload,
)); "token" => $challenge['token']
));
// waiting loop // waiting loop
// we wait for a maximum of 30 seconds to avoid endless loops // we wait for a maximum of 30 seconds to avoid endless loops
@@ -218,9 +227,7 @@ class lescript
$this->client->getLastLinks(); $this->client->getLastLinks();
if (empty($csrfile) || Settings::Get('system.letsencryptreuseold') == 0) { $csr = $this->generateCSR($privateDomainKey, $domains);
$csr = $this->generateCSR($privateDomainKey, $domains);
}
// request certificates creation // request certificates creation
$result = $this->signedRequest("/acme/new-cert", array( $result = $this->signedRequest("/acme/new-cert", array(
@@ -306,7 +313,8 @@ class lescript
$tmpConfPath = $tmpConfMeta["uri"]; $tmpConfPath = $tmpConfMeta["uri"];
// workaround to get SAN working // workaround to get SAN working
fwrite($tmpConf, 'HOME = . fwrite($tmpConf,
'HOME = .
RANDFILE = $ENV::HOME/.rnd RANDFILE = $ENV::HOME/.rnd
[ req ] [ req ]
default_bits = ' . Settings::Get('system.letsencryptkeysize') . ' default_bits = ' . Settings::Get('system.letsencryptkeysize') . '
@@ -320,15 +328,16 @@ basicConstraints = CA:FALSE
subjectAltName = ' . $san . ' subjectAltName = ' . $san . '
keyUsage = nonRepudiation, digitalSignature, keyEncipherment'); keyUsage = nonRepudiation, digitalSignature, keyEncipherment');
$csr = openssl_csr_new(array( $csr = openssl_csr_new(
"CN" => $domain, array(
"ST" => Settings::Get('system.letsencryptstate'), "CN" => $domain,
"C" => Settings::Get('system.letsencryptcountrycode'), "ST" => Settings::Get('system.letsencryptstate'),
"O" => "Unknown" "C" => Settings::Get('system.letsencryptcountrycode'),
), $privateKey, array( "O" => "Unknown"
"config" => $tmpConfPath, ), $privateKey, array(
"digest_alg" => "sha256" "config" => $tmpConfPath,
)); "digest_alg" => "sha256"
));
if (! $csr) if (! $csr)
throw new \RuntimeException("CSR couldn't be generated! " . openssl_error_string()); throw new \RuntimeException("CSR couldn't be generated! " . openssl_error_string());
@@ -343,10 +352,11 @@ keyUsage = nonRepudiation, digitalSignature, keyEncipherment');
private function generateKey() private function generateKey()
{ {
$res = openssl_pkey_new(array( $res = openssl_pkey_new(
"private_key_type" => OPENSSL_KEYTYPE_RSA, array(
"private_key_bits" => (int) Settings::Get('system.letsencryptkeysize') "private_key_type" => OPENSSL_KEYTYPE_RSA,
)); "private_key_bits" => (int) Settings::Get('system.letsencryptkeysize')
));
if (! openssl_pkey_export($res, $privateKey)) { if (! openssl_pkey_export($res, $privateKey)) {
throw new \RuntimeException("Key export failed!"); throw new \RuntimeException("Key export failed!");

View File

@@ -40,14 +40,14 @@
</visibility> </visibility>
<content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content> <content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content>
</command> </command>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
</commands> </commands>
</general> </general>
<!-- HTTP Apache --> <!-- HTTP Apache -->
<daemon name="apache" version="2.4" title="Apache 2.4" default="true"> <daemon name="apache" version="2.4" title="Apache 2.4" default="true">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<command> <command>
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>
@@ -4022,7 +4022,7 @@ aliases: files
<command><![CDATA[/etc/init.d/nscd restart]]></command> <command><![CDATA[/etc/init.d/nscd restart]]></command>
<!-- clear group chache --> <!-- clear group chache -->
<command><![CDATA[nscd --invalidate=group]]></command> <command><![CDATA[nscd --invalidate=group]]></command>
<file /><!-- separate the following mkdir command from the previous nscd --> <!-- @TODO separate the following mkdir command from the previous nscd -->
<command> <command>
<visibility mode="notisdir">/etc/insserv/overrides</visibility> <visibility mode="notisdir">/etc/insserv/overrides</visibility>
<content><![CDATA[mkdir -p /etc/insserv/overrides]]></content> <content><![CDATA[mkdir -p /etc/insserv/overrides]]></content>

View File

@@ -40,8 +40,6 @@
</visibility> </visibility>
<content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content> <content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content>
</command> </command>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
</commands> </commands>
</general> </general>
<!-- HTTP Apache --> <!-- HTTP Apache -->
@@ -49,6 +47,8 @@
default="true"> default="true">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<file name="/etc/apache2/mods-enabled/fastcgi.conf"> <file name="/etc/apache2/mods-enabled/fastcgi.conf">
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>

View File

@@ -40,8 +40,6 @@
</visibility> </visibility>
<content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content> <content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content>
</command> </command>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
</commands> </commands>
</general> </general>
<!-- HTTP Apache --> <!-- HTTP Apache -->

View File

@@ -40,8 +40,6 @@
</visibility> </visibility>
<content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content> <content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content>
</command> </command>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
</commands> </commands>
</general> </general>
<!-- HTTP Apache --> <!-- HTTP Apache -->
@@ -49,6 +47,8 @@
default="true"> default="true">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<file name="/etc/apache2/mods-enabled/fastcgi.conf"> <file name="/etc/apache2/mods-enabled/fastcgi.conf">
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>
@@ -83,6 +83,8 @@ Alias "/.well-known/acme-challenge" "{{settings.system.letsencryptchallengepath}
<daemon name="apache" version="2.4" title="Apache 2.4"> <daemon name="apache" version="2.4" title="Apache 2.4">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<file name="/etc/apache2/mods-enabled/fastcgi.conf"> <file name="/etc/apache2/mods-enabled/fastcgi.conf">
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>

View File

@@ -40,8 +40,6 @@
</visibility> </visibility>
<content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content> <content><![CDATA[mkdir -p {{settings.system.deactivateddocroot}}]]></content>
</command> </command>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
</commands> </commands>
</general> </general>
<!-- HTTP Apache --> <!-- HTTP Apache -->
@@ -49,6 +47,8 @@
default="true"> default="true">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<file name="/etc/apache2/mods-enabled/fastcgi.conf"> <file name="/etc/apache2/mods-enabled/fastcgi.conf">
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>
@@ -83,6 +83,8 @@ Alias "/.well-known/acme-challenge" "{{settings.system.letsencryptchallengepath}
<daemon name="apache" version="2.4" title="Apache 2.4"> <daemon name="apache" version="2.4" title="Apache 2.4">
<install><![CDATA[apt-get install apache2]]></install> <install><![CDATA[apt-get install apache2]]></install>
<include>//service[@type='http']/general/commands</include> <include>//service[@type='http']/general/commands</include>
<command><![CDATA[a2dismod userdir]]></command>
<command><![CDATA[a2enmod headers]]></command>
<file name="/etc/apache2/mods-enabled/fastcgi.conf"> <file name="/etc/apache2/mods-enabled/fastcgi.conf">
<visibility mode="true">{{settings.phpfpm.enabled}} <visibility mode="true">{{settings.phpfpm.enabled}}
</visibility> </visibility>

View File

@@ -0,0 +1,34 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Daniel Reichelt <hacking@nachtgeist.net> (2016-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package Functions
*
*/
function triggerLetsEncryptCSRForAliasDestinationDomain($aliasDestinationDomainID, $log)
{
if (isset($aliasDestinationDomainID) && $aliasDestinationDomainID > 0) {
$log->logAction(ADM_ACTION, LOG_INFO, "LetsEncrypt CSR triggered for domain ID " . $aliasDestinationDomainID);
$upd_stmt = Database::prepare(
"UPDATE
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
SET
`expirationdate` = null
WHERE
domainid = :domainid
");
Database::pexecute($upd_stmt, array(
'domainid' => $aliasDestinationDomainID
));
}
}

View File

@@ -1936,7 +1936,6 @@ $lng['customer']['letsencrypt']['title'] = 'Use Let\'s Encrypt';
$lng['customer']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.<br><strong class="red">ATTENTION:</strong> This feature is still in beta.'; $lng['customer']['letsencrypt']['description'] = 'Get a free certificate from <a href="https://letsencrypt.org">Let\'s Encrypt</a>. The certificate will be created and renewed automatically.<br><strong class="red">ATTENTION:</strong> This feature is still in beta.';
$lng['error']['sslredirectonlypossiblewithsslipport'] = 'Using Let\'s Encrypt is only possible when the domain has at least one ssl-enabled IP/port combination assigned.'; $lng['error']['sslredirectonlypossiblewithsslipport'] = 'Using Let\'s Encrypt is only possible when the domain has at least one ssl-enabled IP/port combination assigned.';
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot (yet) handle wildcard-domains. Please set the ServerAlias to WWW or disable it completely'; $lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot (yet) handle wildcard-domains. Please set the ServerAlias to WWW or disable it completely';
$lng['error']['letsencryptdoesnotworkwithaliasdomains'] = "Usage of Let's Encrypt is not possible for aliasdomains at the moment. Please disable Let's Encrypt or AliasDomain";
$lng['panel']['letsencrypt'] = 'Using Let\'s encrypt'; $lng['panel']['letsencrypt'] = 'Using Let\'s encrypt';
$lng['crondesc']['cron_letsencrypt'] = 'updating Let\'s Encrypt certificates'; $lng['crondesc']['cron_letsencrypt'] = 'updating Let\'s Encrypt certificates';
$lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt environment"; $lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt environment";
@@ -1949,8 +1948,8 @@ $lng['serversettings']['letsencryptchallengepath']['title'] = "Path for Let's En
$lng['serversettings']['letsencryptchallengepath']['description'] = "Directory where the Let's Encrypt challenges should be offered from via a global alias.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>"; $lng['serversettings']['letsencryptchallengepath']['description'] = "Directory where the Let's Encrypt challenges should be offered from via a global alias.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>";
$lng['serversettings']['letsencryptkeysize']['title'] = "Key size for new Let's Encrypt certificates"; $lng['serversettings']['letsencryptkeysize']['title'] = "Key size for new Let's Encrypt certificates";
$lng['serversettings']['letsencryptkeysize']['description'] = "Size of the key in Bits for new Let's Encrypt certificates.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>"; $lng['serversettings']['letsencryptkeysize']['description'] = "Size of the key in Bits for new Let's Encrypt certificates.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>";
$lng['serversettings']['letsencryptreuseold']['title'] = "Re-use Let's Encrypt key / CSR"; $lng['serversettings']['letsencryptreuseold']['title'] = "Re-use Let's Encrypt key";
$lng['serversettings']['letsencryptreuseold']['description'] = "If activated, the same key and CSR will be used for every renew, otherwise a new key / CSR will be generated every time.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>"; $lng['serversettings']['letsencryptreuseold']['description'] = "If activated, the same key will be used for every renew, otherwise a new key will be generated every time.<br><strong class=\"red\">ATTENTION:</strong> Let's Encrypt is still in beta</strong>";
$lng['serversettings']['leenabled']['title'] = "Enable Let's Encrypt"; $lng['serversettings']['leenabled']['title'] = "Enable Let's Encrypt";
$lng['serversettings']['leenabled']['description'] = "If activated, customers are able to let froxlor automatically generate and renew Let's Encrypt ssl-certificates for domains with a ssl IP/port.<br /><br />Please remember that you need to go through the webserver-configuration when eabled because this feature needs a special configuration."; $lng['serversettings']['leenabled']['description'] = "If activated, customers are able to let froxlor automatically generate and renew Let's Encrypt ssl-certificates for domains with a ssl IP/port.<br /><br />Please remember that you need to go through the webserver-configuration when eabled because this feature needs a special configuration.";
$lng['domains']['ssl_redirect_temporarilydisabled'] = "<br>The SSL redirect is temporarily deactivated while a new Let's Encrypt certificate is generated. It will be activated again after the certificate was generated."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "<br>The SSL redirect is temporarily deactivated while a new Let's Encrypt certificate is generated. It will be activated again after the certificate was generated.";

View File

@@ -1590,7 +1590,6 @@ $lng['customer']['letsencrypt']['title'] = 'Benutze Let\'s Encrypt';
$lng['customer']['letsencrypt']['description'] = 'Holt ein kostenloses Zertifikat von <a href="https://letsencrypt.org">Let\'s Encrypt</a>. Das Zertifikat wird automatisch erstellt und verlängert.<br><strong class="red">ACHTUNG:</strong> Dieses Feature befindet sich noch im Test.'; $lng['customer']['letsencrypt']['description'] = 'Holt ein kostenloses Zertifikat von <a href="https://letsencrypt.org">Let\'s Encrypt</a>. Das Zertifikat wird automatisch erstellt und verlängert.<br><strong class="red">ACHTUNG:</strong> Dieses Feature befindet sich noch im Test.';
$lng['error']['sslredirectonlypossiblewithsslipport'] = 'Die Nutzung von Let\'s Encrypt ist nur möglich, wenn die Domain mindestens eine IP/Port - Kombination mit aktiviertem SSL zugewiesen hat.'; $lng['error']['sslredirectonlypossiblewithsslipport'] = 'Die Nutzung von Let\'s Encrypt ist nur möglich, wenn die Domain mindestens eine IP/Port - Kombination mit aktiviertem SSL zugewiesen hat.';
$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann (noch) nicht mit Wildcard-Domains umgehen. Bitte den ServerAlias auf WWW setzen oder deaktivieren'; $lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann (noch) nicht mit Wildcard-Domains umgehen. Bitte den ServerAlias auf WWW setzen oder deaktivieren';
$lng['error']['letsencryptdoesnotworkwithaliasdomains'] = "Die Nutzung von Let's Encrypt ist mit AliasDomains derzeit nicht möglich. Bitte Let's Encrypt oder AliasDomain deaktivieren";
$lng['panel']['letsencrypt'] = 'Benutzt Let\'s encrypt'; $lng['panel']['letsencrypt'] = 'Benutzt Let\'s encrypt';
$lng['crondesc']['cron_letsencrypt'] = 'aktualisiert Let\'s Encrypt Zertifikate'; $lng['crondesc']['cron_letsencrypt'] = 'aktualisiert Let\'s Encrypt Zertifikate';
$lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt Umgebung"; $lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt Umgebung";
@@ -1603,8 +1602,8 @@ $lng['serversettings']['letsencryptchallengepath']['title'] = "Verzeichnis für
$lng['serversettings']['letsencryptchallengepath']['description'] = "Let's Encrypt challenges werden aus diesem Verzeichnis über einen globalen Alias ausgeliefert.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test"; $lng['serversettings']['letsencryptchallengepath']['description'] = "Let's Encrypt challenges werden aus diesem Verzeichnis über einen globalen Alias ausgeliefert.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test";
$lng['serversettings']['letsencryptkeysize']['title'] = "Schlüsselgröße für neue Let's Encrypt Zertifikate"; $lng['serversettings']['letsencryptkeysize']['title'] = "Schlüsselgröße für neue Let's Encrypt Zertifikate";
$lng['serversettings']['letsencryptkeysize']['description'] = "Größe des Schlüssels in Bit für neue Let's Encrypt Zertifikate.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test"; $lng['serversettings']['letsencryptkeysize']['description'] = "Größe des Schlüssels in Bit für neue Let's Encrypt Zertifikate.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test";
$lng['serversettings']['letsencryptreuseold']['title'] = "Let's Encrypt Schlüssel / CSR wiederverwenden"; $lng['serversettings']['letsencryptreuseold']['title'] = "Let's Encrypt Schlüssel wiederverwenden";
$lng['serversettings']['letsencryptreuseold']['description'] = "Wenn dies aktiviert ist, werden der alte Schlüssel und CSR bei jeder Verlängerung verwendet, andernfalls wird ein neues Paar generiert.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test"; $lng['serversettings']['letsencryptreuseold']['description'] = "Wenn dies aktiviert ist, wird der alte Schlüssel bei jeder Verlängerung verwendet, andernfalls wird ein neues Paar generiert.<br><strong class=\"red\">ACHTUNG:</strong> Let's Encrypt befindet sich noch im Test";
$lng['serversettings']['leenabled']['title'] = "Let's Encrypt verwenden"; $lng['serversettings']['leenabled']['title'] = "Let's Encrypt verwenden";
$lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, können Kunden durch Froxlor automatisch generierte und verlängerbare Let's Encrypt SSL-Zertifikate für Domains mit SSL IP/port nutzen.<br /><br />Bitte die Webserver-Konfiguration beachten wenn aktiviert, da dieses Feature eine spezielle Konfiguration benötigt."; $lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, können Kunden durch Froxlor automatisch generierte und verlängerbare Let's Encrypt SSL-Zertifikate für Domains mit SSL IP/port nutzen.<br /><br />Bitte die Webserver-Konfiguration beachten wenn aktiviert, da dieses Feature eine spezielle Konfiguration benötigt.";
$lng['domains']['ssl_redirect_temporarilydisabled'] = "<br>Die SSL-Umleitung ist, während ein neues Let's Encrypt - Zertifikat erstellt wird, temporär deaktiviert. Die Umleitung wird nach der Zertifikatserstellung wieder aktiviert."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "<br>Die SSL-Umleitung ist, während ein neues Let's Encrypt - Zertifikat erstellt wird, temporär deaktiviert. Die Umleitung wird nach der Zertifikatserstellung wieder aktiviert.";

View File

@@ -1,5 +1,4 @@
<?php <?php
if (! defined('MASTER_CRONJOB')) if (! defined('MASTER_CRONJOB'))
die('You cannot access this file directly!'); die('You cannot access this file directly!');
@@ -25,23 +24,74 @@ $cronlog->logAction(CRON_ACTION, LOG_INFO, "Updating Let's Encrypt certificates"
if (! extension_loaded('curl')) { if (! extension_loaded('curl')) {
$cronlog->logAction(CRON_ACTION, LOG_ERR, "Let's Encrypt requires the php cURL extension to be installed."); $cronlog->logAction(CRON_ACTION, LOG_ERR, "Let's Encrypt requires the php cURL extension to be installed.");
exit; exit();
} }
$certificates_stmt = Database::query(" $certificates_stmt = Database::query(
SELECT domssl.`id`, domssl.`domainid`, domssl.expirationdate, domssl.`ssl_cert_file`, domssl.`ssl_key_file`, domssl.`ssl_ca_file`, domssl.`ssl_csr_file`, dom.`domain`, dom.`iswildcarddomain`, dom.`wwwserveralias`, "
dom.`documentroot`, dom.`id` as 'domainid', dom.`ssl_redirect`, cust.`leprivatekey`, cust.`lepublickey`, cust.customerid, cust.loginname SELECT
FROM `" . TABLE_PANEL_CUSTOMERS . "` as cust, `" . TABLE_PANEL_DOMAINS . "` dom LEFT JOIN `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` domssl ON (dom.id = domssl.domainid) domssl.`id`,
WHERE dom.customerid = cust.customerid AND dom.letsencrypt = 1 AND (domssl.expirationdate < DATE_ADD(NOW(), INTERVAL 30 DAY) OR domssl.expirationdate IS NULL) domssl.`domainid`,
"); domssl.expirationdate,
domssl.`ssl_cert_file`,
domssl.`ssl_key_file`,
domssl.`ssl_ca_file`,
domssl.`ssl_csr_file`,
dom.`domain`,
dom.`wwwserveralias`,
dom.`documentroot`,
dom.`id` AS 'domainid',
dom.`ssl_redirect`,
cust.`leprivatekey`,
cust.`lepublickey`,
cust.`customerid`,
cust.`loginname`
FROM
`" . TABLE_PANEL_CUSTOMERS . "` AS cust,
`" . TABLE_PANEL_DOMAINS . "` AS dom
LEFT JOIN
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` AS domssl ON
dom.`id` = domssl.`domainid`
WHERE
dom.`customerid` = cust.`customerid`
AND dom.`letsencrypt` = 1
AND dom.`aliasdomain` IS NULL
AND dom.`iswildcarddomain` = 0
AND (
domssl.`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY)
OR domssl.`expirationdate` IS NULL
)
");
$updcert_stmt = Database::prepare(" $aliasdomains_stmt = Database::prepare(
REPLACE INTO `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `id` = :id, `domainid` = :domainid, `ssl_cert_file` = :crt, `ssl_key_file` = :key, `ssl_ca_file` = :ca, `ssl_cert_chainfile` = :chain, `ssl_csr_file` = :csr, expirationdate = :expirationdate "
"); SELECT
dom.`id` as domainid,
dom.`domain`,
dom.`wwwserveralias`
FROM `" . TABLE_PANEL_DOMAINS . "` AS dom
WHERE
dom.`aliasdomain` = :id
AND dom.`letsencrypt` = 1
AND dom.`iswildcarddomain` = 0
");
$upddom_stmt = Database::prepare(" $updcert_stmt = Database::prepare(
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid "
"); REPLACE INTO
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
SET
`id` = :id,
`domainid` = :domainid,
`ssl_cert_file` = :crt,
`ssl_key_file` = :key,
`ssl_ca_file` = :ca,
`ssl_cert_chainfile` = :chain,
`ssl_csr_file` = :csr,
`expirationdate` = :expirationdate
");
$upddom_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `ssl_redirect` = '1' WHERE `id` = :domainid");
$changedetected = 0; $changedetected = 0;
$certrows = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC); $certrows = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -56,25 +106,27 @@ foreach ($certrows as $certrow) {
if ($certrow['ssl_redirect'] != 2) { if ($certrow['ssl_redirect'] != 2) {
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Updating " . $certrow['domain']); $cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Updating " . $certrow['domain']);
if ($certrow['ssl_cert_file']) { $cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Adding SAN entry: " . $certrow['domain']);
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, "letsencrypt using old key / SAN for " . $certrow['domain']); $domains = array(
// Parse the old certificate $certrow['domain']
$x509data = openssl_x509_parse($certrow['ssl_cert_file']); );
// add www.<domain> to SAN list
if ($certrow['wwwserveralias'] == 1) {
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Adding SAN entry: www." . $certrow['domain']);
$domains[] = 'www.' . $certrow['domain'];
}
// We are interessted in the old SAN - data // add alias domains (and possibly www.<aliasdomain>) to SAN list
$san = explode(', ', $x509data['extensions']['subjectAltName']); Database::pexecute($aliasdomains_stmt, array(
$domains = array(); 'id' => $certrow['domainid']
foreach ($san as $dnsname) { ));
$domains[] = substr($dnsname, 4); $aliasdomains = $aliasdomains_stmt->fetchAll(PDO::FETCH_ASSOC);
} foreach ($aliasdomains as $aliasdomain) {
} else { $cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Adding SAN entry: " . $aliasdomain['domain']);
$cronlog->logAction(CRON_ACTION, LOG_DEBUG, "letsencrypt generating new key / SAN for " . $certrow['domain']); $domains[] = $aliasdomain['domain'];
$domains = array( if ($aliasdomain['wwwserveralias'] == 1) {
$certrow['domain'] $cronlog->logAction(CRON_ACTION, LOG_DEBUG, "Adding SAN entry: www." . $aliasdomain['domain']);
); $domains[] = 'www.' . $aliasdomain['domain'];
// Add www.<domain> for SAN
if ($certrow['wwwserveralias'] == 1) {
$domains[] = 'www.' . $certrow['domain'];
} }
} }
@@ -92,16 +144,17 @@ foreach ($certrows as $certrow) {
$newcert = openssl_x509_parse($return['crt']); $newcert = openssl_x509_parse($return['crt']);
// Store the new data // Store the new data
Database::pexecute($updcert_stmt, array( Database::pexecute($updcert_stmt,
'id' => $certrow['id'], array(
'domainid' => $certrow['domainid'], 'id' => $certrow['id'],
'crt' => $return['crt'], 'domainid' => $certrow['domainid'],
'key' => $return['key'], 'crt' => $return['crt'],
'ca' => $return['chain'], 'key' => $return['key'],
'chain' => $return['chain'], 'ca' => $return['chain'],
'csr' => $return['csr'], 'chain' => $return['chain'],
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']) 'csr' => $return['csr'],
)); 'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
));
if ($certrow['ssl_redirect'] == 3) { if ($certrow['ssl_redirect'] == 3) {
Database::pexecute($upddom_stmt, array( Database::pexecute($upddom_stmt, array(
@@ -113,10 +166,12 @@ foreach ($certrows as $certrow) {
$changedetected = 1; $changedetected = 1;
} catch (Exception $e) { } catch (Exception $e) {
$cronlog->logAction(CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ": " . $e->getMessage()); $cronlog->logAction(CRON_ACTION, LOG_ERR,
"Could not get Let's Encrypt certificate for " . $certrow['domain'] . ": " . $e->getMessage());
} }
} else { } else {
$cronlog->logAction(CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect"); $cronlog->logAction(CRON_ACTION, LOG_WARNING,
"Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
} }
} }