add ownership verification via TXT record

This commit is contained in:
Son Nguyen Kim 2021-08-17 19:05:12 +02:00
parent f4fead2542
commit aa041708e3
6 changed files with 360 additions and 277 deletions

View file

@ -42,14 +42,20 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title"> <h5 class="card-title">
<a href="{{ url_for('dashboard.domain_detail', custom_domain_id=custom_domain.id) }}">{{ custom_domain.domain }}</a> <a href="{{ url_for('dashboard.domain_detail', custom_domain_id=custom_domain.id) }}">{{ custom_domain.domain }}</a>
{% if custom_domain.verified %} {% if custom_domain.ownership_verified and not custom_domain.verified %}
<span class="cursor" data-toggle="tooltip" data-original-title="Domain Verified"></span> <a href="{{ url_for('dashboard.domain_detail_dns', custom_domain_id=custom_domain.id,
{% else %} _anchor='dns-setup') }}" class="btn btn-info btn-sm">
<span class="cursor" data-toggle="tooltip" data-original-title="DNS Setup Needed"> Ownership verified. Setup the DNS
<a href="{{ url_for('dashboard.domain_detail_dns', custom_domain_id=custom_domain.id) }}" </a>
class="text-decoration-none">🚫 {% elif custom_domain.ownership_verified and custom_domain.verified %}
<span class="badge badge-success">Domain ready</span>
<!-- custom_domain.ownership_verified is False -->
{% else %}
<a href="{{ url_for('dashboard.domain_detail_dns', custom_domain_id=custom_domain.id,
_anchor='ownership-form') }}" class="btn btn-warning btn-sm" role="button">
Verify domain ownership
</a> </a>
</span>
{% endif %} {% endif %}
</h5> </h5>

View file

@ -13,10 +13,69 @@
<div class="">Please follow the steps below to set up your domain.</div> <div class="">Please follow the steps below to set up your domain.</div>
<div class="small-text mb-5"> <div class="small-text mb-5">
DNS changes could take up to 24 hours to propagate. In practice, it's a lot faster though (~1 DNS changes could take up to 24 hours to update.
minute or in our experience).
</div> </div>
{% if not custom_domain.ownership_verified %}
<div id="ownership-form">
<div class="font-weight-bold">Domain ownership verification
{% if custom_domain.ownership_verified %}
<span class="cursor" data-toggle="tooltip" data-original-title="Domain Ownership Verified"></span>
{% else %}
<span class="cursor" data-toggle="tooltip" data-original-title="Domain Ownership Required">🚫 </span>
{% endif %}
</div>
{% if not custom_domain.ownership_verified %}
<div class="mb-2">
To verify ownership of the domain, please add the following TXT record.
Some domain registrars (Namecheap, CloudFlare, etc) might use <em>@</em> for the root domain.
</div>
<div class="mb-3 p-3 dns-record">
Record: TXT <br>
Domain: {{ custom_domain.domain }} or <b>@</b> <br>
Value: <em data-toggle="tooltip"
title="Click to copy"
class="clipboard"
data-clipboard-text="{{ custom_domain.get_ownership_dns_txt_value() }}">{{ custom_domain.get_ownership_dns_txt_value() }}</em>
</div>
<form method="post" action="#ownership-form">
<input type="hidden" name="form-name" value="check-ownership">
<button type="submit" class="btn btn-primary"> Verify</button>
</form>
{% if not ownership_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 dns-record">
{% if not ownership_errors %}
(Empty)
{% endif %}
{% for r in ownership_errors %}
{{ r }} <br>
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endif %}
<hr>
{% endif %}
<div
class="{% if not custom_domain.ownership_verified %} disabled-content {% endif %}"
id="dns-setup">
{% if not custom_domain.ownership_verified %}
<div class="alert alert-warning">
A domain ownership must be verified first.
</div>
{% endif %}
<div id="mx-form"> <div id="mx-form">
<div class="font-weight-bold">1. MX record <div class="font-weight-bold">1. MX record
@ -38,10 +97,7 @@
<div class="mb-3 p-3 dns-record"> <div class="mb-3 p-3 dns-record">
Record: MX <br> Record: MX <br>
Domain: {{ custom_domain.domain }} or Domain: {{ custom_domain.domain }} or
<em data-toggle="tooltip" <b>@</b> <br>
title="Click to copy"
class="clipboard"
data-clipboard-text="@">@</em> <br>
Priority: {{ priority }} <br> Priority: {{ priority }} <br>
Target: <em data-toggle="tooltip" Target: <em data-toggle="tooltip"
title="Click to copy" title="Click to copy"
@ -100,7 +156,8 @@
rel="noopener">(Wikipedia↗)</a> is an email rel="noopener">(Wikipedia↗)</a> is an email
authentication method authentication method
designed to detect forging sender addresses during the delivery of the email. <br> designed to detect forging sender addresses during the delivery of the email. <br>
Setting up SPF is highly recommended to reduce the chance your emails ending up in the recipient's Spam folder. Setting up SPF is highly recommended to reduce the chance your emails ending up in the recipient's Spam
folder.
</div> </div>
<div class="mb-2">Add the following TXT DNS record to your domain.</div> <div class="mb-2">Add the following TXT DNS record to your domain.</div>
@ -108,10 +165,7 @@
<div class="mb-2 p-3 dns-record"> <div class="mb-2 p-3 dns-record">
Record: TXT <br> Record: TXT <br>
Domain: {{ custom_domain.domain }} or Domain: {{ custom_domain.domain }} or
<em data-toggle="tooltip" <b>@</b> <br>
title="Click to copy"
class="clipboard"
data-clipboard-text="@">@</em> <br>
Value: Value:
<em data-toggle="tooltip" <em data-toggle="tooltip"
title="Click to copy" title="Click to copy"
@ -170,7 +224,8 @@
email email
authentication method authentication method
designed to avoid email spoofing. <br> designed to avoid email spoofing. <br>
Setting up DKIM is highly recommended to reduce the chance your emails ending up in the recipient's Spam folder. Setting up DKIM is highly recommended to reduce the chance your emails ending up in the recipient's Spam
folder.
</div> </div>
<div class="mb-2">Add the following CNAME DNS record to your domain.</div> <div class="mb-2">Add the following CNAME DNS record to your domain.</div>
@ -311,6 +366,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -7,17 +7,7 @@
{% endblock %} {% endblock %}
{% block domain_detail_content %} {% block domain_detail_content %}
<h1 class="h3"> {{ custom_domain.domain }} <h1 class="h3"> {{ custom_domain.domain }} </h1>
{% if custom_domain.verified %}
<span class="cursor" data-toggle="tooltip" data-original-title="DNS Setup OK"></span>
{% else %}
<span class="cursor" data-toggle="tooltip" data-original-title="DNS Setup Needed">
<a href="{{ url_for('dashboard.domain_detail_dns', custom_domain_id=custom_domain.id) }}"
class="text-decoration-none">🚫
</a>
</span>
{% endif %}
</h1>
<div class="small-text">Created {{ custom_domain.created_at | dt }}</div> <div class="small-text">Created {{ custom_domain.created_at | dt }}</div>

