Skip to content

Commit

Permalink
Add DMARC record explainer (Fixes #40) (#74)
Browse files Browse the repository at this point in the history
* Add DMARC record explainer (Fixes #40)

* Fixed wording of a description and ordering

* Add SP

* Change descriptions

* Forgot sp

* Add DMARC modal

* Add further information to learning modal

* Resolve outstanding lint issue

* Add dmarc desciptions/edited some others

* Use <code> for DMARC tag description values
  • Loading branch information
IAmJSD authored and MattIPv4 committed Sep 5, 2019
1 parent 2ed8d61 commit 719b56a
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 15 deletions.
31 changes: 31 additions & 0 deletions src/data/dmarc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2019 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import i18n from "../i18n"

export default {
v: i18n.data.dmarc.v,
ruf: i18n.data.dmarc.ruf,
rua: i18n.data.dmarc.rua,
pct: i18n.data.dmarc.pct,
p: i18n.data.dmarc.p,
aspf: i18n.data.dmarc.aspf,
adkim: i18n.data.dmarc.adkim,
sp: i18n.data.dmarc.sp,
fo: i18n.data.dmarc.fo,
rf: i18n.data.dmarc.rf,
ri: i18n.data.dmarc.ri,
}
13 changes: 13 additions & 0 deletions src/i18n/en/data/dmarc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default {
v: `This dictates the DMARC protocol version that is being used. This is normally located at the start of a record and set to <code class="slim">DMARC1</code>.`,
ruf: "This is a comma separated list of e-mails where forensic reports should be sent.",
rua: "This is a comma separated list of e-mails where aggregate reports should be sent.",
pct: "This defines the percentage of e-mail which will have this policy applied.",
p: `This defines how domain administrators want e-mail treated on the primary domain that fail the DMARC validation checks. The options are <code class="slim">none</code> (treat the same as usual), <code class="slim">quarantine</code> (mark as spam) or <code class="slim">reject</code> (reject the message).`,
aspf: `If this is set to strict <code class="slim">s</code> mode the domain which e-mails are being sent from must exactly pass SPF record validation. If not, it will default to relaxed <code class="slim">r</code> mode where any sub-domain can inherit the root domain's SPF records.`,
adkim: `By default this is set to relaxed <code class="slim">r</code> mode where any sub-domain can inherit the root domain's DKIM records. If this is set to strict <code class="slim">s</code> mode, the domain which e-mails are being sent from must exactly pass DKIM record validation.`,
sp: `This defines how domain administrators want e-mail treated on sub-domains that fail the DMARC validation checks. The options are <code class="slim">none</code> (treat the same as usual), <code class="slim">quarantine</code> (mark as spam) or <code class="slim">reject</code> (reject the message).`,
fo: `This option allows you to configure when failure reports should be sent. The available options are <code class="slim">0</code> which is the default and specifies that a report should be sent if an email fails SPF and DKIM checks, <code class="slim">1</code> to send a report if SPF or DKIM checks fail, <code class="slim">d</code> to send a report for only DKIM failures and <code class="slim">s</code> to send a report for only SPF failures.`,
rf: `This is the format reports are sent in. It currently only has one supported value, <code class="slim">afrf</code>, which is the default.`,
ri: `The requested interval between DMARC reports being sent in seconds. This defaults to <code class="slim">86400</code>.`,
} as {[key: string]: string}
3 changes: 2 additions & 1 deletion src/i18n/en/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import txt from "./txt"
import dmarc from "./dmarc"
import records from "./records"
import recordKeyHelp from "./record_key_help"

export default {
txt, records, recordKeyHelp,
txt, records, recordKeyHelp, dmarc,
} as {[key: string]: {[key: string]: string}}
7 changes: 7 additions & 0 deletions src/i18n/en/templates/dmarc_explainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
title: "DMARC Explanations",
intro: `<p>A DMARC record is a normal TXT DNS records that is created at <code class="slim">_dmarc.hostname.</code> instead of just the root hostname.
This record can contain any of the following "tags" formatted as <code class="slim">tag=value</code> and separated by semi-colons.</p>
<p>An example of a DMARC TXT record would be: <pre><code>_dmarc.hostname. 300 IN TXT "v=DMARC1;p=reject;pct=100;rua=mailto:postmaster@hostname"</code></pre></p>`,
learnMore: "Learn more about DMARC at",
} as {[key: string]: string}
3 changes: 2 additions & 1 deletion src/i18n/en/templates/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import github from "./github"
import dnsDiff from "./dns_diff"
import skeletons from "./skeletons"
import clipboardModal from "./clipboard_modal"
import dmarcExplainer from "./dmarc_explainer"

export default {
app, dodns, mxBlacklist, records, truncatedRecord,
whois, propagationModal, recordSelectionModal, github,
dnsDiff, skeletons, clipboardModal,
dnsDiff, skeletons, clipboardModal, dmarcExplainer,
} as {[key: string]: {[key: string]: any}}
1 change: 1 addition & 0 deletions src/i18n/en/templates/records.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default {
propagationNote: "Google DNS is reporting different values. This potentially means that your values have not propagated fully yet.",
srvTlsaFormat: `Expecting to see {a} {record} record here? Make sure you're looking at the right sub-domain.
<br/>{record} record names are normally formatted as follows: <code>_&lt;{sub}&gt;._&lt;protocol&gt;.name.</code>`,
dmarcMechanisms: "What are the mechanisms supported in DMARC records?",
} as {[key: string]: string}
25 changes: 21 additions & 4 deletions src/scss/_typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,34 @@ strong {
}

// Code
:not(pre) > code {
:not(pre) > code,
pre {
color: lighten($text, 20);
font-size: 14px;
font-size: 0.85em;
font-family: $mono-font-family;
white-space: nowrap;
padding: $margin * 0.75;
margin: ($margin * 0.5) 0;
border: $thin-border;
border-radius: $border-radius;
background: $panel;
}

:not(pre) > code {
white-space: nowrap;
padding: $margin * 0.75;
display: inline-block;

&.slim {
margin: 0;
padding: 0.15em 0.4em;
}
}

pre {
margin-right: $margin;

code {
font-size: 1.15em;
}
}

// Headings
Expand Down
14 changes: 6 additions & 8 deletions src/standardise_records.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,12 @@ export default (key: string, json: any, txtRecordFragments: any, recordsJoined:
for (const newSplit of dataSplit) {
if (newSplit === "") continue

if (!newSplit.startsWith("v")) {
newRecords.push({
name: record.name,
data: newSplit,
TTL: record.TTL,
type: undefined,
})
}
newRecords.push({
name: record.name,
TTL: record.TTL,
data: newSplit,
type: undefined,
})
}
}
json.Answer = newRecords
Expand Down
64 changes: 64 additions & 0 deletions src/templates/dmarc_explainer_modal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!--
Copyright 2019 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<template>
<div :class="`modal ${toggled ? 'is-active' : ''}`">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
{{ i18n.templates.dmarcExplainer.title }}
</p>
<button class="delete" :aria-label="i18n.common.close" @click="toggle"></button>
</header>
<section class="modal-card-body">
<div v-html="i18n.templates.dmarcExplainer.intro"></div>
<hr>
<p v-for="(value, key) in dmarc" :key="key">
<b>{{ key }}</b>: <span v-html="value"></span>
</p>
<hr>
<p>
{{ i18n.templates.dmarcExplainer.learnMore }}
<ExternalLink link="https://dmarc.org/" text="dmarc.org"></ExternalLink>.
</p>
</section>
</div>
</div>
</template>

<script>
import i18n from "../i18n"
import dmarc from "../data/dmarc"
import ExternalLink from "./ext_link"
export default {
name: "DMARCExplainerModal",
components: { ExternalLink },
data() {
return {
toggled: false,
i18n,
dmarc,
}
},
methods: {
toggle() {
this.$data.toggled = !this.$data.toggled
},
},
}
</script>
16 changes: 15 additions & 1 deletion src/templates/record.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ limitations under the License.
<p v-if="this.$props.recordType === 'SRV' || this.$props.recordType === 'TLSA'" v-html="insertHtmlPlaceholders()"></p>
</div>
<div v-else>
<p v-if="$props.recordType === 'DMARC'">
<a @click="openDmarcModal">{{ i18n.templates.records.dmarcMechanisms }}</a>
</p>
<table class="table">
<thead>
<tr>
Expand Down Expand Up @@ -69,7 +72,7 @@ limitations under the License.
<div v-if="valueNode.description">
<hr style="margin: 5px" />
<p style="font-size: 11px">
<b>{{ valueNode.description }}</b>
<b v-html="valueNode.description"></b>
</p>
</div>
</td>
Expand All @@ -94,6 +97,7 @@ limitations under the License.
<RecordSkeleton :loading="$props.loading"></RecordSkeleton>
</div>
<hr>
<DMARCExplainerModal ref="DMARCExplainerModal"></DMARCExplainerModal>
</div>
</template>

Expand All @@ -107,6 +111,7 @@ limitations under the License.
import records from "../data/records"
import recordKeyHelp from "../data/record_key_help"
import txtFragments from "../data/txt"
import dmarcFragments from "../data/dmarc"
import registrarRegexp from "../data/registrar_regexp"
import nsRegexp from "../data/ns_regexp"
import RecordTutorials from "../data/record_tutorials"
Expand All @@ -116,6 +121,7 @@ limitations under the License.
import DNSDiff from "./dns_diff"
import { reports } from "../plain_text_reports"
import ExternalLink from "./ext_link"
import DMARCExplainerModal from "./dmarc_explainer_modal"
const trimmers = {}
for (const recordKey in records)
Expand Down Expand Up @@ -146,6 +152,7 @@ limitations under the License.
RecordSkeleton,
DNSDiff,
ExternalLink,
DMARCExplainerModal,
},
props: {
recordUrl: String,
Expand Down Expand Up @@ -185,6 +192,9 @@ limitations under the License.
this.handleRegistrar()
},
methods: {
openDmarcModal() {
this.$refs.DMARCExplainerModal.toggle()
},
insertHtmlPlaceholders() {
return i18n.templates.records.srvTlsaFormat
.replace(/{record}/g, this.$props.recordType)
Expand Down Expand Up @@ -311,6 +321,10 @@ limitations under the License.
}
if (txtFragments[truncated]) data.description = txtFragments[truncated]
if (part.length > 20) data.values[0].truncated = truncated
} else if (key === "DMARC") {
const split = part.split("=")
const whitespaceGone = split[0].trim()
if (dmarcFragments[whitespaceGone]) data.description = dmarcFragments[whitespaceGone]
}
}
if (this.$props.expectsHost) {
Expand Down

0 comments on commit 719b56a

Please sign in to comment.