mirror of
https://github.com/simple-login/app.git
synced 2024-09-20 15:05:59 +08:00
Add DMARC
This commit is contained in:
parent
a270987f70
commit
753e82d490
|
@ -9,7 +9,7 @@
|
|||
|
||||
{% block domain_detail_content %}
|
||||
<div class="bg-white p-4" style="max-width: 60rem; margin: auto">
|
||||
<h1 class="h3"> {{ custom_domain.domain }} </h1>
|
||||
<h1 class="h2"> {{ custom_domain.domain }} </h1>
|
||||
<div class="">Please follow the steps below to set up your domain.</div>
|
||||
|
||||
<div class="small-text mb-5">
|
||||
|
@ -167,7 +167,7 @@
|
|||
Domain: <em data-toggle="tooltip"
|
||||
title="Click to copy"
|
||||
class="clipboard"
|
||||
data-clipboard-text="dkim._domainkey.">dkim._domainkey.</em>{{ custom_domain.domain }} <br>
|
||||
data-clipboard-text="dkim._domainkey">dkim._domainkey</em>.{{ custom_domain.domain }} <br>
|
||||
Value:
|
||||
<em data-toggle="tooltip"
|
||||
title="Click to copy"
|
||||
|
@ -211,5 +211,73 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div id="dmarc-form">
|
||||
<div class="font-weight-bold">4. DMARC (Optional)
|
||||
{% if custom_domain.dmarc_verified %}
|
||||
<span class="cursor" data-toggle="tooltip" data-original-title="DMARC Verified">✅</span>
|
||||
{% else %}
|
||||
<span class="cursor" data-toggle="tooltip" data-original-title="DMARC Not Verified">🚫 </span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
DMARC <a href="https://en.wikipedia.org/wiki/DMARC" target="_blank">(Wikipedia↗)</a>
|
||||
is designed to protect the domain from unauthorized use, commonly known as email spoofing. <br>
|
||||
Built around SPF and DKIM, a DMARC policy tells the receiving mail server what to do if
|
||||
neither of those authentication methods passes.
|
||||
</div>
|
||||
|
||||
<div class="mb-2">Add the following TXT DNS record to your domain.</div>
|
||||
|
||||
<div class="mb-2 p-3" style="background-color: #eee">
|
||||
Record: TXT <br>
|
||||
Domain: <em data-toggle="tooltip"
|
||||
title="Click to copy"
|
||||
class="clipboard"
|
||||
data-clipboard-text="_dmarc">_dmarc</em>.{{ custom_domain.domain }} <br>
|
||||
Value:
|
||||
<em data-toggle="tooltip"
|
||||
title="Click to copy"
|
||||
class="clipboard"
|
||||
data-clipboard-text="{{ dmarc_record }}">
|
||||
{{ dmarc_record }}
|
||||
</em>
|
||||
</div>
|
||||
|
||||
<form method="post" action="#dmarc-form">
|
||||
<input type="hidden" name="form-name" value="check-dmarc">
|
||||
{% if custom_domain.dmarc_verified %}
|
||||
<button type="submit" class="btn btn-outline-primary">
|
||||
Re-verify
|
||||
</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Verify
|
||||
</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if not dmarc_ok %}
|
||||
<div class="text-danger mt-4">
|
||||
Your DNS is not correctly set.
|
||||
The TXT record we obtain is:
|
||||
<div class="mb-3 p-3" style="background-color: #eee">
|
||||
{% if not dmarc_errors %}
|
||||
(Empty)
|
||||
{% endif %}
|
||||
|
||||
{% for r in dmarc_errors %}
|
||||
{{ r }} <br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if custom_domain.dmarc_verified %}
|
||||
Without DMARC setup, emails sent from your alias might end up in the Spam/Junk folder.
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
from flask import render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from app.config import EMAIL_SERVERS_WITH_PRIORITY, DKIM_DNS_VALUE, EMAIL_DOMAIN
|
||||
from app.config import EMAIL_SERVERS_WITH_PRIORITY, EMAIL_DOMAIN
|
||||
from app.dashboard.base import dashboard_bp
|
||||
from app.dns_utils import (
|
||||
get_mx_domains,
|
||||
get_spf_domain,
|
||||
get_dkim_record,
|
||||
get_txt_record,
|
||||
get_cname_record,
|
||||
)
|
||||
|
@ -27,8 +26,10 @@ def domain_detail_dns(custom_domain_id):
|
|||
# hardcode the DKIM selector here
|
||||
dkim_cname = f"dkim._domainkey.{EMAIL_DOMAIN}"
|
||||
|
||||
mx_ok = spf_ok = dkim_ok = True
|
||||
mx_errors = spf_errors = dkim_errors = []
|
||||
dmarc_record = "v=DMARC1; p=quarantine; pct=100; adkim=s; aspf=s"
|
||||
|
||||
mx_ok = spf_ok = dkim_ok = dmarc_ok = True
|
||||
mx_errors = spf_errors = dkim_errors = dmarc_errors = []
|
||||
|
||||
if request.method == "POST":
|
||||
if request.form.get("form-name") == "check-mx":
|
||||
|
@ -43,7 +44,7 @@ def domain_detail_dns(custom_domain_id):
|
|||
]
|
||||
else:
|
||||
flash(
|
||||
"Your domain is verified. Now it can be used to create custom alias",
|
||||
"Your domain can start receiving emails. You can now use it to create alias",
|
||||
"success",
|
||||
)
|
||||
custom_domain.verified = True
|
||||
|
@ -58,7 +59,7 @@ def domain_detail_dns(custom_domain_id):
|
|||
if EMAIL_DOMAIN in spf_domains:
|
||||
custom_domain.spf_verified = True
|
||||
db.session.commit()
|
||||
flash("The SPF is setup correctly", "success")
|
||||
flash("SPF is setup correctly", "success")
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
|
||||
|
@ -75,7 +76,7 @@ def domain_detail_dns(custom_domain_id):
|
|||
elif request.form.get("form-name") == "check-dkim":
|
||||
dkim_record = get_cname_record(custom_domain.domain)
|
||||
if dkim_record == dkim_cname:
|
||||
flash("The DKIM is setup correctly.", "success")
|
||||
flash("DKIM is setup correctly.", "success")
|
||||
custom_domain.dkim_verified = True
|
||||
db.session.commit()
|
||||
|
||||
|
@ -89,6 +90,24 @@ def domain_detail_dns(custom_domain_id):
|
|||
dkim_ok = False
|
||||
dkim_errors = [dkim_record or "[Empty]"]
|
||||
|
||||
elif request.form.get("form-name") == "check-dmarc":
|
||||
txt_records = get_txt_record("_dmarc." + custom_domain.domain)
|
||||
if dmarc_record in txt_records:
|
||||
custom_domain.dmarc_verified = True
|
||||
db.session.commit()
|
||||
flash("DMARC is setup correctly", "success")
|
||||
return redirect(
|
||||
url_for(
|
||||
"dashboard.domain_detail_dns", custom_domain_id=custom_domain.id
|
||||
)
|
||||
)
|
||||
else:
|
||||
flash(
|
||||
f"DMARC: The TXT record is not correctly set", "warning",
|
||||
)
|
||||
dmarc_ok = False
|
||||
dmarc_errors = txt_records
|
||||
|
||||
return render_template(
|
||||
"dashboard/domain_detail/dns.html",
|
||||
EMAIL_SERVERS_WITH_PRIORITY=EMAIL_SERVERS_WITH_PRIORITY,
|
||||
|
|
|
@ -71,6 +71,7 @@ def get_spf_domain(hostname) -> [str]:
|
|||
|
||||
|
||||
def get_txt_record(hostname) -> [str]:
|
||||
"""return all domains listed in *include:*"""
|
||||
try:
|
||||
answers = _get_dns_resolver().query(hostname, "TXT")
|
||||
except Exception:
|
||||
|
@ -78,24 +79,10 @@ def get_txt_record(hostname) -> [str]:
|
|||
|
||||
ret = []
|
||||
|
||||
for a in answers: # type: dns.rdtypes.ANY.TXT.TXT
|
||||
ret.append(a)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_dkim_record(hostname) -> str:
|
||||
"""query the dkim._domainkey.{hostname} record and returns its value"""
|
||||
try:
|
||||
answers = _get_dns_resolver().query(f"dkim._domainkey.{hostname}", "TXT")
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
ret = []
|
||||
for a in answers: # type: dns.rdtypes.ANY.TXT.TXT
|
||||
for record in a.strings:
|
||||
record = record.decode() # record is bytes
|
||||
|
||||
ret.append(record)
|
||||
|
||||
return "".join(ret)
|
||||
return ret
|
||||
|
|
|
@ -23,8 +23,3 @@ def test_get_txt_record():
|
|||
|
||||
r = get_txt_record(_DOMAIN)
|
||||
assert len(r) > 0
|
||||
|
||||
|
||||
def test_get_dkim_record():
|
||||
r = get_dkim_record(_DOMAIN)
|
||||
assert r.startswith("v=DKIM1; k=rsa;")
|
||||
|
|
Loading…
Reference in a new issue