1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/accounts/utils.py
catborise 72681ab54e build(deps): the OTP e-mail draws its QR code with segno
django-qr-code was used for one thing: the QR code in the OTP e-mail,
as an inline SVG and a PNG. It brought pydantic, pydantic-core,
annotated-types and typing-inspection (about 10 MB) and, from 5.0 on,
Pillow. segno, which it used underneath, now draws both images with the
same options (error correction M, 4-module border, 1.8 mm SVG modules,
12 px PNG modules); the SVG, the PNG and the alt text are byte for byte
what django-qr-code 4.2 produced. account.html loaded the tag library
without using it.
2026-10-12 07:24:56 +03:00

79 lines
2.6 KiB
Python

import base64
import binascii
import struct
from decimal import Decimal
import segno
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from django_otp import devices_for_user
from django_otp.plugins.otp_totp.models import TOTPDevice
def get_existing_totp_device(user):
"""The user's confirmed TOTP device, or None. Unlike get_user_totp_device
it never creates one, so an unauthenticated caller cannot turn a
password-only account into an OTP-required one."""
for device in devices_for_user(user, confirmed=True):
if isinstance(device, TOTPDevice):
return device
return None
def get_user_totp_device(user):
devices = devices_for_user(user)
for device in devices:
if isinstance(device, TOTPDevice):
return device
device = user.totpdevice_set.create()
return device
def validate_ssh_key(key):
array = key.strip().encode().split()
# An OpenSSH public key has 2 parts (type, key) or 3 parts (type, key, comment).
if len(array) not in (2, 3):
return False
typeofkey = array[0]
string = array[1]
# must have only valid rsa-ssh key characters ie binascii characters
try:
data = base64.decodebytes(string)
except binascii.Error:
return False
# unpack the contents of data, from data[:4] , property of ssh key .
try:
str_len = struct.unpack(">I", data[:4])[0]
except struct.error:
return False
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
if data[4 : 4 + str_len] != typeofkey:
return False
return True
def send_email_with_otp(user, device):
# An inline SVG (1.8 mm modules) and, for mail clients that show no SVG,
# a PNG (12 px modules); error correction M, 4-module border.
qr = segno.make(device.config_url, error="m", mode="byte", encoding="utf-8", micro=False)
style = {"border": 4, "dark": "black", "light": "white"}
send_mail(
_("OTP QR Code"),
_("Please view HTML version of this message."),
None,
[user.email],
html_message=render_to_string(
"accounts/email/otp.html",
{
"totp_url": device.config_url,
"user": user,
"qr_svg": mark_safe(qr.svg_inline(scale=Decimal("1.8"), unit="mm", **style)),
"qr_png": qr.png_data_uri(scale=12, **style),
},
),
fail_silently=False,
)