Skip to content

Commit d738734

Browse files
committed
Add noreply shape check #36
1 parent 9f4c21e commit d738734

File tree

5 files changed

+125
-2
lines changed

5 files changed

+125
-2
lines changed

classes/check/dnsnoreply.php

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
/**
17+
* DNS Email Noreply check.
18+
*
19+
* @package tool_emailutils
20+
* @author Benjamin Walker <[email protected]>
21+
* @copyright Catalyst IT 2024
22+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23+
*
24+
*/
25+
26+
namespace tool_emailutils\check;
27+
use core\check\check;
28+
use core\check\result;
29+
use tool_emailutils\dns_util;
30+
31+
/**
32+
* DNS Email Noreply check.
33+
*
34+
* @package tool_emailutils
35+
* @author Benjamin Walker <[email protected]>
36+
* @copyright Catalyst IT 2024
37+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38+
*/
39+
class dnsnoreply extends check {
40+
41+
/**
42+
* A link to a place to action this
43+
*
44+
* @return \action_link|null
45+
*/
46+
public function get_action_link(): ?\action_link {
47+
return new \action_link(
48+
new \moodle_url('/admin/settings.php?section=outgoingmailconfig'),
49+
get_string('outgoingmailconfig', 'core_admin'));
50+
}
51+
52+
/**
53+
* Get Result.
54+
*
55+
* @return result
56+
*/
57+
public function get_result() : result {
58+
global $DB, $CFG;
59+
60+
$url = new \moodle_url($CFG->wwwroot);
61+
$domain = $url->get_host();
62+
63+
$details = '';
64+
$status = result::INFO;
65+
$summary = '';
66+
67+
$dns = new dns_util();
68+
69+
$noreply = $dns->get_noreply();
70+
$details .= "<p>No reply email: <code>$noreply</code></p>";
71+
72+
$noreplydomain = $dns->get_noreply_domain();
73+
$details .= "<p>No reply domain: <code>$noreplydomain</code></p>";
74+
75+
$details .= "<p>LMS domain: <code>$domain</code></p>";
76+
77+
$primarydomain = $dns->get_primary_domain($domain);
78+
79+
if ($noreplydomain == $domain) {
80+
$status = result::OK;
81+
$summary = "LMS is same as noreply domain";
82+
} else if (str_contains($domain, '.' . $noreplydomain)) {
83+
$status = result::OK;
84+
$summary = "LMS is a subdomain of noreply domain";
85+
} else if (str_contains($noreplydomain, '.' . $primarydomain)) {
86+
$summary = "LMS and noreply domain have a shared domain";
87+
} else {
88+
$summary = "LMS and noreply domain have nothing in common";
89+
}
90+
91+
return new result($status, $summary, $details);
92+
}
93+
}

classes/dns_util.php

+28
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,34 @@ public function get_noreply_domain() {
5858
return $noreplydomain;
5959
}
6060

61+
/**
62+
* Attempts to extract the primary domain from a domain
63+
*
64+
* This may not always be clear, if there is any confusion return the full domain.
65+
*
66+
* @param string $domain
67+
* @return string primary domain
68+
*/
69+
public function get_primary_domain($domain) {
70+
// This pattern works for the majority of cases, but can't be relied on for 100% accuracy.
71+
// It can include subdomains if the main domain is 2 chars or less and there is no ccTLD.
72+
$pattern = '/[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6}$/i';
73+
return (preg_match($pattern, $domain, $matches) === 1) ? $matches[0] : $domain;
74+
}
75+
76+
/**
77+
* Attempts to extract the subdomains from a domain
78+
*
79+
* This may not always be clear, if there is any confusion return known subdomains or a blank string.
80+
*
81+
* @param string $domain
82+
* @return string subdomains
83+
*/
84+
public function get_subdomains($domain) {
85+
$primarydomain = $this->get_primary_domain($domain);
86+
return rtrim(strstr($domain, $primarydomain, true), '.');
87+
}
88+
6189
/**
6290
* Get spf txt record contents
6391
* @return string txt record

lang/en/tool_emailutils.php

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
</ol>
4848
';
4949
$string['checkdnsmx'] = 'DNS Email MX check';
50+
$string['checkdnsnoreply'] = 'DNS Email noreply shape check';
5051
$string['dnssettings'] = 'SPF / DKIM / DMARC DNS settings';
5152
$string['dnsspfinclude'] = 'SPF include';
5253
$string['dnsspfinclude_help'] = '<p>This is an SPF include domain which is expected to be present in the record. For example if this was set to <code>spf.acme.org</code> then the SPF security check would pass if the SPF record was <code>v=spf1 include:spf.acme.org -all</code>.</p>

lib.php

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ function tool_emailutils_security_checks() {
4646
new \tool_emailutils\check\dnsdkim(),
4747
new \tool_emailutils\check\dnsdmarc(),
4848
new \tool_emailutils\check\dnsmx(),
49+
new \tool_emailutils\check\dnsnoreply(),
4950
new \tool_emailutils\check\dnspostmastertools(),
5051
];
5152
}

version.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
defined('MOODLE_INTERNAL') || die();
2727

28-
$plugin->version = 2024011501;
29-
$plugin->release = 2024011501;
28+
$plugin->version = 2024011502;
29+
$plugin->release = 2024011502;
3030
$plugin->requires = 2020061500;
3131
$plugin->component = 'tool_emailutils';
3232
$plugin->dependencies = [

0 commit comments

Comments
 (0)