This commit is contained in:
2025-06-15 19:35:11 +08:00
parent 8a043d2ffa
commit bd0a7f30f8
4 changed files with 43 additions and 7 deletions

View File

@@ -12,7 +12,7 @@ from django.db.models import Count, Q
from django.utils import timezone from django.utils import timezone
import qrcode import qrcode
from otpauth import OtpAuth from otpauth import TOTP
from problem.models import Problem from problem.models import Problem
from submission.models import Submission, JudgeStatus from submission.models import Submission, JudgeStatus
@@ -143,7 +143,7 @@ class TwoFactorAuthAPI(APIView):
label = f"{SysOptions.website_name_shortcut}:{user.username}" label = f"{SysOptions.website_name_shortcut}:{user.username}"
image = qrcode.make( image = qrcode.make(
OtpAuth(token).to_uri( TOTP(token).to_uri(
"totp", label, SysOptions.website_name.replace(" ", "") "totp", label, SysOptions.website_name.replace(" ", "")
) )
) )
@@ -157,7 +157,7 @@ class TwoFactorAuthAPI(APIView):
""" """
code = request.data["code"] code = request.data["code"]
user = request.user user = request.user
if OtpAuth(user.tfa_token).valid_totp(code): if TOTP(user.tfa_token).verify(code):
user.two_factor_auth = True user.two_factor_auth = True
user.save() user.save()
return self.success("Succeeded") return self.success("Succeeded")
@@ -171,7 +171,7 @@ class TwoFactorAuthAPI(APIView):
user = request.user user = request.user
if not user.two_factor_auth: if not user.two_factor_auth:
return self.error("2FA is already turned off") return self.error("2FA is already turned off")
if OtpAuth(user.tfa_token).valid_totp(code): if TOTP(user.tfa_token).verify(code):
user.two_factor_auth = False user.two_factor_auth = False
user.save() user.save()
return self.success("Succeeded") return self.success("Succeeded")
@@ -216,7 +216,7 @@ class UserLoginAPI(APIView):
if user.two_factor_auth and "tfa_code" not in data: if user.two_factor_auth and "tfa_code" not in data:
return self.error("tfa_required") return self.error("tfa_required")
if OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]): if TOTP(user.tfa_token).verify(data["tfa_code"]):
auth.login(request, user) auth.login(request, user)
return self.success("Succeeded") return self.success("Succeeded")
else: else:
@@ -287,7 +287,7 @@ class UserChangeEmailAPI(APIView):
if user.two_factor_auth: if user.two_factor_auth:
if "tfa_code" not in data: if "tfa_code" not in data:
return self.error("tfa_required") return self.error("tfa_required")
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]): if not TOTP(user.tfa_token).verify(data["tfa_code"]):
return self.error("Invalid two factor verification code") return self.error("Invalid two factor verification code")
data["new_email"] = data["new_email"].lower() data["new_email"] = data["new_email"].lower()
if User.objects.filter(email=data["new_email"]).exists(): if User.objects.filter(email=data["new_email"]).exists():
@@ -313,7 +313,7 @@ class UserChangePasswordAPI(APIView):
if user.two_factor_auth: if user.two_factor_auth:
if "tfa_code" not in data: if "tfa_code" not in data:
return self.error("tfa_required") return self.error("tfa_required")
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]): if not TOTP(user.tfa_token).verify(data["tfa_code"]):
return self.error("Invalid two factor verification code") return self.error("Invalid two factor verification code")
user.set_password(data["new_password"]) user.set_password(data["new_password"])
user.save() user.save()

View File

@@ -7,6 +7,7 @@ django-dramatiq==0.13.0
django-redis==5.4.0 django-redis==5.4.0
djangorestframework==3.16.0 djangorestframework==3.16.0
dramatiq==1.18.0 dramatiq==1.18.0
envelopes==0.4
gunicorn==23.0.0 gunicorn==23.0.0
idna==3.10 idna==3.10
otpauth==2.2.1 otpauth==2.2.1
@@ -15,10 +16,12 @@ pillow==11.2.1
prometheus-client==0.22.1 prometheus-client==0.22.1
psycopg==3.2.9 psycopg==3.2.9
psycopg-binary==3.2.9 psycopg-binary==3.2.9
python-dateutil==2.9.0.post0
qrcode==8.2 qrcode==8.2
raven==6.10.0 raven==6.10.0
redis==6.2.0 redis==6.2.0
requests==2.32.4 requests==2.32.4
six==1.17.0
sqlparse==0.5.3 sqlparse==0.5.3
typing-extensions==4.14.0 typing-extensions==4.14.0
urllib3==2.4.0 urllib3==2.4.0

View File

