From d4e5e32c14e252840e1aa63302f0801eb4dcf65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sat, 27 Jul 2019 17:36:31 +0200 Subject: [PATCH 01/17] Implement CAA DNS record for letsencrypt.org --- install/froxlor.sql | 1 + install/updates/froxlor/0.10/update_0.10.inc.php | 6 ++++++ lib/Froxlor/Dns/Dns.php | 11 +++++++++++ .../admin/domains/formfield.domains_add.php | 13 +++++++++++++ .../admin/domains/formfield.domains_edit.php | 15 +++++++++++++++ .../customer/domains/formfield.domains_add.php | 13 +++++++++++++ .../customer/domains/formfield.domains_edit.php | 15 +++++++++++++++ lng/english.lng.php | 6 ++++++ lng/german.lng.php | 6 ++++++ 9 files changed, 86 insertions(+) diff --git a/install/froxlor.sql b/install/froxlor.sql index ec917791..76fe4d6d 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -256,6 +256,7 @@ CREATE TABLE `panel_domains` ( `mod_fcgid_maxrequests` int(4) default '-1', `ismainbutsubto` int(11) unsigned NOT NULL default '0', `letsencrypt` tinyint(1) NOT NULL default '0', + `caa` tinyint(1) NOT NULL default '0', `hsts` varchar(10) NOT NULL default '0', `hsts_sub` tinyint(1) NOT NULL default '0', `hsts_preload` tinyint(1) NOT NULL default '0', diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index 030b82a8..41dfb662 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -263,3 +263,9 @@ if (\Froxlor\Froxlor::isDatabaseVersion('201904100')) { if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc1')) { \Froxlor\Froxlor::updateToVersion('0.10.0-rc2'); } + +if (\Froxlor\Froxlor::isDatabaseVersion('201904250')) { + + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `caa` TINYINT(1) NOT NULL DEFAULT '0' AFTER `letsencrypt`;"); + \Froxlor\Froxlor::updateToDbVersion('201907270'); +} \ No newline at end of file diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index cfc77e93..c34a5543 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -130,6 +130,12 @@ class Dns } } + // additional required records for CAA if activated + if ($domain['caa'] == '1') { + // check for CAA content later + self::addRequiredEntry('@', 'CAA', $required_entries); + } + // additional required records for SPF and DKIM if activated if ($domain['isemaildomain'] == '1') { if (Settings::Get('spf.use_spf') == '1') { @@ -278,6 +284,11 @@ class Dns } } } + + // CAA + if (array_key_exists("CAA", $required_entries)) { + $zonerecords[] = new DnsEntry('@', 'CAA', '0 issue "letsencrypt.org"'); + } } if (empty($primary_ns)) { diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index ddbb6266..b3460fae 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -214,6 +214,19 @@ return array( ), 'value' => array() ), + 'caa' => array( + 'visible' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? true : false) : false), + 'label' => $lng['admin']['caa']['title'], + 'desc' => $lng['admin']['caa']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() + ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', 'label' => $lng['admin']['domain_http2']['title'], diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 4c756ec1..7fe2fe54 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -250,6 +250,21 @@ return array( $result['letsencrypt'] ) ), + 'caa' => array( + 'visible' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? true : false) : false), + 'label' => $lng['admin']['caa']['title'], + 'desc' => $lng['admin']['caa']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['caa'] + ) + ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', 'label' => $lng['admin']['domain_http2']['title'], diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php index 00d9fca6..b620dba1 100644 --- a/lib/formfields/customer/domains/formfield.domains_add.php +++ b/lib/formfields/customer/domains/formfield.domains_add.php @@ -108,6 +108,19 @@ return array( ), 'value' => array() ), + 'caa' => array( + 'visible' => \Froxlor\Settings::Get('system.leenabled') == '1' ? true : false, + 'label' => $lng['customer']['caa']['title'], + 'desc' => $lng['customer']['caa']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() + ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index 56a28543..c5315487 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -128,6 +128,21 @@ return array( $result['letsencrypt'] ) ), + 'caa' => array( + 'visible' => \Froxlor\Settings::Get('system.leenabled') == '1' ? true : false, + 'label' => $lng['customer']['caa']['title'], + 'desc' => $lng['customer']['caa']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['caa'] + ) + ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], diff --git a/lng/english.lng.php b/lng/english.lng.php index e76477c5..3ee60eeb 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1848,6 +1848,12 @@ $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.

Please remember that you need to go through the webserver-configuration when enabled because this feature needs a special configuration."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; +// Added for CAA record support +$lng['admin']['caa']['title'] = 'Use CAA DNS record'; +$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record. Currently it only supports Let\'s Encrypt. This feature is still in beta.'; +$lng['customer']['caa']['title'] = 'Use CAA DNS record'; +$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record. Currently it only supports Let\'s Encrypt. This feature is still in beta.'; + // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; $lng['error']['customized_version'] = 'It looks like your Froxlor installation has been modified, no support sorry.'; diff --git a/lng/german.lng.php b/lng/german.lng.php index f1f44c27..37c3f08f 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1500,6 +1500,12 @@ $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.

