commit 9692235f7f08724be7bfd542553f563c8bab517d Author: Isis Lovecruft isis@torproject.org Date: Thu Jan 15 21:58:55 2015 +0000
Add support for generating QRCodes for bridge lines on bridges.html.
* FIXES #11345 https://bugs.torproject.org/11345 --- lib/bridgedb/HTTPServer.py | 9 ++++- lib/bridgedb/qrcodes.py | 59 ++++++++++++++++++++++++++++++++ lib/bridgedb/templates/bridges.html | 64 ++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/lib/bridgedb/HTTPServer.py b/lib/bridgedb/HTTPServer.py index 6aebba1..b073542 100644 --- a/lib/bridgedb/HTTPServer.py +++ b/lib/bridgedb/HTTPServer.py @@ -49,6 +49,7 @@ from bridgedb.Filters import filterBridgesByIP6 from bridgedb.Filters import filterBridgesByTransport from bridgedb.Filters import filterBridgesByNotBlockedIn from bridgedb.parse import headers +from bridgedb.qrcodes import generateQR from bridgedb.safelog import logSafely
@@ -785,6 +786,11 @@ class WebResourceBridges(resource.Resource): rendered = bridgeLines else: request.setHeader("Content-Type", "text/html; charset=utf-8") + qrcode = None + qrjpeg = generateQR(bridgeLines) + + if qrjpeg: + qrcode = 'data:image/jpeg;base64,%s' % base64.b64encode(qrjpeg) try: langs = translations.getLocaleFromHTTPRequest(request) rtl = translations.usingRTLLang(langs) @@ -792,7 +798,8 @@ class WebResourceBridges(resource.Resource): rendered = template.render(strings, rtl=rtl, lang=langs[0], - answer=bridgeLines) + answer=bridgeLines, + qrcode=qrcode) except Exception as err: rendered = replaceErrorPage(err)
diff --git a/lib/bridgedb/qrcodes.py b/lib/bridgedb/qrcodes.py new file mode 100644 index 0000000..ae25f06 --- /dev/null +++ b/lib/bridgedb/qrcodes.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 ; test-case-name: bridgedb.test.test_qrcodes ; -*- +#_____________________________________________________________________________ +# +# This file is part of BridgeDB, a Tor bridge distribution system. +# +# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 isis@torproject.org +# please also see AUTHORS file +# :copyright: (c) 2007-2015, The Tor Project, Inc. +# (c) 2014-2015, Isis Lovecruft +# :license: see LICENSE for licensing information +#_____________________________________________________________________________ + +"""Utilities for working with QRCodes.""" + + +import cStringIO +import logging + + +def generateQR(bridgelines, imageFormat=u'JPEG'): + """Generate a QRCode for the client's bridge lines. + + :param str bridgelines: The Bridge Lines which we are distributing to the + client. + :rtype: str or ``None`` + + :returns: The generated QRCode, as a string. + """ + logging.debug("Attempting to encode bridge lines into a QRCode...") + + if not bridgelines: + return + + try: + import qrcode + + qr = qrcode.QRCode() + qr.add_data(bridgelines) + buf = cStringIO.StringIO() + img = qr.make_image().resize([350, 350]) + img.save(buf, imageFormat) + buf.seek(0) + imgstr = buf.read() + logging.debug("Got QRCode image string.") + + return imgstr + + except ImportError as error: + logging.error(str(error)) + logging.debug(("You'll need the qrcode Python module for this to " + "work. On Debian-based systems, this should be in the " + "python-qrcode package.")) + except KeyError as error: + logging.error(str(error)) + logging.debug(("It seems python-imaging doesn't understand how to " + "save in the %s format.") % imgFormat) + except Exception as error: + logging.error(("There was an error while attempting to generate the " + "QRCode: %s") % str(error)) diff --git a/lib/bridgedb/templates/bridges.html b/lib/bridgedb/templates/bridges.html index d3c10c1..8048919 100644 --- a/lib/bridgedb/templates/bridges.html +++ b/lib/bridgedb/templates/bridges.html @@ -1,7 +1,7 @@ ## -*- coding: utf-8 -*-
<%inherit file="base.html"/> -<%page args="strings, rtl=False, lang='en', answer=0, **kwargs"/> +<%page args="strings, rtl=False, lang='en', answer=0, qrcode=0, **kwargs"/>
</div> </div> @@ -31,6 +31,20 @@ window.alert(e); } } + + function displayOrHide(element) { + try { + e = document.getElementById(element); + + if (e.style.display === 'none') { + document.getElementById(element).style.display = 'block'; + } else if (e.style.display === 'block') { + document.getElementById(element).style.display = 'none'; + } + } catch (e) { + window.alert(e); + } + } </script>
<div class="container-narrow"> @@ -66,6 +80,50 @@ ${answer.replace("\n", "<br />")} title="Select all bridge lines"> <i class="icon icon-2x icon-paste"></i> ${_("""Select All""")} </button> +% if qrcode: + <a class="btn btn-primary" type="button" id="qrcodebtn" + href="${qrcode}" title="Show QRCode for bridge lines" + onclick="displayOrHide('qrcode')"> + <i class="icon icon-2x icon-qrcode"></i> ${_("""Show QRCode""")} + </a> +% endif + </div> + + <div class="modal" id="qrcode" style="display: none;"> + <div class="modal-dialog modal-sm" style="width: 400px;"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" aria-hidden="true" + onclick="displayOrHide('qrcode')"> + × + </button> + <h4 class="modal-title">${_("""QRCode for your bridge lines""")}</h4> + </div> + <div class="modal-body"> +% if qrcode: + <p style="text-align: center;"> + <img width="350" height="350" + title="QRCode for your bridge lines from BridgeDB" + src="${qrcode}" /> + </p> +% else: + <p class="text-danger"> +## TRANSLATORS: Please translate this into some silly way to say +## "There was a problem!" in your language. For example, +## for Italian, you might translate this into "Mama mia!", +## or for French: "Sacrebleu!". :) +${_("""Uh oh, spaghettios!""")} +${_("""It seems there was an error getting your QRCode.""")} + <i class="icon icon-frown"></i> + </p> +% endif + <p> +${_("""This QRCode contains your bridge lines. Scan it with a QRCode """ \ + """reader to copy your bridge lines onto mobile and other devices.""")} + </p> + </div> + </div> + </div> </div> </div>
@@ -133,6 +191,10 @@ ${_("""Uh oh, spaghettios!""")} <script type="text/javascript"> // Make the 'Select All' button clickable: document.getElementById('selectbtn').className = "btn btn-primary"; + + // Remove the href attribute which opens the QRCode image as a data URL if + // JS is disabled: + document.getElementById('qrcodebtn').removeAttribute('href'); </script>
<hr />