@@ -10,11 +10,13 @@ dependencies = [
"django-dramatiq>=0.13.0", "django-dramatiq>=0.13.0",
"django-redis>=5.4.0", "django-redis>=5.4.0",
"djangorestframework>=3.16.0", "djangorestframework>=3.16.0",
"envelopes>=0.4",
"gunicorn>=23.0.0", "gunicorn>=23.0.0",
"otpauth>=2.2.1", "otpauth>=2.2.1",
"pillow>=11.2.1", "pillow>=11.2.1",
"psycopg>=3.2.9", "psycopg>=3.2.9",
"psycopg-binary>=3.2.9", "psycopg-binary>=3.2.9",
"python-dateutil>=2.9.0.post0",
"qrcode>=8.2", "qrcode>=8.2",
"raven>=6.10.0", "raven>=6.10.0",
"requests>=2.32.4", "requests>=2.32.4",

31
uv.lock generated
View File

@@ -136,6 +136,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ac/00/d9ea755cdeda3d498504775b62122b72ba282b91446fd58980171fb1084c/dramatiq-1.18.0-py3-none-any.whl", hash = "sha256:d360f608aa3cd06f5db714bfcd23825dc7098bacfee52aca536b0bb0faae3c69", size = 121231, upload-time = "2025-05-30T12:00:30.199Z" }, { url = "https://files.pythonhosted.org/packages/ac/00/d9ea755cdeda3d498504775b62122b72ba282b91446fd58980171fb1084c/dramatiq-1.18.0-py3-none-any.whl", hash = "sha256:d360f608aa3cd06f5db714bfcd23825dc7098bacfee52aca536b0bb0faae3c69", size = 121231, upload-time = "2025-05-30T12:00:30.199Z" },
] ]
[[package]]
name = "envelopes"
version = "0.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2e/ac/0aaba34d717868729428bf4dca601c93cd6b0f9123894f2509911027b0dd/Envelopes-0.4.tar.gz", hash = "sha256:a4a02b4dc21467794d3a646f946d99a8c5b3311b2df8e211f96ca9e0b838e7e0", size = 33450, upload-time = "2013-11-13T20:02:09.033Z" }
[[package]] [[package]]
name = "gunicorn" name = "gunicorn"
version = "23.0.0" version = "23.0.0"
@@ -167,11 +173,13 @@ dependencies = [
{ name = "django-dramatiq" }, { name = "django-dramatiq" },
{ name = "django-redis" }, { name = "django-redis" },
{ name = "djangorestframework" }, { name = "djangorestframework" },
{ name = "envelopes" },
{ name = "gunicorn" }, { name = "gunicorn" },
{ name = "otpauth" }, { name = "otpauth" },
{ name = "pillow" }, { name = "pillow" },
{ name = "psycopg" }, { name = "psycopg" },
{ name = "psycopg-binary" }, { name = "psycopg-binary" },
{ name = "python-dateutil" },
{ name = "qrcode" }, { name = "qrcode" },
{ name = "raven" }, { name = "raven" },
{ name = "requests" }, { name = "requests" },
@@ -185,11 +193,13 @@ requires-dist = [
{ name = "django-dramatiq", specifier = ">=0.13.0" }, { name = "django-dramatiq", specifier = ">=0.13.0" },
{ name = "django-redis", specifier = ">=5.4.0" }, { name = "django-redis", specifier = ">=5.4.0" },
{ name = "djangorestframework", specifier = ">=3.16.0" }, { name = "djangorestframework", specifier = ">=3.16.0" },
{ name = "envelopes", specifier = ">=0.4" },
{ name = "gunicorn", specifier = ">=23.0.0" }, { name = "gunicorn", specifier = ">=23.0.0" },
{ name = "otpauth", specifier = ">=2.2.1" }, { name = "otpauth", specifier = ">=2.2.1" },
{ name = "pillow", specifier = ">=11.2.1" }, { name = "pillow", specifier = ">=11.2.1" },
{ name = "psycopg", specifier = ">=3.2.9" }, { name = "psycopg", specifier = ">=3.2.9" },
{ name = "psycopg-binary", specifier = ">=3.2.9" }, { name = "psycopg-binary", specifier = ">=3.2.9" },
{ name = "python-dateutil", specifier = ">=2.9.0.post0" },
{ name = "qrcode", specifier = ">=8.2" }, { name = "qrcode", specifier = ">=8.2" },
{ name = "raven", specifier = ">=6.10.0" }, { name = "raven", specifier = ">=6.10.0" },
{ name = "requests", specifier = ">=2.32.4" }, { name = "requests", specifier = ">=2.32.4" },
@@ -306,6 +316,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" }, { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" },
] ]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "six" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
]
[[package]] [[package]]
name = "qrcode" name = "qrcode"
version = "8.2" version = "8.2"
@@ -351,6 +373,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" },
] ]
[[package]]
name = "six"
version = "1.17.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
]
[[package]] [[package]]
name = "sqlparse" name = "sqlparse"
version = "0.5.3" version = "0.5.3"