diff options
Diffstat (limited to 'modules')
8 files changed, 500 insertions, 0 deletions
diff --git a/modules/private/environment.nix b/modules/private/environment.nix index f7994a1..5fbd023 100644 --- a/modules/private/environment.nix +++ b/modules/private/environment.nix | |||
@@ -820,6 +820,14 @@ in | |||
820 | }; | 820 | }; |
821 | }; | 821 | }; |
822 | }; | 822 | }; |
823 | dmarc_reports = mkOption { | ||
824 | description = "DMARC reports configuration"; | ||
825 | type = submodule { | ||
826 | options = { | ||
827 | mysql = mkMysqlOptions "DMARC" {}; | ||
828 | }; | ||
829 | }; | ||
830 | }; | ||
823 | etherpad-lite = mkOption { | 831 | etherpad-lite = mkOption { |
824 | description = "Etherpad configuration"; | 832 | description = "Etherpad configuration"; |
825 | type = submodule { | 833 | type = submodule { |
diff --git a/modules/private/websites/tools/tools/default.nix b/modules/private/websites/tools/tools/default.nix index 0cb7a10..a5e7f2e 100644 --- a/modules/private/websites/tools/tools/default.nix +++ b/modules/private/websites/tools/tools/default.nix | |||
@@ -47,6 +47,9 @@ let | |||
47 | webhooks = pkgs.callPackage ./webhooks.nix { | 47 | webhooks = pkgs.callPackage ./webhooks.nix { |
48 | env = config.myEnv.tools.webhooks; | 48 | env = config.myEnv.tools.webhooks; |
49 | }; | 49 | }; |
50 | dmarc-reports = pkgs.callPackage ./dmarc_reports.nix { | ||
51 | env = config.myEnv.tools.dmarc_reports; | ||
52 | }; | ||
50 | 53 | ||
51 | landing = pkgs.callPackage ./landing.nix {}; | 54 | landing = pkgs.callPackage ./landing.nix {}; |
52 | 55 | ||
@@ -65,6 +68,7 @@ in { | |||
65 | ++ ttrss.keys | 68 | ++ ttrss.keys |
66 | ++ wallabag.keys | 69 | ++ wallabag.keys |
67 | ++ yourls.keys | 70 | ++ yourls.keys |
71 | ++ dmarc-reports.keys | ||
68 | ++ webhooks.keys; | 72 | ++ webhooks.keys; |
69 | 73 | ||
70 | services.duplyBackup.profiles = { | 74 | services.duplyBackup.profiles = { |
@@ -88,6 +92,7 @@ in { | |||
88 | ++ rompr.apache.modules | 92 | ++ rompr.apache.modules |
89 | ++ shaarli.apache.modules | 93 | ++ shaarli.apache.modules |
90 | ++ dokuwiki.apache.modules | 94 | ++ dokuwiki.apache.modules |
95 | ++ dmarc-reports.apache.modules | ||
91 | ++ phpbb.apache.modules | 96 | ++ phpbb.apache.modules |
92 | ++ ldap.apache.modules | 97 | ++ ldap.apache.modules |
93 | ++ kanboard.apache.modules; | 98 | ++ kanboard.apache.modules; |
@@ -147,6 +152,7 @@ in { | |||
147 | (kanboard.apache.vhostConf pcfg.kanboard.socket) | 152 | (kanboard.apache.vhostConf pcfg.kanboard.socket) |
148 | (grocy.apache.vhostConf pcfg.grocy.socket) | 153 | (grocy.apache.vhostConf pcfg.grocy.socket) |
149 | (phpbb.apache.vhostConf pcfg.phpbb.socket) | 154 | (phpbb.apache.vhostConf pcfg.phpbb.socket) |
155 | (dmarc-reports.apache.vhostConf pcfg.dmarc-reports.socket) | ||
150 | '' | 156 | '' |
151 | Alias /paste /var/lib/fiche | 157 | Alias /paste /var/lib/fiche |
152 | <Directory "/var/lib/fiche"> | 158 | <Directory "/var/lib/fiche"> |
@@ -342,6 +348,15 @@ in { | |||
342 | group = "wwwrun"; | 348 | group = "wwwrun"; |
343 | settings = shaarli.phpFpm.pool; | 349 | settings = shaarli.phpFpm.pool; |
344 | }; | 350 | }; |
351 | dmarc-reports = { | ||
352 | user = "wwwrun"; | ||
353 | group = "wwwrun"; | ||
354 | settings = dmarc-reports.phpFpm.pool; | ||
355 | phpEnv = dmarc-reports.phpFpm.phpEnv; | ||
356 | phpOptions = config.services.phpfpm.phpOptions + '' | ||
357 | extension=${pkgs.php}/lib/php/extensions/mysqli.so | ||
358 | ''; | ||
359 | }; | ||
345 | dokuwiki = { | 360 | dokuwiki = { |
346 | user = "wwwrun"; | 361 | user = "wwwrun"; |
347 | group = "wwwrun"; | 362 | group = "wwwrun"; |
@@ -386,6 +401,7 @@ in { | |||
386 | 401 | ||
387 | services.websites.webappDirs = { | 402 | services.websites.webappDirs = { |
388 | _adminer = adminer.webRoot; | 403 | _adminer = adminer.webRoot; |
404 | "${dmarc-reports.apache.webappName}" = dmarc-reports.webRoot; | ||
389 | "${dokuwiki.apache.webappName}" = dokuwiki.webRoot; | 405 | "${dokuwiki.apache.webappName}" = dokuwiki.webRoot; |
390 | "${phpbb.apache.webappName}" = phpbb.webRoot; | 406 | "${phpbb.apache.webappName}" = phpbb.webRoot; |
391 | "${ldap.apache.webappName}" = "${ldap.webRoot}/htdocs"; | 407 | "${ldap.apache.webappName}" = "${ldap.webRoot}/htdocs"; |
diff --git a/modules/private/websites/tools/tools/dmarc_reports.nix b/modules/private/websites/tools/tools/dmarc_reports.nix new file mode 100644 index 0000000..2e44526 --- /dev/null +++ b/modules/private/websites/tools/tools/dmarc_reports.nix | |||
@@ -0,0 +1,56 @@ | |||
1 | { env }: | ||
2 | rec { | ||
3 | keys = [{ | ||
4 | dest = "webapps/tools-dmarc-reports.php"; | ||
5 | user = "wwwrun"; | ||
6 | group = "wwwrun"; | ||
7 | permissions = "0400"; | ||
8 | text = '' | ||
9 | <?php | ||
10 | $dbhost = "${env.mysql.host}"; | ||
11 | $dbname = "${env.mysql.database}"; | ||
12 | $dbuser = "${env.mysql.user}"; | ||
13 | $dbpass = "${env.mysql.password}"; | ||
14 | $dbport = "${env.mysql.port}"; | ||
15 | ?> | ||
16 | ''; | ||
17 | }]; | ||
18 | webRoot = ./dmarc_reports; | ||
19 | apache = rec { | ||
20 | user = "wwwrun"; | ||
21 | group = "wwwrun"; | ||
22 | modules = [ "proxy_fcgi" ]; | ||
23 | webappName = "tools_dmarc_reports"; | ||
24 | root = "/run/current-system/webapps/${webappName}"; | ||
25 | vhostConf = socket: '' | ||
26 | Alias /dmarc-reports "${root}" | ||
27 | <Directory "${root}"> | ||
28 | DirectoryIndex index.html | ||
29 | <FilesMatch "\.php$"> | ||
30 | SetHandler "proxy:unix:${socket}|fcgi://localhost" | ||
31 | </FilesMatch> | ||
32 | |||
33 | AllowOverride None | ||
34 | Options +FollowSymlinks | ||
35 | Require all granted | ||
36 | </Directory> | ||
37 | ''; | ||
38 | }; | ||
39 | phpFpm = rec { | ||
40 | basedir = builtins.concatStringsSep ":" | ||
41 | [ webRoot "/var/secrets/webapps/tools-dmarc-reports.php" ]; | ||
42 | pool = { | ||
43 | "listen.owner" = apache.user; | ||
44 | "listen.group" = apache.group; | ||
45 | "pm" = "ondemand"; | ||
46 | "pm.max_children" = "60"; | ||
47 | "pm.process_idle_timeout" = "60"; | ||
48 | |||
49 | # Needed to avoid clashes in browser cookies (same domain) | ||
50 | "php_admin_value[open_basedir]" = "${basedir}:/tmp"; | ||
51 | }; | ||
52 | phpEnv = { | ||
53 | SECRETS_FILE = "/var/secrets/webapps/tools-dmarc-reports.php"; | ||
54 | }; | ||
55 | }; | ||
56 | } | ||
diff --git a/modules/private/websites/tools/tools/dmarc_reports/api.php b/modules/private/websites/tools/tools/dmarc_reports/api.php new file mode 100644 index 0000000..9b7f0c0 --- /dev/null +++ b/modules/private/websites/tools/tools/dmarc_reports/api.php | |||
@@ -0,0 +1,87 @@ | |||
1 | <?php | ||
2 | |||
3 | require(getenv("SECRETS_FILE")); | ||
4 | |||
5 | $response = array( | ||
6 | "status" => "ok", | ||
7 | ); | ||
8 | $mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname, $dbport); | ||
9 | |||
10 | function error_die($text, $number) { | ||
11 | http_response_code("500"); | ||
12 | $message = array( | ||
13 | "status" => "error", | ||
14 | "message" => $text, | ||
15 | "code" => $number | ||
16 | ); | ||
17 | |||
18 | die(json_encode($message)); | ||
19 | } | ||
20 | |||
21 | if ($mysqli->connect_errno) { | ||
22 | error_die($mysqli->connect_error, $mysqli->connect_errno); | ||
23 | } | ||
24 | |||
25 | if (!isset($_GET['serial'])) { | ||
26 | $response["domains"] = array(); | ||
27 | $query = $mysqli->query("SELECT DISTINCT domain FROM `report` ORDER BY domain"); | ||
28 | if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } | ||
29 | while($row = $query->fetch_assoc()) { | ||
30 | $response["domains"][] = $row['domain']; | ||
31 | } | ||
32 | |||
33 | $response["orgs"] = array(); | ||
34 | $query = $mysqli->query("SELECT DISTINCT org FROM `report` ORDER BY org"); | ||
35 | if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } | ||
36 | while($row = $query->fetch_assoc()) { | ||
37 | $response["orgs"][] = $row['org']; | ||
38 | } | ||
39 | |||
40 | $response["dates"] = array(); | ||
41 | $query = $mysqli->query("SELECT DISTINCT DISTINCT year(mindate) as year, month(mindate) as month FROM `report` ORDER BY year DESC,month DESC"); | ||
42 | if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } | ||
43 | while($row = $query->fetch_assoc()) { | ||
44 | $response["dates"][] = sprintf( "%'.04d-%'.02d", $row['year'], $row['month'] ); | ||
45 | } | ||
46 | |||
47 | $response["summaries"] = array(); | ||
48 | if (isset($_GET['errors_only'])) { | ||
49 | $where = " WHERE (spfresult != 'pass' or dkimresult != 'pass')"; | ||
50 | } else { | ||
51 | $where = ""; | ||
52 | } | ||
53 | |||
54 | $sql = "SELECT report.* , sum(rptrecord.rcount) AS rcount, MIN(rptrecord.dkimresult) AS dkimresult, MIN(rptrecord.spfresult) AS spfresult FROM report LEFT JOIN (SELECT rcount, COALESCE(dkimresult, 'neutral') AS dkimresult, COALESCE(spfresult, 'neutral') AS spfresult, serial FROM rptrecord) AS rptrecord ON report.serial = rptrecord.serial$where GROUP BY serial ORDER BY mindate ASC, maxdate ASC, org"; | ||
55 | $query = $mysqli->query($sql); | ||
56 | if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } | ||
57 | while($row = $query->fetch_assoc()) { | ||
58 | unset($row["raw_xml"]); | ||
59 | $response["summaries"][] = $row; | ||
60 | } | ||
61 | } else { | ||
62 | $response["rptrecord"] = []; | ||
63 | $sql = $mysqli->prepare("SELECT * FROM rptrecord where serial = ?"); | ||
64 | $sql->bind_param("s", $_GET["serial"]); | ||
65 | $sql->execute(); | ||
66 | $query = $sql->get_result(); | ||
67 | if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } | ||
68 | while($row = $query->fetch_assoc()) { | ||
69 | if ($row['ip']) { | ||
70 | $ip = long2ip($row['ip']); | ||
71 | $host = gethostbyaddr($ip); | ||
72 | } elseif ( $row['ip6'] ) { | ||
73 | $ip = inet_ntop($row['ip6']); | ||
74 | $host = gethostbyaddr($ip); | ||
75 | } else { | ||
76 | $ip = "-"; | ||
77 | $host = "-"; | ||
78 | } | ||
79 | $row['ip'] = $ip; | ||
80 | $row['host'] = $host; | ||
81 | unset($row['ip6']); | ||
82 | $response["rptrecord"][] = $row; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | echo json_encode($response, JSON_PRETTY_PRINT); | ||
87 | ?> | ||
diff --git a/modules/private/websites/tools/tools/dmarc_reports/app.js b/modules/private/websites/tools/tools/dmarc_reports/app.js new file mode 100644 index 0000000..7fe67d0 --- /dev/null +++ b/modules/private/websites/tools/tools/dmarc_reports/app.js | |||
@@ -0,0 +1,86 @@ | |||
1 | const app = new Vue({ | ||
2 | el: '#app', | ||
3 | data: { | ||
4 | info: null, | ||
5 | summaries: [], | ||
6 | selectedSummary: null, | ||
7 | filterGreen: true, | ||
8 | filterDomain: null, | ||
9 | filterOrg: null, | ||
10 | //filterDate: (new Date()).toISOString().substring(0, 7), | ||
11 | filterDate: null, | ||
12 | reverse: true, | ||
13 | }, | ||
14 | created: async function () { | ||
15 | let that = this; | ||
16 | |||
17 | try { | ||
18 | this.info = await this.getInfo(); | ||
19 | this.summaries = this.info.summaries; | ||
20 | } catch (error) {} | ||
21 | }, | ||
22 | methods: { | ||
23 | filtered: function () { | ||
24 | let that = this; | ||
25 | let filtered = this.summaries.filter(function (summary) { | ||
26 | return (!that.filterGreen || that.getColor(summary) !== "lime") | ||
27 | && (!that.filterDomain || summary.domain === that.filterDomain) | ||
28 | && (!that.filterOrg || summary.org === that.filterOrg) | ||
29 | && (!that.filterDate || that.inDates(summary)); | ||
30 | }); | ||
31 | if (this.reverse) { | ||
32 | return filtered.reverse(); | ||
33 | } else { | ||
34 | return filtered; | ||
35 | } | ||
36 | }, | ||
37 | toggle: async function(summary) { | ||
38 | if (this.selectedSummary && this.selectedSummary.serial === summary.serial) { | ||
39 | this.selectedSummary = null; | ||
40 | } else { | ||
41 | if (!summary.details) { | ||
42 | summary.details = await this.getDetails(summary.serial); | ||
43 | } | ||
44 | this.selectedSummary = summary; | ||
45 | } | ||
46 | }, | ||
47 | inDates: function(summary) { | ||
48 | if (!this.filterDate) { return true; } | ||
49 | |||
50 | let mindate = (new Date(summary.mindate)).toISOString().substring(0, 7); | ||
51 | let maxdate = (new Date(summary.maxdate)).toISOString().substring(0, 7); | ||
52 | |||
53 | return mindate === this.filterDate || maxdate === this.filterDate; | ||
54 | }, | ||
55 | printDate: function (date) { | ||
56 | return (new Date(date)).toISOString(); | ||
57 | }, | ||
58 | getColor: function (element) { | ||
59 | if (element.dkimresult === "fail" && element.spfresult === "fail") { | ||
60 | return "red"; | ||
61 | } else if (element.dkimresult === "fail" || element.spfresult === "fail") { | ||
62 | return "orange"; | ||
63 | } else if (element.dkimresult === "pass" && element.spfresult === "pass") { | ||
64 | return "lime"; | ||
65 | } else { | ||
66 | return "yellow"; | ||
67 | } | ||
68 | }, | ||
69 | getInfo: function (event) { | ||
70 | return fetch('api.php').then(function (response) { | ||
71 | if (response.status != 200) { return; } | ||
72 | return response.text().then(function (body) { | ||
73 | return JSON.parse(body); | ||
74 | }); | ||
75 | }); | ||
76 | }, | ||
77 | getDetails: function (serial) { | ||
78 | return fetch(`api.php?serial=${serial}`).then(function (response) { | ||
79 | if (response.status != 200) { return; } | ||
80 | return response.text().then(function (body) { | ||
81 | return JSON.parse(body); | ||
82 | }); | ||
83 | }); | ||
84 | } | ||
85 | } | ||
86 | }); | ||
diff --git a/modules/private/websites/tools/tools/dmarc_reports/default.css b/modules/private/websites/tools/tools/dmarc_reports/default.css new file mode 100644 index 0000000..11608cc --- /dev/null +++ b/modules/private/websites/tools/tools/dmarc_reports/default.css | |||
@@ -0,0 +1,126 @@ | |||
1 | h1 { | ||
2 | text-align: center; | ||
3 | } | ||
4 | |||
5 | table.reportlist { | ||
6 | margin: 2em auto 2em auto; | ||
7 | border-collapse: collapse; | ||
8 | clear: both; | ||
9 | } | ||
10 | |||
11 | table.reportlist td, table.reportlist th { | ||
12 | padding:3px; | ||
13 | } | ||
14 | |||
15 | table.reportlist thead { | ||
16 | border-top: 1px solid grey; | ||
17 | border-bottom: 1px solid grey; | ||
18 | |||
19 | } | ||
20 | table.reportlist tbody tr:first-child td { | ||
21 | padding-top: 10px; | ||
22 | } | ||
23 | table.reportlist tr.sum { | ||
24 | border-top: 1px solid grey; | ||
25 | } | ||
26 | table.reportlist tr.selected { | ||
27 | background-color: lightgrey; | ||
28 | } | ||
29 | .reportdesc { | ||
30 | font-weight: bold; | ||
31 | width: 90%; | ||
32 | margin-left: auto; | ||
33 | margin-right: auto; | ||
34 | } | ||
35 | |||
36 | tr.summaryrow { | ||
37 | cursor: pointer; | ||
38 | } | ||
39 | |||
40 | tr.summaryrow:hover, tr.summaryrow.selected { | ||
41 | background-color: lightgray; | ||
42 | border-left: 1px solid lightgray; | ||
43 | } | ||
44 | |||
45 | td.reportcell { | ||
46 | border-bottom: 1px solid lightgray; | ||
47 | border-left: 1px solid lightgray; | ||
48 | border-right: 1px solid lightgray; | ||
49 | } | ||
50 | |||
51 | table.reportdata { | ||
52 | margin: 0px auto 0px auto; | ||
53 | border-collapse: separate; | ||
54 | border-spacing: 2px; | ||
55 | } | ||
56 | |||
57 | table.reportdata tr th, table.reportdata tr td { | ||
58 | text-align: center; | ||
59 | padding: 3px; | ||
60 | } | ||
61 | |||
62 | table.reportdata tr.red { | ||
63 | background-color: #FF0000; | ||
64 | } | ||
65 | |||
66 | table.reportdata tr.orange { | ||
67 | background-color: #FFA500; | ||
68 | } | ||
69 | |||
70 | table.reportdata tr.lime { | ||
71 | background-color: #00FF00; | ||
72 | } | ||
73 | |||
74 | table.reportdata tr.yellow { | ||
75 | background-color: #FFFF00; | ||
76 | } | ||
77 | |||
78 | .optionblock { | ||
79 | background: lightgrey; | ||
80 | padding: 0.4em; | ||
81 | float: right; | ||
82 | margin: auto 2em 1em auto; | ||
83 | white-space: nowrap; | ||
84 | } | ||
85 | |||
86 | .optionlabel { | ||
87 | font-weight: bold; | ||
88 | float: left; clear: left; | ||
89 | margin-right: 1em; | ||
90 | } | ||
91 | |||
92 | .options { | ||
93 | font-size: 70%; | ||
94 | text-align: right; | ||
95 | border: none; | ||
96 | width: 97%; | ||
97 | padding: 0.4em; | ||
98 | } | ||
99 | |||
100 | .center { | ||
101 | text-align:center; | ||
102 | } | ||
103 | |||
104 | .circle_lime:before { | ||
105 | content: ' \25CF'; | ||
106 | font-size: 25px; | ||
107 | color: #00FF00; | ||
108 | } | ||
109 | |||
110 | .circle_red:before { | ||
111 | content: ' \25CF'; | ||
112 | font-size: 25px; | ||
113 | color: #FF0000; | ||
114 | } | ||
115 | |||
116 | .circle_yellow:before { | ||
117 | content: ' \25CF'; | ||
118 | font-size: 25px; | ||
119 | color: #FFFF00; | ||
120 | } | ||
121 | |||
122 | .circle_orange:before { | ||
123 | content: ' \25CF'; | ||
124 | font-size: 25px; | ||
125 | color: #FFA500; | ||
126 | } | ||
diff --git a/modules/private/websites/tools/tools/dmarc_reports/index.html b/modules/private/websites/tools/tools/dmarc_reports/index.html new file mode 100644 index 0000000..ded05e1 --- /dev/null +++ b/modules/private/websites/tools/tools/dmarc_reports/index.html | |||
@@ -0,0 +1,118 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html> | ||
3 | |||
4 | <head> | ||
5 | <meta charset="utf-8"> | ||
6 | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
7 | <meta name="robots" content="noindex"> | ||
8 | <title>Dmarc reports</title> | ||
9 | <link rel="stylesheet" href="default.css"> | ||
10 | </head> | ||
11 | |||
12 | <body> | ||
13 | <div id="app" style="width: 100%"> | ||
14 | <div class="optionblock" v-if="info"> | ||
15 | <div class='options'> | ||
16 | <span class='optionlabel'>Hide all-green lines:</span> | ||
17 | <label><input type="radio" :value="false" v-model="filterGreen"> no</label> | ||
18 | <label><input type="radio" :value="true" v-model="filterGreen"> yes</label> | ||
19 | </div> | ||
20 | <div class='options'> | ||
21 | <span class='optionlabel'>Sort order:</span> | ||
22 | <label><input type="radio" :value="false" v-model="reverse"> ascending</label> | ||
23 | <label><input type="radio" :value="true" v-model="reverse"> descending</label> | ||
24 | </div> | ||
25 | <div class='options'> | ||
26 | <span class='optionlabel'>Domain(s):</span> | ||
27 | <select v-model="filterDomain"> | ||
28 | <option selected="selected" :value="null">[all]</option> | ||
29 | <option v-for="domain in info.domains" :value="domain">{{ domain }}</option> | ||
30 | </select> | ||
31 | </div> | ||
32 | <div class='options'> | ||
33 | <span class='optionlabel'>Organisation(s):</span> | ||
34 | <select v-model="filterOrg"> | ||
35 | <option selected="selected" :value="null">[all]</option> | ||
36 | <option v-for="org in info.orgs" :value="org">{{ org }}</option> | ||
37 | </select> | ||
38 | </div> | ||
39 | <div class='options'> | ||
40 | <span class='optionlabel'>Time:</span> | ||
41 | <select v-model="filterDate"> | ||
42 | <option selected="selected" :value="null">[all]</option> | ||
43 | <option v-for="date in info.dates" :value="date">{{ date }}</option> | ||
44 | </select> | ||
45 | </div> | ||
46 | </div> | ||
47 | |||
48 | <h1 class='main'>DMARC Reports</h1> | ||
49 | <table class='reportlist' v-if="summaries"> | ||
50 | <thead> | ||
51 | <tr> | ||
52 | <th></th> | ||
53 | <th>Start Date</th> | ||
54 | <th>End Date</th> | ||
55 | <th>Domain</th> | ||
56 | <th>Reporting Organization</th> | ||
57 | <th>Report ID</th> | ||
58 | <th>Messages</th> | ||
59 | </tr> | ||
60 | </thead> | ||
61 | <tbody> | ||
62 | <template v-for="summary in filtered()"> | ||
63 | <tr v-on:click="toggle(summary)" class="summaryrow" | ||
64 | v-bind:class="[{ selected: selectedSummary && summary.serial === selectedSummary.serial }]"> | ||
65 | <td class='right'><span :class="'circle_' + getColor(summary)"></span></td> | ||
66 | <td class='right'>{{ printDate(summary.mindate) }}</td> | ||
67 | <td class='right'>{{ printDate(summary.maxdate) }}</td> | ||
68 | <td class='center'>{{ summary.domain }}</td> | ||
69 | <td class='center'>{{ summary.org }}</td> | ||
70 | <td class='center'>{{ summary.reportid }}</td> | ||
71 | <td class='center'>{{ summary.rcount }}</td> | ||
72 | </tr> | ||
73 | <tr v-if="selectedSummary && summary.serial === selectedSummary.serial"> | ||
74 | <td colspan="6" class="reportcell"> | ||
75 | <div class='center reportdesc'> | ||
76 | <p>Policies: adkim={{ summary.policy_adkim }}, aspf={{ summary.policy_aspf }}, p={{ summary.policy_none }}, sp={{ summary.policy_sp }}, pct={{ summary.policy_pct }}</p> | ||
77 | </div> | ||
78 | <table v-if="summary.details" class='reportdata'> | ||
79 | <thead> | ||
80 | <tr> | ||
81 | <th>IP Address</th> | ||
82 | <th>Host Name</th> | ||
83 | <th>Message Count</th> | ||
84 | <th>Disposition</th> | ||
85 | <th>Reason</th> | ||
86 | <th>DKIM Domain</th> | ||
87 | <th>Raw DKIM Result</th> | ||
88 | <th>SPF Domain</th> | ||
89 | <th>Raw SPF Result</th> | ||
90 | </tr> | ||
91 | </thead> | ||
92 | <tbody> | ||
93 | <tr v-for="record in summary.details.rptrecord" :class='getColor(record)'> | ||
94 | <td>{{ record.ip }}</td> | ||
95 | <td>{{ record.host }}</td> | ||
96 | <td>{{ record.rcount }}</td> | ||
97 | <td>{{ record.disposition }}</td> | ||
98 | <td>{{ record.reason }}</td> | ||
99 | <td>{{ record.dkimdomain }}</td> | ||
100 | <td>{{ record.dkimresult }}</td> | ||
101 | <td>{{ record.spfdomain }}</td> | ||
102 | <td>{{ record.spfresult }}</td> | ||
103 | </tr> | ||
104 | </tbody> | ||
105 | </table> | ||
106 | </td> | ||
107 | <td></td> | ||
108 | </tr> | ||
109 | </template> | ||
110 | </tbody> | ||
111 | </table> | ||
112 | </div> | ||
113 | |||
114 | <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script> | ||
115 | <script src="app.js"></script> | ||
116 | </body> | ||
117 | |||
118 | </html> | ||
diff --git a/modules/private/websites/tools/tools/landing/config.yml b/modules/private/websites/tools/tools/landing/config.yml index 42ebcd1..f97b3f3 100644 --- a/modules/private/websites/tools/tools/landing/config.yml +++ b/modules/private/websites/tools/tools/landing/config.yml | |||
@@ -13,6 +13,9 @@ links: | |||
13 | icon: "fas fa-desktop" | 13 | icon: "fas fa-desktop" |
14 | url: "https://status.immae.eu" | 14 | url: "https://status.immae.eu" |
15 | target: '_blank' # optionnal html a tag target attribute | 15 | target: '_blank' # optionnal html a tag target attribute |
16 | - name: "DMARC status" | ||
17 | url: "https://tools.immae.eu/dmarc-reports" | ||
18 | target: '_blank' | ||
16 | - name: "Change password" | 19 | - name: "Change password" |
17 | url: "https://tools.immae.eu/ldap_password.php" | 20 | url: "https://tools.immae.eu/ldap_password.php" |
18 | target: '_blank' | 21 | target: '_blank' |