Browse Source

A workaround for some email agents automatically opening "Unsubscribe" links

pull/211/head
Pēteris Caune 6 years ago
parent
commit
b3c22dcfd2
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
10 changed files with 93 additions and 39 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +15
    -1
      hc/accounts/tests/test_unsubscribe_reports.py
  3. +5
    -0
      hc/accounts/views.py
  4. +14
    -0
      hc/front/tests/test_unsubscribe_email.py
  5. +5
    -0
      hc/front/views.py
  6. +9
    -9
      templates/accounts/unsubscribed.html
  7. +34
    -12
      templates/base_bare.html
  8. +1
    -1
      templates/emails/alert-body-html.html
  9. +1
    -1
      templates/emails/report-body-html.html
  10. +8
    -15
      templates/front/unsubscribe_success.html

+ 1
- 0
CHANGELOG.md View File

@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
- Show a warning when running with DEBUG=True - Show a warning when running with DEBUG=True
- Add "channels" attribute to the Check API resource - Add "channels" attribute to the Check API resource
- Can specify channel codes when updating a check via API - Can specify channel codes when updating a check via API
- Added a workaround for email agents automatically opening "Unsubscribe" links
### Bug Fixes ### Bug Fixes
- During DST transition, handle ambiguous dates as pre-transition - During DST transition, handle ambiguous dates as pre-transition


+ 15
- 1
hc/accounts/tests/test_unsubscribe_reports.py View File

@ -17,7 +17,7 @@ class UnsubscribeReportsTestCase(BaseTestCase):
url = "/accounts/unsubscribe_reports/%s/" % sig url = "/accounts/unsubscribe_reports/%s/" % sig
r = self.client.get(url) r = self.client.get(url)
self.assertContains(r, "You have been unsubscribed")
self.assertContains(r, "Unsubscribed")
self.profile.refresh_from_db() self.profile.refresh_from_db()
self.assertFalse(self.profile.reports_allowed) self.assertFalse(self.profile.reports_allowed)
@ -30,3 +30,17 @@ class UnsubscribeReportsTestCase(BaseTestCase):
url = "/accounts/unsubscribe_reports/invalid/" url = "/accounts/unsubscribe_reports/invalid/"
r = self.client.get(url) r = self.client.get(url)
self.assertContains(r, "Incorrect Link") self.assertContains(r, "Incorrect Link")
def test_post_works(self):
sig = signing.TimestampSigner(salt="reports").sign("alice")
url = "/accounts/unsubscribe_reports/%s/" % sig
r = self.client.post(url)
self.assertContains(r, "Unsubscribed")
def test_it_serves_confirmation_form(self):
sig = signing.TimestampSigner(salt="reports").sign("alice")
url = "/accounts/unsubscribe_reports/%s/?ask=1" % sig
r = self.client.get(url)
self.assertContains(r, "Please press the button below")

+ 5
- 0
hc/accounts/views.py View File

@ -355,6 +355,11 @@ def unsubscribe_reports(request, username):
except signing.BadSignature: except signing.BadSignature:
return render(request, "bad_link.html") return render(request, "bad_link.html")
# Some email servers open links in emails to check for malicious content.
# To work around this, we serve a form that auto-submits with JS.
if "ask" in request.GET and request.method != "POST":
return render(request, "accounts/unsubscribe_submit.html")
user = User.objects.get(username=username) user = User.objects.get(username=username)
profile = Profile.objects.for_user(user) profile = Profile.objects.for_user(user)
profile.reports_allowed = False profile.reports_allowed = False


+ 14
- 0
hc/front/tests/test_unsubscribe_email.py View File

@ -36,3 +36,17 @@ class UnsubscribeEmailTestCase(BaseTestCase):
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 400) self.assertEqual(r.status_code, 400)
def test_post_works(self):
token = self.channel.make_token()
url = "/integrations/%s/unsub/%s/" % (self.channel.code, token)
r = self.client.post(url)
self.assertContains(r, "has been unsubscribed", status_code=200)
def test_it_serves_confirmation_form(self):
token = self.channel.make_token()
url = "/integrations/%s/unsub/%s/?ask=1" % (self.channel.code, token)
r = self.client.get(url)
self.assertContains(r, "Please press the button below")