Bitte die Webserver-Konfiguration beachten wenn aktiviert, da dieses Feature eine spezielle Konfiguration benötigt."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; +// Added for CAA record support +$lng['admin']['caa']['title'] = 'CAA DNS Eintrag erstellen'; +$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden. Im Moment wird nur Let\'s Encrypt unterstützt. Dieses Feature befindet sich noch im Test.'; +$lng['customer']['caa']['title'] = 'CAA DNS Eintrag erstellen'; +$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden. Im Moment wird nur Let\'s Encrypt unterstützt. Dieses Feature befindet sich noch im Test.'; + // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; $lng['error']['customized_version'] = 'Es scheint als wäre die Froxlor Installation angepasst worden. Kein Support, sorry.'; From 64fe300e426acbf85ae3d1a746ef060e261ae4b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 16:28:29 +0200 Subject: [PATCH 02/17] Implement general CAA DNS records for all issuers --- install/froxlor.sql | 2 +- .../updates/froxlor/0.10/update_0.10.inc.php | 2 +- lib/Froxlor/Dns/Dns.php | 19 +++++++++++++++++-- .../admin/domains/formfield.domains_add.php | 15 ++++++--------- .../admin/domains/formfield.domains_edit.php | 17 ++++++----------- .../domains/formfield.domains_add.php | 15 ++++++--------- .../domains/formfield.domains_edit.php | 17 ++++++----------- lng/english.lng.php | 8 ++++---- lng/german.lng.php | 8 ++++---- 9 files changed, 51 insertions(+), 52 deletions(-) diff --git a/install/froxlor.sql b/install/froxlor.sql index 76fe4d6d..f50c5c1f 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -256,7 +256,7 @@ CREATE TABLE `panel_domains` ( `mod_fcgid_maxrequests` int(4) default '-1', `ismainbutsubto` int(11) unsigned NOT NULL default '0', `letsencrypt` tinyint(1) NOT NULL default '0', - `caa` tinyint(1) NOT NULL default '0', + `caa` text default NULL, `hsts` varchar(10) NOT NULL default '0', `hsts_sub` tinyint(1) NOT NULL default '0', `hsts_preload` tinyint(1) NOT NULL default '0', diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index 41dfb662..fae59b55 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -266,6 +266,6 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc1')) { if (\Froxlor\Froxlor::isDatabaseVersion('201904250')) { - Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `caa` TINYINT(1) NOT NULL DEFAULT '0' AFTER `letsencrypt`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `caa` text default NULL AFTER `letsencrypt`;"); \Froxlor\Froxlor::updateToDbVersion('201907270'); } \ No newline at end of file diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index c34a5543..0d754f21 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -131,9 +131,15 @@ class Dns } // additional required records for CAA if activated - if ($domain['caa'] == '1') { + if (!is_null($domain['caa'])) { // check for CAA content later self::addRequiredEntry('@', 'CAA', $required_entries); + // additional required records by subdomain setting + if ($domain['iswildcarddomain'] == '1') { + self::addRequiredEntry('*', 'CAA', $required_entries); + } elseif ($domain['wwwserveralias'] == '1') { + self::addRequiredEntry('www', 'CAA', $required_entries); + } } // additional required records for SPF and DKIM if activated @@ -287,7 +293,16 @@ class Dns // CAA if (array_key_exists("CAA", $required_entries)) { - $zonerecords[] = new DnsEntry('@', 'CAA', '0 issue "letsencrypt.org"'); + foreach ($required_entries as $type => $records) { + if ($type == 'CAA') { + foreach ($records as $record) { + $caa_entries = explode(PHP_EOL, $domain['caa']); + foreach ($caa_entries as $entry) { + $zonerecords[] = new DnsEntry($record, 'CAA', self::encloseTXTContent($entry)); + } + } + } + } } } diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index b3460fae..b2dde16b 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -215,17 +215,14 @@ return array( 'value' => array() ), 'caa' => array( - 'visible' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? true : false) : false), + 'visible' => $ssl_ipsandports != '' ? true : false, + 'style' => 'align-top', 'label' => $lng['admin']['caa']['title'], 'desc' => $lng['admin']['caa']['description'], - 'type' => 'checkbox', - 'values' => array( - array( - 'label' => $lng['panel']['yes'], - 'value' => '1' - ) - ), - 'value' => array() + 'type' => 'textarea', + 'value' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? '0 issue "letsencrypt.org"' : '') : ''), + 'cols' => 60, + 'rows' => 5 ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 7fe2fe54..5585a193 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -251,19 +251,14 @@ return array( ) ), 'caa' => array( - 'visible' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? true : false) : false), + 'visible' => $ssl_ipsandports != '' ? true : false, + 'style' => 'align-top', 'label' => $lng['admin']['caa']['title'], 'desc' => $lng['admin']['caa']['description'], - 'type' => 'checkbox', - 'values' => array( - array( - 'label' => $lng['panel']['yes'], - 'value' => '1' - ) - ), - 'value' => array( - $result['caa'] - ) + 'type' => 'textarea', + 'value' => $result['caa'], + 'cols' => 60, + 'rows' => 5 ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php index b620dba1..15f352d2 100644 --- a/lib/formfields/customer/domains/formfield.domains_add.php +++ b/lib/formfields/customer/domains/formfield.domains_add.php @@ -109,17 +109,14 @@ return array( 'value' => array() ), 'caa' => array( - 'visible' => \Froxlor\Settings::Get('system.leenabled') == '1' ? true : false, + 'visible' => $ssl_ipsandports != '' ? true : false, + 'style' => 'align-top', 'label' => $lng['customer']['caa']['title'], 'desc' => $lng['customer']['caa']['description'], - 'type' => 'checkbox', - 'values' => array( - array( - 'label' => $lng['panel']['yes'], - 'value' => '1' - ) - ), - 'value' => array() + 'type' => 'textarea', + 'value' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? '0 issue "letsencrypt.org"' : '') : ''), + 'cols' => 60, + 'rows' => 5 ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index c5315487..9a21d3e6 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -129,19 +129,14 @@ return array( ) ), 'caa' => array( - 'visible' => \Froxlor\Settings::Get('system.leenabled') == '1' ? true : false, + 'visible' => $ssl_ipsandports != '' ? true : false, + 'style' => 'align-top', 'label' => $lng['customer']['caa']['title'], 'desc' => $lng['customer']['caa']['description'], - 'type' => 'checkbox', - 'values' => array( - array( - 'label' => $lng['panel']['yes'], - 'value' => '1' - ) - ), - 'value' => array( - $result['caa'] - ) + 'type' => 'textarea', + 'value' => $result['caa'], + 'cols' => 60, + 'rows' => 5 ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], diff --git a/lng/english.lng.php b/lng/english.lng.php index 3ee60eeb..e88c4d13 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1849,10 +1849,10 @@ $lng['serversettings']['leenabled']['description'] = "If activated, customers ar $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['admin']['caa']['title'] = 'Use CAA DNS record'; -$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record. Currently it only supports Let\'s Encrypt. This feature is still in beta.'; -$lng['customer']['caa']['title'] = 'Use CAA DNS record'; -$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record. Currently it only supports Let\'s Encrypt. This feature is still in beta.'; +$lng['admin']['caa']['title'] = 'Use CAA DNS records'; +$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). An example for the use with Let\'s Encrypt would be:
0 issue "letsencrypt.org"
To enable Incident Reporting, you would need to add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, DNS server might not start again!'; +$lng['customer']['caa']['title'] = 'Use CAA DNS records'; +$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). An example for the use with Let\'s Encrypt would be:
0 issue "letsencrypt.org"
To enable Incident Reporting, you would need to add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, DNS server might not start again!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; diff --git a/lng/german.lng.php b/lng/german.lng.php index 37c3f08f..a838ce0a 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1501,10 +1501,10 @@ $lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, k $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['admin']['caa']['title'] = 'CAA DNS Eintrag erstellen'; -$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden. Im Moment wird nur Let\'s Encrypt unterstützt. Dieses Feature befindet sich noch im Test.'; -$lng['customer']['caa']['title'] = 'CAA DNS Eintrag erstellen'; -$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden. Im Moment wird nur Let\'s Encrypt unterstützt. Dieses Feature befindet sich noch im Test.'; +$lng['admin']['caa']['title'] = 'CAA DNS Einträge erstellen'; +$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Ein Beispiel für Let\'s Encrypt wäre:
0 issue "letsencrypt.org"
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der DNS-Server könnte nicht mehr starten!'; +$lng['customer']['caa']['title'] = 'CAA DNS Einträge erstellen'; +$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Ein Beispiel für Let\'s Encrypt wäre:
0 issue "letsencrypt.org"
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der DNS-Server könnte nicht mehr starten!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; From 57ac337ef7688fe52db083a31c1323b19486b2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 16:52:05 +0200 Subject: [PATCH 03/17] Add a few more commonly used RR types to DNS editor --- dns_editor.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dns_editor.php b/dns_editor.php index c1d28546..936193e0 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -108,11 +108,22 @@ if (! empty($dom_entries)) { $type_select_values = array( 'A', 'AAAA', - 'NS', + 'CAA', + 'CNAME', + 'DNAME', + 'DNSKEY', + 'DS', + 'LOC', 'MX', + 'NS', + 'NSEC', + 'NSEC3', + 'PTR', + 'RP', + 'RRSIG', 'SRV', + 'SSHFP', 'TXT', - 'CNAME' ); asort($type_select_values); foreach ($type_select_values as $_type) { From 5eef98fdfd0d3814b1796f1f72628d0b17cdab50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 18:10:01 +0200 Subject: [PATCH 04/17] Bump DB Version to 201907270 --- install/froxlor.sql | 2 +- lib/Froxlor/Froxlor.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/froxlor.sql b/install/froxlor.sql index f50c5c1f..169d7712 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -682,7 +682,7 @@ opcache.interned_strings_buffer'), ('panel', 'customer_hide_options', ''), ('panel', 'is_configured', '0'), ('panel', 'version', '0.10.0-rc2'), - ('panel', 'db_version', '201904250'); + ('panel', 'db_version', '201907270'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 53e32359..eff34ca5 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -10,7 +10,7 @@ final class Froxlor const VERSION = '0.10.0-rc2'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '201904250'; + const DBVERSION = '201907270'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; From b427212b00fd708b2969a6ed14fc410f69f422ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 18:11:42 +0200 Subject: [PATCH 05/17] Properly implement migrations for caa field in TABLE_DOMAIN_DNS using `showUpdateStep()` and `lastStepStatus()` --- install/updates/froxlor/0.10/update_0.10.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index fae59b55..a009fb54 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -266,6 +266,9 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc1')) { if (\Froxlor\Froxlor::isDatabaseVersion('201904250')) { + showUpdateStep("Adding field caa for domains"); Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `caa` text default NULL AFTER `letsencrypt`;"); + lastStepStatus(0); + \Froxlor\Froxlor::updateToDbVersion('201907270'); } \ No newline at end of file From 358ca61a2698a137aa64b48dba24d254a016b229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 18:47:47 +0200 Subject: [PATCH 06/17] Implement validators to prevent breaking DNS server when adding newly introduced RR types --- dns_editor.php | 6 --- lib/Froxlor/Api/Commands/DomainZones.php | 60 ++++++++++++++---------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/dns_editor.php b/dns_editor.php index 936193e0..77f121ef 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -111,16 +111,10 @@ $type_select_values = array( 'CAA', 'CNAME', 'DNAME', - 'DNSKEY', - 'DS', 'LOC', 'MX', 'NS', - 'NSEC', - 'NSEC3', - 'PTR', 'RP', - 'RRSIG', 'SRV', 'SSHFP', 'TXT', diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index ccdcad79..e717d7c7 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -138,6 +138,34 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour $errors[] = $this->lng['error']['dns_arec_noipv4']; } elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { $errors[] = $this->lng['error']['dns_aaaarec_noipv6']; + } elseif ($type == 'CAA' && ! empty($content)) { + // check that CAA content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + } elseif ($type == 'CNAME' || $type == 'DNAME') { + // check for trailing dot + if (substr($content, - 1) == '.') { + // remove it for checks + $content = substr($content, 0, - 1); + } else { + // add domain name + $content .= '.' . $domain; + } + if (! \Froxlor\Validate\Validate::validateDomain($content, true)) { + $errors[] = $this->lng['error']['dns_cname_invaliddom']; + } else { + // check whether there are RR-records for the same resource + foreach ($dom_entries as $existing_entries) { + if (($existing_entries['type'] == 'A' || $existing_entries['type'] == 'AAAA' || $existing_entries['type'] == 'MX' || $existing_entries['type'] == 'NS') && $existing_entries['record'] == $record) { + $errors[] = $this->lng['error']['dns_cname_nomorerr']; + break; + } + } + } + // append trailing dot (again) + $content .= '.'; + } elseif ($type == 'LOC' && ! empty($content)) { + // check that LOC content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($content); } elseif ($type == 'MX') { if ($prio === null || $prio < 0) { $errors[] = $this->lng['error']['dns_mx_prioempty']; @@ -161,28 +189,6 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } // append trailing dot (again) $content .= '.'; - } elseif ($type == 'CNAME') { - // check for trailing dot - if (substr($content, - 1) == '.') { - // remove it for checks - $content = substr($content, 0, - 1); - } else { - // add domain name - $content .= '.' . $domain; - } - if (! \Froxlor\Validate\Validate::validateDomain($content, true)) { - $errors[] = $this->lng['error']['dns_cname_invaliddom']; - } else { - // check whether there are RR-records for the same resource - foreach ($dom_entries as $existing_entries) { - if (($existing_entries['type'] == 'A' || $existing_entries['type'] == 'AAAA' || $existing_entries['type'] == 'MX' || $existing_entries['type'] == 'NS') && $existing_entries['record'] == $record) { - $errors[] = $this->lng['error']['dns_cname_nomorerr']; - break; - } - } - } - // append trailing dot (again) - $content .= '.'; } elseif ($type == 'NS') { // check for trailing dot if (substr($content, - 1) == '.') { @@ -194,8 +200,8 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } // append trailing dot (again) $content .= '.'; - } elseif ($type == 'TXT' && ! empty($content)) { - // check that TXT content is enclosed in " " + } elseif ($type == 'RP' && ! empty($content)) { + // check that RP content is enclosed in " " $content = \Froxlor\Dns\Dns::encloseTXTContent($content); } elseif ($type == 'SRV') { if ($prio === null || $prio < 0) { @@ -232,6 +238,12 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour if (substr($content, - 1) != '.') { $content .= '.'; } + } elseif ($type == 'SSHFP' && ! empty($content)) { + // check that SSHFP content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + } elseif ($type == 'TXT' && ! empty($content)) { + // check that TXT content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($content); } $new_entry = array( From 240178eba71d9e9389a874dc18b6bfc07e038a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 19:49:32 +0200 Subject: [PATCH 07/17] Implement global CAA settings --- actions/admin/settings/160.nameserver.php | 16 ++++++++++ install/froxlor.sql | 3 +- .../updates/froxlor/0.10/update_0.10.inc.php | 5 +-- lib/Froxlor/Dns/Dns.php | 31 ++++++++++++------- lng/english.lng.php | 6 ++-- lng/german.lng.php | 6 ++-- 6 files changed, 45 insertions(+), 22 deletions(-) diff --git a/actions/admin/settings/160.nameserver.php b/actions/admin/settings/160.nameserver.php index a7df3322..8c24f75f 100644 --- a/actions/admin/settings/160.nameserver.php +++ b/actions/admin/settings/160.nameserver.php @@ -107,6 +107,22 @@ return array( 'default' => false, 'save_method' => 'storeSettingField' ), + 'system_dns_createcaaentry' => array( + 'label' => $lng['serversettings']['caa_entry'], + 'settinggroup' => 'system', + 'varname' => 'dns_createcaaentry', + 'type' => 'bool', + 'default' => true, + 'save_method' => 'storeSettingField' + ), + 'caa.caa_entry' => array( + 'label' => $lng['serversettings']['caa_entry_custom'], + 'settinggroup' => 'caa', + 'varname' => 'caa_entry', + 'type' => 'text', + 'default' => '', + 'save_method' => 'storeSettingField' + ), 'system_defaultttl' => array( 'label' => $lng['serversettings']['defaultttl'], 'settinggroup' => 'system', diff --git a/install/froxlor.sql b/install/froxlor.sql index 169d7712..f3cf318c 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -256,7 +256,6 @@ CREATE TABLE `panel_domains` ( `mod_fcgid_maxrequests` int(4) default '-1', `ismainbutsubto` int(11) unsigned NOT NULL default '0', `letsencrypt` tinyint(1) NOT NULL default '0', - `caa` text default NULL, `hsts` varchar(10) NOT NULL default '0', `hsts_sub` tinyint(1) NOT NULL default '0', `hsts_preload` tinyint(1) NOT NULL default '0', @@ -376,6 +375,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('admin', 'show_news_feed', '0'), ('admin', 'show_version_login', '0'), ('admin', 'show_version_footer', '0'), + ('caa', 'caa_entry', ''), ('spf', 'use_spf', '0'), ('spf', 'spf_entry', '"v=spf1 a mx -all"'), ('dkim', 'dkim_algorithm', 'all'), @@ -562,6 +562,7 @@ opcache.interned_strings_buffer'), ('system', 'mod_fcgid_defaultini', '1'), ('system', 'ftpserver', 'proftpd'), ('system', 'dns_createmailentry', '0'), + ('system', 'dns_createcaaentry', '1'), ('system', 'froxlordirectlyviahostname', '0'), ('system', 'report_enable', '1'), ('system', 'report_webmax', '90'), diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index a009fb54..bac449ea 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -266,8 +266,9 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc1')) { if (\Froxlor\Froxlor::isDatabaseVersion('201904250')) { - showUpdateStep("Adding field caa for domains"); - Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `caa` text default NULL AFTER `letsencrypt`;"); + showUpdateStep("Adding new settings for CAA"); + Settings::AddNew('caa.caa_entry', '', true); + Settings::AddNew('system.dns_createcaaentry', 1, true); lastStepStatus(0); \Froxlor\Froxlor::updateToDbVersion('201907270'); diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index 0d754f21..bd0b4a78 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -131,15 +131,9 @@ class Dns } // additional required records for CAA if activated - if (!is_null($domain['caa'])) { + if (Settings::Get('system.dns_createcaaentry') && Settings::Get('system.use_ssl') == "1" && !empty($domain['p_ssl_ipandports'])) { // check for CAA content later - self::addRequiredEntry('@', 'CAA', $required_entries); - // additional required records by subdomain setting - if ($domain['iswildcarddomain'] == '1') { - self::addRequiredEntry('*', 'CAA', $required_entries); - } elseif ($domain['wwwserveralias'] == '1') { - self::addRequiredEntry('www', 'CAA', $required_entries); - } + self::addRequiredEntry('@CAA@', 'CAA', $required_entries); } // additional required records for SPF and DKIM if activated @@ -162,6 +156,10 @@ class Dns if (array_key_exists($entry['type'], $required_entries) && array_key_exists(md5($entry['record']), $required_entries[$entry['type']])) { unset($required_entries[$entry['type']][md5($entry['record'])]); } + if (Settings::Get('system.dns_createcaaentry') == '1' && $entry['type'] == 'CAA' && strtolower(substr($entry['content'], 0, 7)) == '"v=caa1') { + // unset special CAA required-entry + unset($required_entries[$entry['type']][md5("@CAA@")]); + } if (Settings::Get('spf.use_spf') == '1' && $entry['type'] == 'TXT' && $entry['record'] == '@' && strtolower(substr($entry['content'], 0, 7)) == '"v=spf1') { // unset special spf required-entry unset($required_entries[$entry['type']][md5("@SPF@")]); @@ -296,9 +294,20 @@ class Dns foreach ($required_entries as $type => $records) { if ($type == 'CAA') { foreach ($records as $record) { - $caa_entries = explode(PHP_EOL, $domain['caa']); - foreach ($caa_entries as $entry) { - $zonerecords[] = new DnsEntry($record, 'CAA', self::encloseTXTContent($entry)); + if ($record == '@CAA@') { + $caa_entries = explode(PHP_EOL, Settings::Get('caa.caa_entry')); + if ($domain['letsencrypt'] == 1) { + $le_entry = $domain['iswildcarddomain'] == '1' ? '0 issuewild "letsencrypt.org"' : '0 issue "letsencrypt.org"'; + array_push($caa_entries, $le_entry); + } + + foreach ($caa_entries as $entry) { + $zonerecords[] = new DnsEntry('@', 'CAA', self::encloseTXTContent($entry)); + // additional required records by subdomain setting + if ($domain['wwwserveralias'] == '1') { + $zonerecords[] = new DnsEntry('www', 'CAA', self::encloseTXTContent($entry)); + } + } } } } diff --git a/lng/english.lng.php b/lng/english.lng.php index e88c4d13..289cdaa7 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1849,10 +1849,8 @@ $lng['serversettings']['leenabled']['description'] = "If activated, customers ar $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['admin']['caa']['title'] = 'Use CAA DNS records'; -$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). An example for the use with Let\'s Encrypt would be:
0 issue "letsencrypt.org"
To enable Incident Reporting, you would need to add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, DNS server might not start again!'; -$lng['customer']['caa']['title'] = 'Use CAA DNS records'; -$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). An example for the use with Let\'s Encrypt would be:
0 issue "letsencrypt.org"
To enable Incident Reporting, you would need to add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, DNS server might not start again!'; +$lng['serversettings']['caa_entry'] = 'Generate CAA DNS records
Automatically generates CAA records for SSL-enabled domains that are using Let\'s Encrypt'; +$lng['serversettings']['caa_custom'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). If Let\'s Encrypt is enabled for this domain, this entry will always be added automatically and does not need to be added manually:
0 issue "letsencrypt.org" (If domain is a wildcard domain, issuewild will be used instead).
To enable Incident Reporting, you can add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, your CAA records might not work!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; diff --git a/lng/german.lng.php b/lng/german.lng.php index a838ce0a..f4773dad 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1501,10 +1501,8 @@ $lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, k $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['admin']['caa']['title'] = 'CAA DNS Einträge erstellen'; -$lng['admin']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Ein Beispiel für Let\'s Encrypt wäre:
0 issue "letsencrypt.org"
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der DNS-Server könnte nicht mehr starten!'; -$lng['customer']['caa']['title'] = 'CAA DNS Einträge erstellen'; -$lng['customer']['caa']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Ein Beispiel für Let\'s Encrypt wäre:
0 issue "letsencrypt.org"
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der DNS-Server könnte nicht mehr starten!'; +$lng['serversettings']['caa_entry']= 'CAA DNS Einträge generieren
Generiert CAA Einträge automatisch für alle Domains mit aktiviertem SSL und Let\'s Encrypt'; +$lng['serversettings']['caa_custom']= 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Wenn Let\'s Encrypt für eine Domain aktiviert wurde und die obige Option aktiviert wurde, wird immer automatisch dieser Eintrag angefügt und muss nicht selber angegeben werden:
0 issue "letsencrypt.org" (Wenn wildcard aktiviert ist, wird statdessen issuewild benutzt).
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Die CAA finalen Einträge könnten daher falsch sein!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; From be0470aec123ef652a1261ced99b175b794ff2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 19:49:56 +0200 Subject: [PATCH 08/17] Revert per-domain CAA settings --- lib/formfields/admin/domains/formfield.domains_add.php | 10 ---------- .../admin/domains/formfield.domains_edit.php | 10 ---------- .../customer/domains/formfield.domains_add.php | 10 ---------- .../customer/domains/formfield.domains_edit.php | 10 ---------- 4 files changed, 40 deletions(-) diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index b2dde16b..ddbb6266 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -214,16 +214,6 @@ return array( ), 'value' => array() ), - 'caa' => array( - 'visible' => $ssl_ipsandports != '' ? true : false, - 'style' => 'align-top', - 'label' => $lng['admin']['caa']['title'], - 'desc' => $lng['admin']['caa']['description'], - 'type' => 'textarea', - 'value' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? '0 issue "letsencrypt.org"' : '') : ''), - 'cols' => 60, - 'rows' => 5 - ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', 'label' => $lng['admin']['domain_http2']['title'], diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 5585a193..4c756ec1 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -250,16 +250,6 @@ return array( $result['letsencrypt'] ) ), - 'caa' => array( - 'visible' => $ssl_ipsandports != '' ? true : false, - 'style' => 'align-top', - 'label' => $lng['admin']['caa']['title'], - 'desc' => $lng['admin']['caa']['description'], - 'type' => 'textarea', - 'value' => $result['caa'], - 'cols' => 60, - 'rows' => 5 - ), 'http2' => array( 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', 'label' => $lng['admin']['domain_http2']['title'], diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php index 15f352d2..00d9fca6 100644 --- a/lib/formfields/customer/domains/formfield.domains_add.php +++ b/lib/formfields/customer/domains/formfield.domains_add.php @@ -108,16 +108,6 @@ return array( ), 'value' => array() ), - 'caa' => array( - 'visible' => $ssl_ipsandports != '' ? true : false, - 'style' => 'align-top', - 'label' => $lng['customer']['caa']['title'], - 'desc' => $lng['customer']['caa']['description'], - 'type' => 'textarea', - 'value' => (\Froxlor\Settings::Get('system.leenabled') == '1' ? ($ssl_ipsandports != '' ? '0 issue "letsencrypt.org"' : '') : ''), - 'cols' => 60, - 'rows' => 5 - ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index 9a21d3e6..56a28543 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -128,16 +128,6 @@ return array( $result['letsencrypt'] ) ), - 'caa' => array( - 'visible' => $ssl_ipsandports != '' ? true : false, - 'style' => 'align-top', - 'label' => $lng['customer']['caa']['title'], - 'desc' => $lng['customer']['caa']['description'], - 'type' => 'textarea', - 'value' => $result['caa'], - 'cols' => 60, - 'rows' => 5 - ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], From e67e2a85de7676857afa2a67d0a45e7743ff8014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Sun, 28 Jul 2019 20:05:55 +0200 Subject: [PATCH 09/17] Implement test for Domain Zone CAA record --- install/froxlor.sql | 4 ++-- tests/DomainZones/DomainZonesTest.php | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/install/froxlor.sql b/install/froxlor.sql index f3cf318c..51ffe079 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -375,7 +375,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('admin', 'show_news_feed', '0'), ('admin', 'show_version_login', '0'), ('admin', 'show_version_footer', '0'), - ('caa', 'caa_entry', ''), + ('caa', 'caa_entry', ''), ('spf', 'use_spf', '0'), ('spf', 'spf_entry', '"v=spf1 a mx -all"'), ('dkim', 'dkim_algorithm', 'all'), @@ -562,7 +562,7 @@ opcache.interned_strings_buffer'), ('system', 'mod_fcgid_defaultini', '1'), ('system', 'ftpserver', 'proftpd'), ('system', 'dns_createmailentry', '0'), - ('system', 'dns_createcaaentry', '1'), + ('system', 'dns_createcaaentry', '1'), ('system', 'froxlordirectlyviahostname', '0'), ('system', 'report_enable', '1'), ('system', 'report_webmax', '90'), diff --git a/tests/DomainZones/DomainZonesTest.php b/tests/DomainZones/DomainZonesTest.php index fef9ba2f..03fe78d0 100644 --- a/tests/DomainZones/DomainZonesTest.php +++ b/tests/DomainZones/DomainZonesTest.php @@ -277,6 +277,30 @@ class DomainZonesTest extends TestCase DomainZones::getLocal($admin_userdata, $data)->add(); } + public function testAdminDomainZonesAddCAA() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue "letsencrypt.org"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issue "letsencrypt.org"') * - 1) == '0 issue "letsencrypt.org"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org"', $entry); + } + public function testAdminDomainZonesAddCname() { global $admin_userdata; From a377c1e6c56e7a1bdc35696905167583f86440cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 07:39:11 +0200 Subject: [PATCH 10/17] Split l18n string into title and description --- lng/english.lng.php | 6 ++++-- lng/german.lng.php | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lng/english.lng.php b/lng/english.lng.php index 289cdaa7..4996b77e 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1849,8 +1849,10 @@ $lng['serversettings']['leenabled']['description'] = "If activated, customers ar $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['serversettings']['caa_entry'] = 'Generate CAA DNS records
Automatically generates CAA records for SSL-enabled domains that are using Let\'s Encrypt'; -$lng['serversettings']['caa_custom'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). If Let\'s Encrypt is enabled for this domain, this entry will always be added automatically and does not need to be added manually:
0 issue "letsencrypt.org" (If domain is a wildcard domain, issuewild will be used instead).
To enable Incident Reporting, you can add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, your CAA records might not work!'; +$lng['serversettings']['caa_entry']['title'] = 'Generate CAA DNS records'; +$lng['serversettings']['caa_entry']['description'] = 'Automatically generates CAA records for SSL-enabled domains that are using Let\'s Encrypt'; +$lng['serversettings']['caa_custom']['title'] = 'Additional CAA DNS records'; +$lng['serversettings']['caa_custom']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.
The content of this field will be included into the DNS zone directly (each line results in a CAA record). If Let\'s Encrypt is enabled for this domain, this entry will always be added automatically and does not need to be added manually:
0 issue "letsencrypt.org" (If domain is a wildcard domain, issuewild will be used instead).
To enable Incident Reporting, you can add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"
Attention: The code won\'t be checked for any errors. If it contains errors, your CAA records might not work!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; diff --git a/lng/german.lng.php b/lng/german.lng.php index f4773dad..eb861056 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1501,8 +1501,10 @@ $lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, k $lng['domains']['ssl_redirect_temporarilydisabled'] = "
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."; // Added for CAA record support -$lng['serversettings']['caa_entry']= 'CAA DNS Einträge generieren
Generiert CAA Einträge automatisch für alle Domains mit aktiviertem SSL und Let\'s Encrypt'; -$lng['serversettings']['caa_custom']= 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Wenn Let\'s Encrypt für eine Domain aktiviert wurde und die obige Option aktiviert wurde, wird immer automatisch dieser Eintrag angefügt und muss nicht selber angegeben werden:
0 issue "letsencrypt.org" (Wenn wildcard aktiviert ist, wird statdessen issuewild benutzt).
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Die CAA finalen Einträge könnten daher falsch sein!'; +$lng['serversettings']['caa_entry']['title'] = 'CAA DNS Einträge generieren'; +$lng['serversettings']['caa_entry']['description'] = 'Generiert CAA Einträge automatisch für alle Domains mit aktiviertem SSL und Let\'s Encrypt'; +$lng['serversettings']['caa_custom']['title'] = 'Zusätzliche CAA DNS Einträge'; +$lng['serversettings']['caa_custom']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen, ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.
Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Wenn Let\'s Encrypt für eine Domain aktiviert wurde und die obige Option aktiviert wurde, wird immer automatisch dieser Eintrag angefügt und muss nicht selber angegeben werden:
0 issue "letsencrypt.org" (Wenn wildcard aktiviert ist, wird statdessen issuewild benutzt).
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"
ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Die CAA finalen Einträge könnten daher falsch sein!'; // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; From 78ef2a4e236bc46fa947d10a1a92c58e02cf7c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 07:41:09 +0200 Subject: [PATCH 11/17] Fix serversettings field --- actions/admin/settings/160.nameserver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/admin/settings/160.nameserver.php b/actions/admin/settings/160.nameserver.php index 8c24f75f..67260bfa 100644 --- a/actions/admin/settings/160.nameserver.php +++ b/actions/admin/settings/160.nameserver.php @@ -115,7 +115,7 @@ return array( 'default' => true, 'save_method' => 'storeSettingField' ), - 'caa.caa_entry' => array( + 'caa_caa_entry' => array( 'label' => $lng['serversettings']['caa_entry_custom'], 'settinggroup' => 'caa', 'varname' => 'caa_entry', From bfb3fb0a92bb02308797661eb549fc34d3711122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 11:36:34 +0200 Subject: [PATCH 12/17] Add Regex to check for invalid CAA entry --- lib/Froxlor/Api/Commands/DomainZones.php | 11 +++++++++-- lng/english.lng.php | 1 + lng/german.lng.php | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index e717d7c7..9e233fec 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -139,8 +139,15 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { $errors[] = $this->lng['error']['dns_aaaarec_noipv6']; } elseif ($type == 'CAA' && ! empty($content)) { - // check that CAA content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + $re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; + preg_match($re, $content, $matches); + + if (empty($matches)) { + $errors[] = $this->lng['error']['dns_content_invalid']; + } else { + // check that CAA content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($matches[0]); + } } elseif ($type == 'CNAME' || $type == 'DNAME') { // check for trailing dot if (substr($content, - 1) == '.') { diff --git a/lng/english.lng.php b/lng/english.lng.php index 4996b77e..aad8a566 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -1892,6 +1892,7 @@ $lng['tasks']['backup_customerfiles'] = 'Backup job for customer %loginname%'; $lng['error']['dns_domain_nodns'] = 'DNS is not enabled for this domain'; $lng['error']['dns_content_empty'] = 'No content given'; +$lng['error']['dns_content_invalid'] = 'DNS content invalid'; $lng['error']['dns_arec_noipv4'] = 'No valid IP address for A-record given'; $lng['error']['dns_aaaarec_noipv6'] = 'No valid IP address for AAAA-record given'; $lng['error']['dns_mx_prioempty'] = 'Invalid MX priority given'; diff --git a/lng/german.lng.php b/lng/german.lng.php index eb861056..9c335afe 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -1543,6 +1543,7 @@ $lng['tasks']['backup_customerfiles'] = 'Datensicherung für Kunde %loginname%'; $lng['error']['dns_domain_nodns'] = 'DNS ist für diese Domain nicht aktiviert'; $lng['error']['dns_content_empty'] = 'Keinen Inhalt angegeben'; +$lng['error']['dns_content_invalid'] = 'DNS Eintrag ungültig'; $lng['error']['dns_arec_noipv4'] = 'Keine gültige IP-Adresse für A-Eintrag angegeben'; $lng['error']['dns_aaaarec_noipv6'] = 'Keine gültige IP-Adresse für AAAA-Eintrag angegeben'; $lng['error']['dns_mx_prioempty'] = 'Ungültige MX Priorität angegeben'; From 95d47eb6c9ecc9a28cff3f02ef03d29fe3aae8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 11:53:00 +0200 Subject: [PATCH 13/17] Add unit tests for CAA entry validation --- tests/DomainZones/DomainZonesTest.php | 320 +++++++++++++++++++++++++- 1 file changed, 319 insertions(+), 1 deletion(-) diff --git a/tests/DomainZones/DomainZonesTest.php b/tests/DomainZones/DomainZonesTest.php index 03fe78d0..42a3b493 100644 --- a/tests/DomainZones/DomainZonesTest.php +++ b/tests/DomainZones/DomainZonesTest.php @@ -277,7 +277,7 @@ class DomainZonesTest extends TestCase DomainZones::getLocal($admin_userdata, $data)->add(); } - public function testAdminDomainZonesAddCAA() + public function testAdminDomainZonesAddCAAIssue() { global $admin_userdata; @@ -301,6 +301,324 @@ class DomainZonesTest extends TestCase $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org"', $entry); } + public function testAdminDomainZonesAddCAAIssueWithParameters() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue "letsencrypt.org; account=230123"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issue "letsencrypt.org; account=230123"') * - 1) == '0 issue "letsencrypt.org; account=230123"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org; account=230123"', $entry); + } + + public function testAdminDomainZonesAddCAAIssueWithTwoParameters() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue "letsencrypt.org; account=230123 policy=ev"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issue "letsencrypt.org; account=230123 policy=ev"') * - 1) == '0 issue "letsencrypt.org; account=230123 policy=ev"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org; account=230123 policy=ev"', $entry); + } + + public function testAdminDomainZonesAddCAAInvalidIssueValue() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue ""letsencrypt.org"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAInvalidIssueDomain() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue "no-valid-domain"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAInvalidIssueTld() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issue "no-valid-domai.n"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAIssueWild() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild "letsencrypt.org"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issuewild "letsencrypt.org"') * - 1) == '0 issuewild "letsencrypt.org"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org"', $entry); + } + + public function testAdminDomainZonesAddCAAIssueWildWithParameters() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild "letsencrypt.org; account=230123"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issuewild "letsencrypt.org; account=230123"') * - 1) == '0 issuewild "letsencrypt.org; account=230123"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org; account=230123"', $entry); + } + + public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild "letsencrypt.org; account=230123 policy=ev"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 issuewild "letsencrypt.org; account=230123 policy=ev"') * - 1) == '0 issuewild "letsencrypt.org; account=230123 policy=ev"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org; account=230123 policy=ev"', $entry); + } + + public function testAdminDomainZonesAddCAAInvalidIssueWildValue() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild ""letsencrypt.org"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAInvalidIssueWildDomain() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild "no-valid-domain"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAInvalidIssueWildTld() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 issuewild "no-valid-domai.n"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAIodefMail() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "mailto:security@example.com"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 iodef "mailto:security@example.com"') * - 1) == '0 iodef "mailto:security@example.com"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 iodef "mailto:security@example.com"', $entry); + } + + public function testAdminDomainZonesAddCAAIodefMailInvalid() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "mailtosecurity@example.com"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAIodefHttp() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "http://iodef.example.com/"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 iodef "http://iodef.example.com/"') * - 1) == '0 iodef "http://iodef.example.com/"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 iodef "http://iodef.example.com/"', $entry); + } + + public function testAdminDomainZonesAddCAAIodefHttpInvalid() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "http:/iodef.example.com/"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + + public function testAdminDomainZonesAddCAAIodefHttps() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "https://iodef.example.com/"' + ]; + $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertTrue(count($result) > 1); + $found = false; + foreach ($result as $entry) { + if (substr($entry, strlen('0 iodef "https://iodef.example.com/"') * - 1) == '0 iodef "https://iodef.example.com/"') { + $found = true; + break; + } + } + $this->assertTrue($found); + $this->assertEquals('@ 18000 IN CAA 0 iodef "https://iodef.example.com/"', $entry); + } + + public function testAdminDomainZonesAddCAAIodefHttpsInvalid() + { + global $admin_userdata; + + $data = [ + 'domainname' => 'test2.local', + 'record' => '@', + 'type' => 'CAA', + 'content' => '0 iodef "https:/iodef.example.com/"' + ]; + $this->expectExceptionMessage("DNS content invalid"); + DomainZones::getLocal($admin_userdata, $data)->add(); + } + public function testAdminDomainZonesAddCname() { global $admin_userdata; From 16ccc273a9a112a49168305f347c301cf85a348e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 14:27:44 +0200 Subject: [PATCH 14/17] Don't actually enclose CAA records in brackets --- lib/Froxlor/Api/Commands/DomainZones.php | 12 ++++-------- lib/Froxlor/Dns/Dns.php | 4 ++-- lib/userdata.inc.php.bak | 10 ++++++++++ 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 lib/userdata.inc.php.bak diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index 9e233fec..88b4eb80 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -145,8 +145,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour if (empty($matches)) { $errors[] = $this->lng['error']['dns_content_invalid']; } else { - // check that CAA content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($matches[0]); + $content = $matches[0]; } } elseif ($type == 'CNAME' || $type == 'DNAME') { // check for trailing dot @@ -171,8 +170,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour // append trailing dot (again) $content .= '.'; } elseif ($type == 'LOC' && ! empty($content)) { - // check that LOC content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + $content = $content; } elseif ($type == 'MX') { if ($prio === null || $prio < 0) { $errors[] = $this->lng['error']['dns_mx_prioempty']; @@ -208,8 +206,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour // append trailing dot (again) $content .= '.'; } elseif ($type == 'RP' && ! empty($content)) { - // check that RP content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + $content = $content; } elseif ($type == 'SRV') { if ($prio === null || $prio < 0) { $errors[] = $this->lng['error']['dns_srv_prioempty']; @@ -246,8 +243,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour $content .= '.'; } } elseif ($type == 'SSHFP' && ! empty($content)) { - // check that SSHFP content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + $content = $content; } elseif ($type == 'TXT' && ! empty($content)) { // check that TXT content is enclosed in " " $content = \Froxlor\Dns\Dns::encloseTXTContent($content); diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index bd0b4a78..2bf9c371 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -302,10 +302,10 @@ class Dns } foreach ($caa_entries as $entry) { - $zonerecords[] = new DnsEntry('@', 'CAA', self::encloseTXTContent($entry)); + $zonerecords[] = new DnsEntry('@', 'CAA', $entry); // additional required records by subdomain setting if ($domain['wwwserveralias'] == '1') { - $zonerecords[] = new DnsEntry('www', 'CAA', self::encloseTXTContent($entry)); + $zonerecords[] = new DnsEntry('www', 'CAA', $entry); } } } diff --git a/lib/userdata.inc.php.bak b/lib/userdata.inc.php.bak new file mode 100644 index 00000000..4f1b32db --- /dev/null +++ b/lib/userdata.inc.php.bak @@ -0,0 +1,10 @@ + Date: Mon, 29 Jul 2019 14:30:39 +0200 Subject: [PATCH 15/17] Simplify unit tests for CAA entry validation --- tests/DomainZones/DomainZonesTest.php | 88 ++++++++++++++++----------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/tests/DomainZones/DomainZonesTest.php b/tests/DomainZones/DomainZonesTest.php index 42a3b493..e082fd22 100644 --- a/tests/DomainZones/DomainZonesTest.php +++ b/tests/DomainZones/DomainZonesTest.php @@ -281,18 +281,19 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issue "letsencrypt.org"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue "letsencrypt.org"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issue "letsencrypt.org"') * - 1) == '0 issue "letsencrypt.org"') { + if (substr($entry, -strlen($content)) == $content) { $found = true; break; } @@ -305,59 +306,62 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issue "letsencrypt.org; account=230123"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue "letsencrypt.org; account=230123"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issue "letsencrypt.org; account=230123"') * - 1) == '0 issue "letsencrypt.org; account=230123"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org; account=230123"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIssueWithTwoParameters() { global $admin_userdata; + $content = '0 issue "letsencrypt.org; account=230123 policy=ev"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue "letsencrypt.org; account=230123 policy=ev"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issue "letsencrypt.org; account=230123 policy=ev"') * - 1) == '0 issue "letsencrypt.org; account=230123 policy=ev"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 issue "letsencrypt.org; account=230123 policy=ev"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAInvalidIssueValue() { global $admin_userdata; + $content = '0 issue ""letsencrypt.org"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue ""letsencrypt.org"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -367,11 +371,12 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issue "no-valid-domain"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue "no-valid-domain"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -381,11 +386,12 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issue "no-valid-domai.n"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issue "no-valid-domai.n"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -395,83 +401,87 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issue "letsencrypt.org"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild "letsencrypt.org"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issuewild "letsencrypt.org"') * - 1) == '0 issuewild "letsencrypt.org"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIssueWildWithParameters() { global $admin_userdata; + $content = '0 issuewild "letsencrypt.org; account=230123"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild "letsencrypt.org; account=230123"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issuewild "letsencrypt.org; account=230123"') * - 1) == '0 issuewild "letsencrypt.org; account=230123"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org; account=230123"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters() { global $admin_userdata; + $content = '0 issuewild "letsencrypt.org; account=230123 policy=ev"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild "letsencrypt.org; account=230123 policy=ev"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 issuewild "letsencrypt.org; account=230123 policy=ev"') * - 1) == '0 issuewild "letsencrypt.org; account=230123 policy=ev"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 issuewild "letsencrypt.org; account=230123 policy=ev"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAInvalidIssueWildValue() { global $admin_userdata; + $content = '0 issuewild ""letsencrypt.org"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild ""letsencrypt.org"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -481,11 +491,12 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issuewild "no-valid-domain"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild "no-valid-domain"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -495,11 +506,12 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 issuewild "no-valid-domai.n"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 issuewild "no-valid-domai.n"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -509,35 +521,37 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 iodef "mailto:security@example.com"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "mailto:security@example.com"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 iodef "mailto:security@example.com"') * - 1) == '0 iodef "mailto:security@example.com"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 iodef "mailto:security@example.com"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIodefMailInvalid() { global $admin_userdata; + $content = '0 iodef "mailtosecurity@example.com"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "mailtosecurity@example.com"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -547,35 +561,37 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 iodef "http://iodef.example.com/"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "http://iodef.example.com/"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 iodef "http://iodef.example.com/"') * - 1) == '0 iodef "http://iodef.example.com/"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 iodef "http://iodef.example.com/"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIodefHttpInvalid() { global $admin_userdata; + $content = '0 iodef "http:/iodef.example.com/"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "http:/iodef.example.com/"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); @@ -585,35 +601,37 @@ class DomainZonesTest extends TestCase { global $admin_userdata; + $content = '0 iodef "https://iodef.example.com/"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "https://iodef.example.com/"' + 'content' => $content, ]; $json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $result = json_decode($json_result, true)['data']; $this->assertTrue(count($result) > 1); $found = false; foreach ($result as $entry) { - if (substr($entry, strlen('0 iodef "https://iodef.example.com/"') * - 1) == '0 iodef "https://iodef.example.com/"') { + if (substr($entry, strlen($content) * - 1) == $content) { $found = true; break; } } $this->assertTrue($found); - $this->assertEquals('@ 18000 IN CAA 0 iodef "https://iodef.example.com/"', $entry); + $this->assertEquals('@ 18000 IN CAA '.$content, $entry); } public function testAdminDomainZonesAddCAAIodefHttpsInvalid() { global $admin_userdata; + $content = '0 iodef "https:/iodef.example.com/"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', 'type' => 'CAA', - 'content' => '0 iodef "https:/iodef.example.com/"' + 'content' => $content, ]; $this->expectExceptionMessage("DNS content invalid"); DomainZones::getLocal($admin_userdata, $data)->add(); From 84d80d695a6018fdf050640038ca6f63f81b00e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 15:02:13 +0200 Subject: [PATCH 16/17] Add Url and Domain validation for CAA records using native Froxlor function --- lib/Froxlor/Api/Commands/DomainZones.php | 4 ++++ tests/DomainZones/DomainZonesTest.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index 88b4eb80..276dc571 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -144,6 +144,10 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour if (empty($matches)) { $errors[] = $this->lng['error']['dns_content_invalid']; + } elseif (($matches['type'] == 'issue' || $matches['type'] == 'issuewild') && !\Froxlor\Validate\Validate::validateDomain($matches['domain'])) { + $errors[] = $this->lng['error']['dns_content_invalid']; + } elseif ($matches['type'] == 'iodef' && !\Froxlor\Validate\Validate::validateUrl($matches['url'])) { + $errors[] = $this->lng['error']['dns_content_invalid']; } else { $content = $matches[0]; } diff --git a/tests/DomainZones/DomainZonesTest.php b/tests/DomainZones/DomainZonesTest.php index e082fd22..c0bd3143 100644 --- a/tests/DomainZones/DomainZonesTest.php +++ b/tests/DomainZones/DomainZonesTest.php @@ -401,7 +401,7 @@ class DomainZonesTest extends TestCase { global $admin_userdata; - $content = '0 issue "letsencrypt.org"'; + $content = '0 issuewild "letsencrypt.org"'; $data = [ 'domainname' => 'test2.local', 'record' => '@', From dd488106afd334734823824e0429b2d0b9f6ee81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Kolly?= Date: Mon, 29 Jul 2019 16:09:11 +0200 Subject: [PATCH 17/17] Remove lib/userdata.inc.php.bak --- .gitignore | 1 + lib/userdata.inc.php.bak | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 lib/userdata.inc.php.bak diff --git a/.gitignore b/.gitignore index 8c981d1d..3d547882 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ install/update.log templates/* lib/userdata.inc.php +lib/userdata.inc.php.bak logs/* !logs/index.html .buildpath diff --git a/lib/userdata.inc.php.bak b/lib/userdata.inc.php.bak deleted file mode 100644 index 4f1b32db..00000000 --- a/lib/userdata.inc.php.bak +++ /dev/null @@ -1,10 +0,0 @@ -