Merge lp:~twom/canonical-identity-provider/2fa-qrcode-fix into lp:canonical-identity-provider/release

Proposed by Tom Wardill
Status: Merged
Approved by: Tom Wardill
Approved revision: no longer in the source branch.
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: lp:~twom/canonical-identity-provider/2fa-qrcode-fix
Merge into: lp:canonical-identity-provider/release
Diff against target: 91 lines (+37/-5)
3 files modified
src/identityprovider/templatetags/qrcode.py (+6/-3)
src/identityprovider/tests/test_templatetags.py (+30/-1)
src/webui/tests/test_views_devices.py (+1/-1)
To merge this branch: bzr merge lp:~twom/canonical-identity-provider/2fa-qrcode-fix
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Ricardo Kirkner (community) Approve
Review via email: mp+341510@code.launchpad.net

Commit message

Mark the output of the qrcode template tag as safe.

Description of the change

Mark the output of the qrcode template tag as safe.

Avoids encoding the google url, but the data is quoted explicitly, so should be safe.

Change notice for django:
https://docs.djangoproject.com/en/dev/releases/1.9/#simple-tag-now-wraps-tag-output-in-conditional-escape

Final output of string:
https://chart.googleapis.com/chart?chs=250x250&chld=L|0&cht=qr&chl=otpauth%3A//totp/UbuntuSSO/zl%40beyfvift.org%3Fsecret%3DABJYTWOCRT5P7QK4NEKTAYN2FWU5PHKI%26period%3D30

To post a comment you must log in.
Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

LGTM

review: Approve
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/identityprovider/templatetags/qrcode.py'
--- src/identityprovider/templatetags/qrcode.py 2016-12-14 10:53:13 +0000
+++ src/identityprovider/templatetags/qrcode.py 2018-03-16 13:31:48 +0000
@@ -2,12 +2,14 @@
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from base64 import b32encode4from base64 import b32encode
5from urllib import quote5from urllib import quote_plus
6from django import template6from django import template
7from django.conf import settings7from django.conf import settings
8from django.utils.safestring import mark_safe
89
9register = template.Library()10register = template.Library()
10URL = 'https://chart.googleapis.com/chart?chs=250x250&chld=L|0&cht=qr&chl=%s'11URL = ('https://chart.googleapis.com/chart'
12 '?chs=250x250&chld=L%%7C0&cht=qr&chl=%s')
1113
1214
13def _encode(s):15def _encode(s):
@@ -30,4 +32,5 @@
30 otp_url += '&period={}'.format(settings.TOTP_PERIOD)32 otp_url += '&period={}'.format(settings.TOTP_PERIOD)
3133
32 # note: for https, you *must* use this domain34 # note: for https, you *must* use this domain
33 return URL % quote(otp_url)35 # mark this as safe as otherwise django will urlquote our data for us
36 return mark_safe(URL % quote_plus(otp_url))
3437
=== modified file 'src/identityprovider/tests/test_templatetags.py'
--- src/identityprovider/tests/test_templatetags.py 2014-11-28 19:08:01 +0000
+++ src/identityprovider/tests/test_templatetags.py 2018-03-16 13:31:48 +0000
@@ -1,12 +1,12 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from django.template import Context, Template
4from django.test import TestCase5from django.test import TestCase
56
6from identityprovider.templatetags.google_analytics import expand_ga_commands7from identityprovider.templatetags.google_analytics import expand_ga_commands
7from identityprovider.templatetags.static_url import static_url8from identityprovider.templatetags.static_url import static_url
89
9
10SNIPPETS = [10SNIPPETS = [
11 None,11 None,
12 '',12 '',
@@ -56,3 +56,32 @@
56 url = '/+relative'56 url = '/+relative'
57 with self.settings(RELATIVE_URL=url):57 with self.settings(RELATIVE_URL=url):
58 self.assertEqual(static_url('relative'), url)58 self.assertEqual(static_url('relative'), url)
59
60
61class QRCodeURLTestCase(TestCase):
62
63 def test_not_encoded(self):
64 """The url string should be marked as safe as we can't escape the &"""
65 qr_data = {
66 'oath_mode': 'totp',
67 'ident': u'UbuntuSSO/zl@beyfvift.org',
68 'hex_key': 'A10EE5139362F3150BFABB7DDBEC5EE6FA2CA989',
69 }
70
71 # Render the template tag so we see the final result
72 # as calling the method won't result in the string being encoded
73 template = Template(
74 '{% load qrcode %}{% qrcode_url mode ident hex_key %}'
75 )
76 context = Context(qr_data)
77 result = template.render(context)
78
79 # Ideally, we should just decode the string here and check if it
80 # changes but the email address is correctly encoded,
81 # so that changes if so.
82 # instead, check the whole string we have generated
83 expected_result = (
84 u'https://chart.googleapis.com/chart?chs=250x250&'
85 u'chld=L%7C0&cht=qr&chl=otpauth%3A%2F%2F%2FUbuntuSSO%2Fzl%40'
86 u'beyfvift.org%3Fsecret%3DUEHOKE4TMLZRKC72XN65X3C6435CZKMJ')
87 self.assertEqual(result, expected_result)
5988
=== modified file 'src/webui/tests/test_views_devices.py'
--- src/webui/tests/test_views_devices.py 2018-02-09 20:56:16 +0000
+++ src/webui/tests/test_views_devices.py 2018-03-16 13:31:48 +0000
@@ -5,7 +5,7 @@
55
6import re6import re
7from base64 import b16encode, b32encode7from base64 import b16encode, b32encode
8from urllib import quote as urlquote8from urllib import quote_plus as urlquote
99
10import mock10import mock
11from django.conf import settings11from django.conf import settings