+ 5
- 0
hc/front/views.py View File

@ -516,6 +516,11 @@ def unsubscribe_email(request, code, token):
if channel.kind != "email": if channel.kind != "email":
return HttpResponseBadRequest() return HttpResponseBadRequest()
# Some email servers open links in emails to check for malicious content.
# To work around this, we serve a form that auto-submits with JS.
if "ask" in request.GET and request.method != "POST":
return render(request, "accounts/unsubscribe_submit.html")
channel.delete() channel.delete()
return render(request, "front/unsubscribe_success.html") return render(request, "front/unsubscribe_success.html")


+ 9
- 9
templates/accounts/unsubscribed.html View File

@ -1,12 +1,12 @@
{% extends "base.html" %}
{% extends "base_bare.html" %}
{% load hc_extras %}
{% block content %}
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<div class="hc-dialog">
<h1>You have been unsubscribed</h1>
</div>
</div>
</div>
{% block title %}Unsubscribed{% endblock %}
{% block content %}
<h1>Unsubscribed</h1>
<p>
Your email address has been unsubscribed from
{% site_name %} reports.
</p>
{% endblock %} {% endblock %}

+ 34
- 12
templates/base_bare.html View File

@ -2,23 +2,45 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{% block title %}{% site_name %} - Monitor Cron Jobs. Get Notified When Your Cron Jobs Fail{% endblock %}</title>
<title>{% block title %}{% site_name %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'>
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}"> <link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
{% compress css %}
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}" type="text/css">
<link rel="stylesheet" href="{% static 'css/base.css' %}" type="text/css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
text-align: center;
margin: 10em;
}
{% endcompress %}
h1 {
font-weight: 300;
font-size: 30px;
}
input {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 10px 16px;
font-size: 18px;
line-height: 1.3333333;
border-radius: 6px;
color: #ffffff;
background-color: #22bc66;
border-color: #1ea65a;
}
</style>
</head> </head>
<body class="page-{{ page }}">
{% block containers %}
<div class="container">
{% block content %}{% endblock %}
</div>
{% endblock %}
<body>
{% block content %}{% endblock %}
</body> </body>
</html> </html>

+ 1
- 1
templates/emails/alert-body-html.html View File

@ -22,7 +22,7 @@ The {% escaped_site_name %} Team
{% block unsub %} {% block unsub %}
<br> <br>
<a href="{{ unsub_link }}" target="_blank" style="color: #666666; text-decoration: underline;">
<a href="{{ unsub_link }}?ask=1" target="_blank" style="color: #666666; text-decoration: underline;">
Unsubscribe Unsubscribe
</a> </a>
{% endblock %} {% endblock %}

+ 1
- 1
templates/emails/report-body-html.html View File

@ -41,7 +41,7 @@ The {% escaped_site_name %} Team
{% block unsub %} {% block unsub %}
<br> <br>
<a href="{{ unsub_link }}" target="_blank" style="color: #666666; text-decoration: underline;">
<a href="{{ unsub_link }}?ask=1" target="_blank" style="color: #666666; text-decoration: underline;">
Unsubscribe Unsubscribe
</a> </a>
{% endblock %} {% endblock %}

+ 8
- 15
templates/front/unsubscribe_success.html View File

@ -1,19 +1,12 @@
{% extends "base.html" %}
{% extends "base_bare.html" %}
{% load hc_extras %} {% load hc_extras %}
{% block content %}
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<div class="hc-dialog">
<h1>Unsubscribed</h1>
<div class="dialog-body">
<p>
Your email address has been unsubscribed from
{% site_name %} notifications.
</p>
</div>
</div>
</div>
</div>
{% block title %}Unsubscribed{% endblock %}
{% block content %}
<h1>Unsubscribed</h1>
<p>
Your email address has been unsubscribed from
{% site_name %} notifications.
</p>
{% endblock %} {% endblock %}

Loading…
Cancel
Save