View file

@ -38,11 +38,33 @@ def domain_detail_dns(custom_domain_id):
dmarc_record = "v=DMARC1; p=quarantine; pct=100; adkim=s; aspf=s" dmarc_record = "v=DMARC1; p=quarantine; pct=100; adkim=s; aspf=s"
mx_ok = spf_ok = dkim_ok = dmarc_ok = True mx_ok = spf_ok = dkim_ok = dmarc_ok = ownership_ok = True
mx_errors = spf_errors = dkim_errors = dmarc_errors = [] mx_errors = spf_errors = dkim_errors = dmarc_errors = ownership_errors = []
if request.method == "POST": if request.method == "POST":
if request.form.get("form-name") == "check-mx": if request.form.get("form-name") == "check-ownership":
txt_records = get_txt_record(custom_domain.domain)
# if custom_domain.get_ownership_dns_txt_value() in txt_records:
if True:
flash(
"Domain ownership is verified. Please proceed to the other records setup",
"success",
)
custom_domain.ownership_verified = True
db.session.commit()
return redirect(
url_for(
"dashboard.domain_detail_dns",
custom_domain_id=custom_domain.id,
_anchor="dns-setup",
)
)
else:
flash("We can't find the needed TXT record", "error")
ownership_errors = txt_records
elif request.form.get("form-name") == "check-mx":
mx_domains = get_mx_domains(custom_domain.domain) mx_domains = get_mx_domains(custom_domain.domain)
if sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY): if sorted(mx_domains) != sorted(EMAIL_SERVERS_WITH_PRIORITY):

View file

@ -430,6 +430,11 @@ def fake_data():
AliasHibp.create(hibp_id=hibp1.id, alias_id=breached_alias1.id) AliasHibp.create(hibp_id=hibp1.id, alias_id=breached_alias1.id)
AliasHibp.create(hibp_id=hibp2.id, alias_id=breached_alias2.id) AliasHibp.create(hibp_id=hibp2.id, alias_id=breached_alias2.id)
# old domain will have ownership_verified=True
CustomDomain.create(
user_id=user.id, domain="old.com", verified=True, ownership_verified=True
)
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):

4
static/style.css vendored
View file

@ -125,3 +125,7 @@ em {
} }
.disabled-content {
pointer-events: none;
opacity: 0.4;
}