Skip to content

Commit 4554e32

Browse files
committed
colors
1 parent 6dd3a4a commit 4554e32

1 file changed

Lines changed: 34 additions & 19 deletions

File tree

dns.html

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ <h2 class="info-title">Hyperscaler DNS Exposure of Swiss Municipalities</h2>
5858
<div class="info-grid">
5959
<div class="info-card">
6060
<h3>What is this?</h3>
61-
<p>A map of all ~2,100 Swiss municipalities colored <strong style="color:#d32f2f">red</strong> if <em>any</em> email-related DNS record references a US hyperscaler &mdash; Microsoft, Google, or AWS. Even a single <code>include:</code> in SPF is enough to trigger exposure.</p>
61+
<p>A map of all ~2,100 Swiss municipalities shaded by how deeply their email DNS touches a US hyperscaler &mdash; Microsoft, Google, or AWS. <strong style="color:#e8741b">Orange</strong> means the MX record itself points to a hyperscaler (email lives there). <strong style="color:#c48b1a">Pale amber</strong> means the MX is elsewhere but SPF, DKIM, autodiscover, or another record still delegates to one. <strong style="color:#5a8a63">Green</strong> means no hyperscaler trace at all.</p>
6262
</div>
6363
<div class="info-card">
6464
<h3>How is this different from the Email Map?</h3>
65-
<p>The <a href="/">Email Map</a> picks one winning provider per municipality. This map casts a wider net: a municipality whose email is hosted by a Swiss provider but whose SPF record still delegates to <code>spf.protection.outlook.com</code> shows green on the Email Map, but red here.</p>
65+
<p>The <a href="/">Email Map</a> picks one winning provider per municipality. This map casts a wider net and grades exposure: a municipality whose email is hosted by a Swiss provider but whose SPF record still delegates to <code>spf.protection.outlook.com</code> shows as Swiss on the Email Map, but pale amber here.</p>
6666
</div>
6767
<div class="info-card">
6868
<h3>Which records are checked?</h3>
@@ -84,10 +84,18 @@ <h3>Open source &amp; open data</h3>
8484
document.addEventListener('DOMContentLoaded', function () {
8585

8686
var DNS_COLORS = {
87-
hyperscaler: '#d32f2f',
88-
clean: '#4caf50',
89-
nodata: '#cfcfcf',
90-
lake: '#afd7f5',
87+
heavy: '#fc7417',
88+
partial: '#fcae3c',
89+
clean: '#8cee92',
90+
nodata: '#d8d8d8',
91+
lake: '#8fc1e8',
92+
};
93+
94+
var DNS_TEXT_ON = {
95+
heavy: '#fff',
96+
partial: '#5a3a00',
97+
clean: '#1f3a22',
98+
nodata: '#333',
9199
};
92100

93101
// Mirror of src/mail_sovereignty/signatures.py — keep in sync if Cloudflare
@@ -194,16 +202,22 @@ <h3>Open source &amp; open data</h3>
194202
if (!m) return 'nodata';
195203
var hasData = (m.mx && m.mx.length) || m.spf;
196204
if (!hasData) return 'nodata';
197-
return getHyperscalerHits(m).length > 0 ? 'hyperscaler' : 'clean';
205+
var hits = getHyperscalerHits(m);
206+
if (hits.length === 0) return 'clean';
207+
for (var i = 0; i < hits.length; i++) {
208+
if (hits[i].kind === 'mx') return 'heavy';
209+
}
210+
return 'partial';
198211
}
199212

200213
function getColor(m) {
201214
return DNS_COLORS[getDnsStatus(m)];
202215
}
203216

204217
function getStatusLabel(status) {
205-
if (status === 'hyperscaler') return 'Hyperscaler exposed';
206-
if (status === 'clean') return 'No hyperscaler';
218+
if (status === 'heavy') return 'MX on hyperscaler';
219+
if (status === 'partial') return 'Hyperscaler in SPF/DNS';
220+
if (status === 'clean') return 'No hyperscaler';
207221
return 'No data';
208222
}
209223

@@ -221,12 +235,12 @@ <h3>Open source &amp; open data</h3>
221235
muni = dnsData.municipalities;
222236
showGenerated(dnsData);
223237

224-
var counts = { hyperscaler: 0, clean: 0, nodata: 0 };
238+
var counts = { heavy: 0, partial: 0, clean: 0, nodata: 0 };
225239
var byHyperscaler = { microsoft: 0, google: 0, aws: 0 };
226240
for (var bfs of Object.keys(muni)) {
227241
var status = getDnsStatus(muni[bfs]);
228242
counts[status]++;
229-
if (status === 'hyperscaler') {
243+
if (status === 'heavy' || status === 'partial') {
230244
var hs = getHyperscalerHits(muni[bfs]);
231245
var seenH = {};
232246
for (var i = 0; i < hs.length; i++) {
@@ -248,14 +262,15 @@ <h3>Open source &amp; open data</h3>
248262
'<div class="legend-content">' +
249263
'<strong>Hyperscaler DNS Exposure</strong>' +
250264
'<div class="legend-group">' +
251-
'<i class="legend-swatch" style="background:' + DNS_COLORS.hyperscaler + '"></i>Hyperscaler exposed (' + counts.hyperscaler + ')<br>' +
265+
'<i class="legend-swatch" style="background:' + DNS_COLORS.heavy + '"></i>MX on hyperscaler (' + counts.heavy + ')<br>' +
266+
'<i class="legend-swatch" style="background:' + DNS_COLORS.partial + '"></i>Hyperscaler in SPF/DNS only (' + counts.partial + ')<br>' +
252267
'<i class="legend-swatch" style="background:' + DNS_COLORS.clean + '"></i>No hyperscaler (' + counts.clean + ')<br>' +
253268
'<i class="legend-swatch" style="background:' + DNS_COLORS.nodata + '"></i>No data (' + counts.nodata + ')' +
254269
'</div>' +
255270
'<div class="legend-group" style="margin-top:6px;font-size:11px;color:#666;">' +
256-
'Microsoft: ' + byHyperscaler.microsoft + '<br>' +
257-
'Google: ' + byHyperscaler.google + '<br>' +
258-
'AWS: ' + byHyperscaler.aws +
271+
'Any trace of Microsoft: ' + byHyperscaler.microsoft + '<br>' +
272+
'Any trace of Google: ' + byHyperscaler.google + '<br>' +
273+
'Any trace of AWS: ' + byHyperscaler.aws +
259274
'</div>' +
260275
'</div>';
261276
L.DomEvent.disableClickPropagation(div);
@@ -274,8 +289,8 @@ <h3>Open source &amp; open data</h3>
274289
var m = muni[bfs];
275290
return {
276291
fillColor: getColor(m),
277-
weight: 0.6,
278-
color: '#afafaf',
292+
weight: 0.5,
293+
color: '#444444',
279294
fillOpacity: 1
280295
};
281296
},
@@ -289,7 +304,7 @@ <h3>Open source &amp; open data</h3>
289304
var status = getDnsStatus(m);
290305
var statusLabel = getStatusLabel(status);
291306
var color = DNS_COLORS[status];
292-
var textColor = status === 'nodata' ? '#333' : '#fff';
307+
var textColor = DNS_TEXT_ON[status];
293308

294309
var eName = escapeHtml(m.name);
295310
var cantonCode = CANTON_CODES[m.canton] || '';
@@ -303,7 +318,7 @@ <h3>Open source &amp; open data</h3>
303318
'<strong>' + nameDisplay + '</strong><br>' +
304319
eDomain + ' ' + badge;
305320

306-
if (status === 'hyperscaler') {
321+
if (status === 'heavy' || status === 'partial') {
307322
var hits = getHyperscalerHits(m);
308323
var hyperscalersFound = {};
309324
for (var i = 0; i < hits.length; i++) hyperscalersFound[hits[i].hyperscaler] = true;

0 commit comments

Comments
 (0)