update deps

This commit is contained in:
2026-05-05 07:23:59 -06:00
parent c0c5be9420
commit 0fd7dedea6
6 changed files with 786 additions and 711 deletions

View File

@@ -12,7 +12,7 @@ from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.timezone import now
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
from otpauth import OtpAuth
from otpauth import TOTP
from options.options import SysOptions
from problem.models import Problem
@@ -42,6 +42,22 @@ from ..serializers import (
from ..tasks import send_email_async
def _totp(token):
return TOTP(token.encode("utf-8"))
def _totp_uri(token, label, issuer):
return _totp(token).to_uri(label, issuer)
def _valid_totp(token, code):
try:
code = int(code)
except (TypeError, ValueError):
return False
return _totp(token).verify(code)
class UserProfileAPI(APIView):
@method_decorator(ensure_csrf_cookie)
def get(self, request, **kwargs):
@@ -142,9 +158,7 @@ class TwoFactorAuthAPI(APIView):
label = f"{SysOptions.website_name_shortcut}:{user.username}"
image = qrcode.make(
OtpAuth(token).to_uri(
"totp", label, SysOptions.website_name.replace(" ", "")
)
_totp_uri(token, label, SysOptions.website_name.replace(" ", ""))
)
return self.success(img2base64(image))
@@ -156,7 +170,7 @@ class TwoFactorAuthAPI(APIView):
"""
code = request.data["code"]
user = request.user
if OtpAuth(user.tfa_token).valid_totp(code):
if _valid_totp(user.tfa_token, code):
user.two_factor_auth = True
user.save()
return self.success("Succeeded")
@@ -170,7 +184,7 @@ class TwoFactorAuthAPI(APIView):
user = request.user
if not user.two_factor_auth:
return self.error("2FA is already turned off")
if OtpAuth(user.tfa_token).valid_totp(code):
if _valid_totp(user.tfa_token, code):
user.two_factor_auth = False
user.save()
return self.success("Succeeded")
@@ -219,7 +233,7 @@ class UserLoginAPI(APIView):
if user.two_factor_auth and "tfa_code" not in data:
return self.error("tfa_required")
if OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
if _valid_totp(user.tfa_token, data["tfa_code"]):
prev_login = user.last_login
auth.login(request, user)
request.session["prev_login"] = (
@@ -294,7 +308,7 @@ class UserChangeEmailAPI(APIView):
if user.two_factor_auth:
if "tfa_code" not in data:
return self.error("tfa_required")
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
if not _valid_totp(user.tfa_token, data["tfa_code"]):
return self.error("Invalid two factor verification code")
data["new_email"] = data["new_email"].lower()
if User.objects.filter(email=data["new_email"]).exists():
@@ -320,7 +334,7 @@ class UserChangePasswordAPI(APIView):
if user.two_factor_auth:
if "tfa_code" not in data:
return self.error("tfa_required")
if not OtpAuth(user.tfa_token).valid_totp(data["tfa_code"]):
if not _valid_totp(user.tfa_token, data["tfa_code"]):
return self.error("Invalid two factor verification code")
user.set_password(data["new_password"])
user.save()

View File

@@ -1,76 +1,68 @@
annotated-types==0.7.0
anyio==4.12.0
asgiref==3.11.0
attrs==25.4.0
anyio==4.13.0
asgiref==3.11.1
attrs==26.1.0
autobahn==25.12.2
automat==25.4.16
cbor2==5.7.1
certifi==2025.11.12
cbor2==6.0.1
certifi==2026.4.22
cffi==2.0.0
channels==4.3.2
channels-redis==4.3.0
charset-normalizer==3.4.4
charset-normalizer==3.4.7
colorama==0.4.6 ; sys_platform == 'win32'
constantly==23.10.4
coverage==6.5.0
cryptography==46.0.3
cryptography==48.0.0
daphne==4.2.1
distro==1.9.0
django==6.0
django-cas-ng==5.0.1
django-dbconn-retry==0.1.8
django-dramatiq==0.13.0
django-redis==5.4.0
djangorestframework==3.16.0
dramatiq==1.17.0
entrypoints==0.4
envelopes==0.4
flake8==7.0.0
flake8-coding==1.3.2
flake8-quotes==3.3.2
gunicorn==22.0.0
django==6.0.4
django-cas-ng==5.1.1
django-dbconn-retry==0.3.1
django-dramatiq==0.15.0
django-redis==6.0.0
djangorestframework==3.17.1
dramatiq==2.1.0
gunicorn==26.0.0
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
hyperlink==21.0.0
idna==3.11
idna==3.13
incremental==24.11.0
jiter==0.12.0
jsonfield==3.1.0
lxml==6.0.2
mccabe==0.7.0
jiter==0.14.0
lxml==6.1.0
msgpack==1.1.2
openai==2.14.0
otpauth==1.0.1
packaging==25.0
pillow==10.2.0
prometheus-client==0.23.1
psycopg==3.2.9
psycopg-binary==3.2.9
openai==2.34.0
otpauth==2.2.1
packaging==26.2
pillow==12.2.0
psycopg==3.3.4
psycopg-binary==3.3.4
py-ubjson==0.16.1
pyasn1==0.6.1
pyasn1==0.6.3
pyasn1-modules==0.4.2
pycodestyle==2.11.1
pycparser==2.23
pydantic==2.12.5
pydantic-core==2.41.5
pyflakes==3.2.0
pyopenssl==25.3.0
python-cas==1.7.1
python-dateutil==2.8.2
pycparser==3.0 ; implementation_name != 'PyPy'
pydantic==2.13.3
pydantic-core==2.46.3
pyopenssl==26.2.0
python-cas==1.7.2
python-dateutil==2.9.0.post0
qrcode==8.2
raven==6.10.0
redis==7.1.0
requests==2.32.5
redis==7.4.0
requests==2.33.1
sentry-sdk==2.59.0
service-identity==24.2.0
six==1.17.0
sniffio==1.3.1
sqlparse==0.5.5
tqdm==4.67.1
tqdm==4.67.3
twisted==25.5.0
txaio==25.12.2
typing-extensions==4.15.0
typing-inspection==0.4.2
ujson==5.11.0
urllib3==2.6.2
xlsxwriter==3.2.0
zope-interface==8.1.1
tzdata==2026.2 ; sys_platform == 'win32'
u-msgpack-python==2.8.0 ; platform_python_implementation != 'CPython'
ujson==5.12.0
urllib3==2.6.3
xlsxwriter==3.2.9
zope-interface==8.4

View File

@@ -10,9 +10,14 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
import logging
import os
import raven
from copy import deepcopy
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
from utils.shortcuts import get_env
production_env = get_env("OJ_ENV", "dev") == "production"
@@ -40,9 +45,6 @@ VENDOR_APPS = [
"django_dbconn_retry",
]
if production_env:
VENDOR_APPS.append("raven.contrib.django.raven_compat")
LOCAL_APPS = [
"account",
@@ -148,7 +150,19 @@ HITOKOTO_DIR = os.path.join(DATA_DIR, "hitokoto")
STATICFILES_DIRS = [os.path.join(DATA_DIR, "public")]
LOGGING_HANDLERS = ["console", "sentry"] if production_env else ["console"]
SENTRY_DSN = get_env("SENTRY_DSN")
if production_env and SENTRY_DSN:
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[
DjangoIntegration(),
LoggingIntegration(level=logging.INFO, event_level=logging.ERROR),
],
send_default_pii=False,
)
LOGGING_HANDLERS = ["console"]
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
@@ -164,11 +178,6 @@ LOGGING = {
"class": "logging.StreamHandler",
"formatter": "standard",
},
"sentry": {
"level": "ERROR",
"class": "raven.contrib.django.raven_compat.handlers.SentryHandler",
"formatter": "standard",
},
},
"loggers": {
"django.request": {
@@ -256,10 +265,6 @@ DRAMATIQ_RESULT_BACKEND = {
"MIDDLEWARE_OPTIONS": {"result_ttl": None},
}
RAVEN_CONFIG = {
"dsn": "https://b200023b8aed4d708fb593c5e0a6ad3d:1fddaba168f84fcf97e0d549faaeaff0@sentry.io/263057"
}
IP_HEADER = "HTTP_X_REAL_IP"
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"

View File

@@ -5,29 +5,26 @@ description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"channels>=4.2.0",
"channels-redis>=4.2.0",
"daphne>=4.1.2",
"django>=5.2.3",
"django-cas-ng==5.0.1",
"django-dbconn-retry==0.1.8",
"django-dramatiq==0.13.0",
"django-redis==5.4.0",
"djangorestframework==3.16.0",
"dramatiq==1.17.0",
"entrypoints==0.4",
"envelopes==0.4",
"gunicorn==22.0.0",
"jsonfield==3.1.0",
"openai>=1.108.1",
"otpauth==1.0.1",
"pillow==10.2.0",
"psycopg==3.2.9",
"psycopg-binary==3.2.9",
"python-dateutil==2.8.2",
"qrcode==8.2",
"raven==6.10.0",
"xlsxwriter==3.2.0",
"channels>=4.3.2,<5",
"channels-redis>=4.3.0,<5",
"daphne>=4.2.1,<5",
"django>=6.0.4,<6.1",
"django-cas-ng>=5.1.1,<6",
"django-dbconn-retry>=0.3.1,<0.4",
"django-dramatiq>=0.15.0,<0.16",
"django-redis>=6.0.0,<7",
"djangorestframework>=3.17.1,<4",
"dramatiq>=2.1.0,<3",
"gunicorn>=26.0.0,<27",
"openai>=2.34.0,<3",
"otpauth>=2.2.1,<3",
"pillow>=12.2.0,<13",
"psycopg>=3.3.4,<4",
"psycopg-binary>=3.3.4,<4",
"python-dateutil>=2.9.0.post0,<3",
"qrcode>=8.2,<9",
"sentry-sdk[django]>=2.0.0,<3",
"xlsxwriter>=3.2.9,<4",
]
[dependency-groups]

View File

@@ -2,10 +2,12 @@ import os
import random
import re
from base64 import b64encode
from email.utils import formataddr
from io import BytesIO
from django.core.mail import EmailMultiAlternatives, get_connection
from django.utils.crypto import get_random_string
from envelopes import Envelope
from django.utils.html import strip_tags
def rand_str(length=32, type="lower_hex"):
@@ -56,21 +58,29 @@ def datetime2str(value, format="iso-8601"):
return value
return value.strftime(format)
def natural_sort_key(s, _nsre=re.compile(r"(\d+)")):
return [int(text) if text.isdigit() else text.lower()
for text in re.split(_nsre, s)]
def send_email(smtp_config, from_name, to_email, to_name, subject, content):
envelope = Envelope(from_addr=(smtp_config["email"], from_name),
to_addr=(to_email, to_name),
subject=subject,
html_body=content)
return envelope.send(smtp_config["server"],
login=smtp_config["email"],
password=smtp_config["password"],
connection = get_connection(
host=smtp_config["server"],
port=smtp_config["port"],
tls=smtp_config["tls"])
username=smtp_config["email"],
password=smtp_config["password"],
use_tls=smtp_config["tls"],
)
message = EmailMultiAlternatives(
subject=subject,
body=strip_tags(content),
from_email=formataddr((from_name, smtp_config["email"])),
to=[formataddr((to_name, to_email))],
connection=connection,
)
message.attach_alternative(content, "text/html")
return message.send()
def get_env(name, default=""):

1267
uv.lock generated

File diff suppressed because it is too large Load Diff