From 9c08c3bc093d3d4547214daf057051e7384581e9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Sun, 26 Apr 2020 15:22:33 +0200 Subject: [PATCH] Add anonymize for dmarc_reports --- modules/private/environment.nix | 1 + .../websites/tools/tools/dmarc_reports.nix | 5 + .../tools/tools/dmarc_reports/api.php | 45 ++- .../websites/tools/tools/dmarc_reports/app.js | 33 ++- .../tools/tools/dmarc_reports/default.css | 256 +++++++++--------- .../tools/tools/dmarc_reports/index.html | 12 +- 6 files changed, 211 insertions(+), 141 deletions(-) diff --git a/modules/private/environment.nix b/modules/private/environment.nix index 5fbd023..0002622 100644 --- a/modules/private/environment.nix +++ b/modules/private/environment.nix @@ -825,6 +825,7 @@ in type = submodule { options = { mysql = mkMysqlOptions "DMARC" {}; + anonymous_key = mkOption { type = str; description = "Anonymous hashing key"; }; }; }; }; diff --git a/modules/private/websites/tools/tools/dmarc_reports.nix b/modules/private/websites/tools/tools/dmarc_reports.nix index 2e44526..e264e80 100644 --- a/modules/private/websites/tools/tools/dmarc_reports.nix +++ b/modules/private/websites/tools/tools/dmarc_reports.nix @@ -12,6 +12,7 @@ rec { $dbuser = "${env.mysql.user}"; $dbpass = "${env.mysql.password}"; $dbport = "${env.mysql.port}"; + $anonymous_key = "${env.anonymous_key}"; ?> ''; }]; @@ -32,7 +33,11 @@ rec { AllowOverride None Options +FollowSymlinks + + SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 + Use LDAPConnect Require all granted + Require ldap-attribute uid=immae ''; }; diff --git a/modules/private/websites/tools/tools/dmarc_reports/api.php b/modules/private/websites/tools/tools/dmarc_reports/api.php index 9b7f0c0..5d4657e 100644 --- a/modules/private/websites/tools/tools/dmarc_reports/api.php +++ b/modules/private/websites/tools/tools/dmarc_reports/api.php @@ -18,6 +18,28 @@ function error_die($text, $number) { die(json_encode($message)); } +$anonymous = isset($_GET['anonymous']) && $_GET['anonymous']; +function maybe_anonymize($string, $long = false) { + global $anonymous_key; + global $anonymous; + if ($anonymous) { + if ($long) { + return md5($anonymous_key . ":" . $string); + } else { + return substr(md5($anonymous_key . ":" . $string), 0, 6); + } + } else { + return $string; + } +} + +if (!$anonymous && (!isset($_SERVER['HTTP_AUTHORIZATION']) || $_SERVER['HTTP_AUTHORIZATION'] === "")) { + header('WWW-Authenticate: Basic realm="Immae"'); + header('HTTP/1.0 401 Unauthorized'); + echo "You need to be authenticated to access private information"; + exit; +} + if ($mysqli->connect_errno) { error_die($mysqli->connect_error, $mysqli->connect_errno); } @@ -27,14 +49,14 @@ if (!isset($_GET['serial'])) { $query = $mysqli->query("SELECT DISTINCT domain FROM `report` ORDER BY domain"); if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } while($row = $query->fetch_assoc()) { - $response["domains"][] = $row['domain']; + $response["domains"][] = maybe_anonymize($row['domain']); } $response["orgs"] = array(); $query = $mysqli->query("SELECT DISTINCT org FROM `report` ORDER BY org"); if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } while($row = $query->fetch_assoc()) { - $response["orgs"][] = $row['org']; + $response["orgs"][] = maybe_anonymize($row['org']); } $response["dates"] = array(); @@ -55,7 +77,13 @@ if (!isset($_GET['serial'])) { $query = $mysqli->query($sql); if ($mysqli->error) { error_die($mysqli->error, $mysqli->errno); } while($row = $query->fetch_assoc()) { - unset($row["raw_xml"]); + $wanted_keys = array( + 'domain', 'org', 'reportid', 'mindate', 'maxdate', 'rcount', 'serial', 'policy_adkim', 'policy_aspf', 'policy_none', 'policy_sp', 'policy_pct', 'spfresult', 'dkimresult' + ); + $row = array_intersect_key($row, array_fill_keys($wanted_keys, '1')); + $row["domain"] = maybe_anonymize($row["domain"]); + $row["org"] = maybe_anonymize($row["org"]); + $row["reportid"] = maybe_anonymize($row["reportid"], true); $response["summaries"][] = $row; } } else { @@ -76,9 +104,14 @@ if (!isset($_GET['serial'])) { $ip = "-"; $host = "-"; } - $row['ip'] = $ip; - $row['host'] = $host; - unset($row['ip6']); + $wanted_keys = array( + 'ip', 'host', 'rcount', 'disposition', 'reason', 'dkimdomain', 'dkimresult', 'spfdomain', 'spfresult' + ); + $row = array_intersect_key($row, array_fill_keys($wanted_keys, '1')); + $row['ip'] = maybe_anonymize($ip); + $row['host'] = maybe_anonymize($host); + $row['dkimdomain'] = maybe_anonymize($row['dkimdomain']); + $row['spfdomain'] = maybe_anonymize($row['spfdomain']); $response["rptrecord"][] = $row; } } diff --git a/modules/private/websites/tools/tools/dmarc_reports/app.js b/modules/private/websites/tools/tools/dmarc_reports/app.js index 7fe67d0..8e8a6c4 100644 --- a/modules/private/websites/tools/tools/dmarc_reports/app.js +++ b/modules/private/websites/tools/tools/dmarc_reports/app.js @@ -2,7 +2,7 @@ const app = new Vue({ el: '#app', data: { info: null, - summaries: [], + summaries: null, selectedSummary: null, filterGreen: true, filterDomain: null, @@ -10,16 +10,31 @@ const app = new Vue({ //filterDate: (new Date()).toISOString().substring(0, 7), filterDate: null, reverse: true, + anonymous: true, }, created: async function () { let that = this; - try { - this.info = await this.getInfo(); - this.summaries = this.info.summaries; - } catch (error) {} + if ('anonymous' in localStorage) { + this.anonymous = JSON.parse(localStorage.anonymous); + } + this.fetchAll(); }, methods: { + fetchAll: async function() { + try { + this.info = await this.getInfo(); + this.summaries = this.info.summaries; + } catch (error) { + this.info = null; + this.summaries = null; + } + }, + toggleAnonymous: function() { + this.anonymous = !this.anonymous; + localStorage.anonymous = this.anonymous; + this.fetchAll(); + }, filtered: function () { let that = this; let filtered = this.summaries.filter(function (summary) { @@ -53,7 +68,7 @@ const app = new Vue({ return mindate === this.filterDate || maxdate === this.filterDate; }, printDate: function (date) { - return (new Date(date)).toISOString(); + return (new Date(date)).toISOString().replace("T", " ").replace(/\..*Z$/, " UTC"); }, getColor: function (element) { if (element.dkimresult === "fail" && element.spfresult === "fail") { @@ -67,7 +82,8 @@ const app = new Vue({ } }, getInfo: function (event) { - return fetch('api.php').then(function (response) { + let anonymous = this.anonymous ? "anonymous=1" : ""; + return fetch(`api.php?${anonymous}`).then(function (response) { if (response.status != 200) { return; } return response.text().then(function (body) { return JSON.parse(body); @@ -75,7 +91,8 @@ const app = new Vue({ }); }, getDetails: function (serial) { - return fetch(`api.php?serial=${serial}`).then(function (response) { + let anonymous = this.anonymous ? "&anonymous=1" : ""; + return fetch(`api.php?serial=${serial}${anonymous}`).then(function (response) { if (response.status != 200) { return; } return response.text().then(function (body) { return JSON.parse(body); diff --git a/modules/private/websites/tools/tools/dmarc_reports/default.css b/modules/private/websites/tools/tools/dmarc_reports/default.css index 11608cc..9e0c63f 100644 --- a/modules/private/websites/tools/tools/dmarc_reports/default.css +++ b/modules/private/websites/tools/tools/dmarc_reports/default.css @@ -1,126 +1,130 @@ -h1 { - text-align: center; -} - -table.reportlist { - margin: 2em auto 2em auto; - border-collapse: collapse; - clear: both; -} - -table.reportlist td, table.reportlist th { - padding:3px; -} - -table.reportlist thead { - border-top: 1px solid grey; - border-bottom: 1px solid grey; - -} -table.reportlist tbody tr:first-child td { - padding-top: 10px; -} -table.reportlist tr.sum { - border-top: 1px solid grey; -} -table.reportlist tr.selected { - background-color: lightgrey; -} -.reportdesc { - font-weight: bold; - width: 90%; - margin-left: auto; - margin-right: auto; -} - -tr.summaryrow { - cursor: pointer; -} - -tr.summaryrow:hover, tr.summaryrow.selected { - background-color: lightgray; - border-left: 1px solid lightgray; -} - -td.reportcell { - border-bottom: 1px solid lightgray; - border-left: 1px solid lightgray; - border-right: 1px solid lightgray; -} - -table.reportdata { - margin: 0px auto 0px auto; - border-collapse: separate; - border-spacing: 2px; -} - -table.reportdata tr th, table.reportdata tr td { - text-align: center; - padding: 3px; -} - -table.reportdata tr.red { - background-color: #FF0000; -} - -table.reportdata tr.orange { - background-color: #FFA500; -} - -table.reportdata tr.lime { - background-color: #00FF00; -} - -table.reportdata tr.yellow { - background-color: #FFFF00; -} - -.optionblock { - background: lightgrey; - padding: 0.4em; - float: right; - margin: auto 2em 1em auto; - white-space: nowrap; -} - -.optionlabel { - font-weight: bold; - float: left; clear: left; - margin-right: 1em; -} - -.options { - font-size: 70%; - text-align: right; - border: none; - width: 97%; - padding: 0.4em; -} - -.center { - text-align:center; -} - -.circle_lime:before { - content: ' \25CF'; - font-size: 25px; - color: #00FF00; -} - -.circle_red:before { - content: ' \25CF'; - font-size: 25px; - color: #FF0000; -} - -.circle_yellow:before { - content: ' \25CF'; - font-size: 25px; - color: #FFFF00; -} - -.circle_orange:before { - content: ' \25CF'; - font-size: 25px; - color: #FFA500; -} +h1 { + text-align: center; +} + +p.warninginfo { + text-align: center; +} + +table.reportlist { + margin: 2em auto 2em auto; + border-collapse: collapse; + clear: both; +} + +table.reportlist td, table.reportlist th { + padding:3px; +} + +table.reportlist thead { + border-top: 1px solid grey; + border-bottom: 1px solid grey; + +} +table.reportlist tbody tr:first-child td { + padding-top: 10px; +} +table.reportlist tr.sum { + border-top: 1px solid grey; +} +table.reportlist tr.selected { + background-color: lightgrey; +} +.reportdesc { + font-weight: bold; + width: 90%; + margin-left: auto; + margin-right: auto; +} + +tr.summaryrow { + cursor: pointer; +} + +tr.summaryrow:hover, tr.summaryrow.selected { + background-color: lightgray; + border-left: 1px solid lightgray; +} + +td.reportcell { + border-bottom: 1px solid lightgray; + border-left: 1px solid lightgray; + border-right: 1px solid lightgray; +} + +table.reportdata { + margin: 0px auto 0px auto; + border-collapse: separate; + border-spacing: 2px; +} + +table.reportdata tr th, table.reportdata tr td { + text-align: center; + padding: 3px; +} + +table.reportdata tr.red { + background-color: #FF0000; +} + +table.reportdata tr.orange { + background-color: #FFA500; +} + +table.reportdata tr.lime { + background-color: #00FF00; +} + +table.reportdata tr.yellow { + background-color: #FFFF00; +} + +.optionblock { + background: lightgrey; + padding: 0.4em; + float: right; + margin: auto 2em 1em auto; + white-space: nowrap; +} + +.optionlabel { + font-weight: bold; + float: left; clear: left; + margin-right: 1em; +} + +.options { + font-size: 70%; + text-align: right; + border: none; + width: 97%; + padding: 0.4em; +} + +.center { + text-align:center; +} + +.circle_lime:before { + content: ' \25CF'; + font-size: 25px; + color: #00FF00; +} + +.circle_red:before { + content: ' \25CF'; + font-size: 25px; + color: #FF0000; +} + +.circle_yellow:before { + content: ' \25CF'; + font-size: 25px; + color: #FFFF00; +} + +.circle_orange:before { + content: ' \25CF'; + font-size: 25px; + color: #FFA500; +} diff --git a/modules/private/websites/tools/tools/dmarc_reports/index.html b/modules/private/websites/tools/tools/dmarc_reports/index.html index ded05e1..af29cdf 100644 --- a/modules/private/websites/tools/tools/dmarc_reports/index.html +++ b/modules/private/websites/tools/tools/dmarc_reports/index.html @@ -11,7 +11,13 @@
-
+
+
+ Anonymize + + +
+

DMARC Reports

+

+ No information could be fetched. If in non-anonymous mode you need to be logged-in +

-- 2.41.0