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 django-otp#141.
  • Loading branch information
bluetech committed Apr 16, 2024
1 parent 48996ef commit 3e9c0f6
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 18 deletions.
13 changes: 13 additions & 0 deletions CHANGES.rst
@@ -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
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
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
9 changes: 2 additions & 7 deletions src/django_otp/plugins/otp_hotp/admin.py
Expand Up @@ -7,6 +7,7 @@
from django.utils.html import format_html

from django_otp.conf import settings
from django_otp.qrcode import write_qrcode_image

from .models import HOTPDevice

Expand Down Expand Up @@ -150,14 +151,8 @@ 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)
write_qrcode_image(device.config_url, response)
except ImportError:
response = HttpResponse('', status=503)

Expand Down
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
9 changes: 2 additions & 7 deletions src/django_otp/plugins/otp_totp/admin.py
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,14 +151,8 @@ 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)
write_qrcode_image(device.config_url, response)
except ImportError:
response = HttpResponse('', status=503)

Expand Down
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
21 changes: 21 additions & 0 deletions src/django_otp/qr.py
@@ -0,0 +1,21 @@
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 3e9c0f6

Please sign in to comment.