Skip to content

Commit

Permalink
Add support for segno as alternative to qrcode for QR image gener…
Browse files Browse the repository at this point in the history
…ation

Fix #141.
  • Loading branch information
bluetech authored and psagers committed Apr 16, 2024
1 parent 48996ef commit a9062d9
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 20 deletions.
13 changes: 13 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
Pending
--------------------------------------------------------------------------------

- `#141`_: Support alternative QR code library `segno`_.

Previously, only the `qrcode`_ library was supported.

Use ``segno`` by installing ``django-otp[segno]`` or just install the
``segno`` package.

.. _#141: https://github.com/django-otp/django-otp/issues/141
.. _segno: https://pypi.python.org/pypi/segno/

v1.4.1 - April 10, 2024 - Minor EmailDevice updates
--------------------------------------------------------------------------------

Expand Down
5 changes: 3 additions & 2 deletions docs/source/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,13 @@ django-otp includes support for several standard device types.
:class:`~django_otp.plugins.otp_totp.models.TOTPDevice` handle standard OTP
algorithms, which can be used with a variety of OTP generators. For example,
it's easy to pair these devices with `Google Authenticator`_ using the `otpauth
URL scheme`_. If you have the `qrcode`_ package installed, the admin interface
will generate QR Codes for you.
URL scheme`_. If you have either the `segno`_ or `qrcode`_ packages installed,
the admin interface will generate QR Codes for you.


.. _Google Authenticator: https://github.com/google/google-authenticator
.. _otpauth URL scheme: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
.. _segno: https://pypi.python.org/pypi/segno/
.. _qrcode: https://pypi.python.org/pypi/qrcode/


Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ dependencies = [
]

[project.optional-dependencies]
segno = [
"segno",
]
qrcode = [
"qrcode",
]
Expand All @@ -38,6 +41,7 @@ Documentation = "https://django-otp-official.readthedocs.io/"

[tool.hatch.envs.default]
features = [
"segno",
"qrcode",
]
dependencies = [
Expand Down
11 changes: 3 additions & 8 deletions src/django_otp/plugins/otp_hotp/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.utils.html import format_html

from django_otp.conf import settings
from django_otp.qr import write_qrcode_image

from .models import HOTPDevice

Expand Down Expand Up @@ -150,15 +151,9 @@ def qrcode_view(self, request, pk):
raise PermissionDenied()

try:
import qrcode
import qrcode.image.svg

img = qrcode.make(
device.config_url, image_factory=qrcode.image.svg.SvgImage
)
response = HttpResponse(content_type='image/svg+xml')
img.save(response)
except ImportError:
write_qrcode_image(device.config_url, response)
except ModuleNotFoundError:
response = HttpResponse('', status=503)

return response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
</p>
<p id="no-qrcode" style="display: none">
Install <a href="https://pypi.python.org/pypi/qrcode/">qrcode</a> or use the URL below:
Install <a href="https://pypi.python.org/pypi/segno/">segno</a> or <a href="https://pypi.python.org/pypi/qrcode/">qrcode</a> or use the URL below:
</p>
<p>{{ device.config_url }}</p>
</div>
Expand Down
11 changes: 3 additions & 8 deletions src/django_otp/plugins/otp_totp/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.utils.html import format_html

from django_otp.conf import settings
from django_otp.qr import write_qrcode_image

from .models import TOTPDevice

Expand Down Expand Up @@ -150,15 +151,9 @@ def qrcode_view(self, request, pk):
raise PermissionDenied()

try:
import qrcode
import qrcode.image.svg

img = qrcode.make(
device.config_url, image_factory=qrcode.image.svg.SvgImage
)
response = HttpResponse(content_type='image/svg+xml')
img.save(response)
except ImportError:
write_qrcode_image(device.config_url, response)
except ModuleNotFoundError:
response = HttpResponse('', status=503)

return response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
</p>
<p id="no-qrcode" style="display: none">
Install <a href="https://pypi.python.org/pypi/qrcode/">qrcode</a> or use the URL below:
Install <a href="https://pypi.python.org/pypi/segno/">segno</a> or <a href="https://pypi.python.org/pypi/qrcode/">qrcode</a> or use the URL below:
</p>
<p>{{ device.config_url }}</p>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/django_otp/qr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
def write_qrcode_image(data, out):
"""Write a QR code image for data to out.
The written image is in image/svg+xml format.
One of `qrcode` or `segno` are required. If neither is found, raises
ModuleNotFoundError.
"""
try:
import qrcode
import qrcode.image.svg

img = qrcode.make(data, image_factory=qrcode.image.svg.SvgImage)
img.save(out)
except ModuleNotFoundError:
import segno

img = segno.make(data)
img.save(out, kind='svg')

0 comments on commit a9062d9

Please sign in to comment.