From d4409ab595c4281fdf0fbb688ad32ec5c844b5e3 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 15 Jun 2025 10:42:28 +0800 Subject: [PATCH] test for csrf --- announcement/views/oj.py | 7 +- oj/dev_settings.py | 2 + oj/production_settings.py | 19 +++- oj/settings.py | 210 +++++++++++++++++++------------------- tutorial/views/admin.py | 14 +-- 5 files changed, 134 insertions(+), 118 deletions(-) diff --git a/announcement/views/oj.py b/announcement/views/oj.py index ec814eb..f0a3696 100644 --- a/announcement/views/oj.py +++ b/announcement/views/oj.py @@ -1,8 +1,7 @@ from utils.api import APIView from announcement.models import Announcement -from announcement.serializers import (AnnouncementSerializer, - AnnouncementListSerializer) +from announcement.serializers import AnnouncementSerializer, AnnouncementListSerializer class AnnouncementAPI(APIView): @@ -16,4 +15,6 @@ class AnnouncementAPI(APIView): return self.error("Announcement does not exist") announcements = Announcement.objects.filter(visible=True) - return self.success(self.paginate_data(request, announcements, AnnouncementListSerializer)) + return self.success( + self.paginate_data(request, announcements, AnnouncementListSerializer) + ) diff --git a/oj/dev_settings.py b/oj/dev_settings.py index 6dba915..6f94409 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -21,4 +21,6 @@ DEBUG = True ALLOWED_HOSTS = ["*"] +CSRF_TRUSTED_ORIGINS = ["http://localhost:5173"] + DATA_DIR = f"{BASE_DIR}/data" diff --git a/oj/production_settings.py b/oj/production_settings.py index 467b35b..dc05ca9 100644 --- a/oj/production_settings.py +++ b/oj/production_settings.py @@ -18,6 +18,23 @@ REDIS_CONF = { DEBUG = False -ALLOWED_HOSTS = ["*"] +ALLOWED_HOSTS = [ + "localhost", + "127.0.0.1", + "oj.xuyue.cc", + "ojtest.xuyue.cc", + "10.13.114.114", + "150.158.29.156", +] + +CSRF_TRUSTED_ORIGINS = [ + "http://localhost:5173", + "http://localhost:9005", # health check + "http://127.0.0.1:5173", + "https://oj.xuyue.cc", + "https://ojtest.xuyue.cc", + "http://10.13.114.114:81", + "http://150.158.29.156:8881", +] DATA_DIR = "/data" diff --git a/oj/settings.py b/oj/settings.py index cc3ac48..2381d67 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -9,6 +9,7 @@ https://docs.djangoproject.com/en/1.8/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ + import os import raven from copy import deepcopy @@ -27,93 +28,93 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Applications VENDOR_APPS = [ - 'django.contrib.auth', - 'django.contrib.sessions', - 'django.contrib.contenttypes', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', - 'django_dramatiq', - 'django_dbconn_retry', + "django.contrib.auth", + "django.contrib.sessions", + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", + "django_dramatiq", + "django_dbconn_retry", ] if production_env: - VENDOR_APPS.append('raven.contrib.django.raven_compat') + VENDOR_APPS.append("raven.contrib.django.raven_compat") LOCAL_APPS = [ - 'account', - 'announcement', - 'conf', - 'problem', - 'contest', - 'utils', - 'submission', - 'options', - 'judge', - 'message', - 'comment', - 'tutorial', + "account", + "announcement", + "conf", + "problem", + "contest", + "utils", + "submission", + "options", + "judge", + "message", + "comment", + "tutorial", ] INSTALLED_APPS = VENDOR_APPS + LOCAL_APPS MIDDLEWARE = ( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'account.middleware.APITokenAuthMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'account.middleware.AdminRoleRequiredMiddleware', - 'account.middleware.SessionRecordMiddleware', + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "account.middleware.APITokenAuthMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.security.SecurityMiddleware", + "account.middleware.AdminRoleRequiredMiddleware", + "account.middleware.SessionRecordMiddleware", # 'account.middleware.LogSqlMiddleware', ) -ROOT_URLCONF = 'oj.urls' +ROOT_URLCONF = "oj.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'oj.wsgi.application' +WSGI_APPLICATION = "oj.wsgi.application" # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -124,9 +125,9 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ -STATIC_URL = '/public/' +STATIC_URL = "/public/" -AUTH_USER_MODEL = 'account.User' +AUTH_USER_MODEL = "account.User" TEST_CASE_DIR = os.path.join(DATA_DIR, "test_case") LOG_PATH = os.path.join(DATA_DIR, "log") @@ -142,57 +143,55 @@ 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'] +LOGGING_HANDLERS = ["console", "sentry"] if production_env else ["console"] LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'standard': { - 'format': '[%(asctime)s] - [%(levelname)s] - [%(name)s:%(lineno)d] - %(message)s', - 'datefmt': '%Y-%m-%d %H:%M:%S' - } - }, - 'handlers': { - 'console': { - 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'standard' - }, - 'sentry': { - 'level': 'ERROR', - 'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler', - 'formatter': 'standard' - } - }, - 'loggers': { - 'django.request': { - 'handlers': LOGGING_HANDLERS, - 'level': 'ERROR', - 'propagate': True, - }, - 'django.db.backends': { - 'handlers': LOGGING_HANDLERS, - 'level': 'ERROR', - 'propagate': True, - }, - 'dramatiq': { - 'handlers': LOGGING_HANDLERS, - 'level': 'DEBUG', - 'propagate': False, + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "[%(asctime)s] - [%(levelname)s] - [%(name)s:%(lineno)d] - %(message)s", + "datefmt": "%Y-%m-%d %H:%M:%S", + } + }, + "handlers": { + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "standard", }, - '': { - 'handlers': LOGGING_HANDLERS, - 'level': 'WARNING', - 'propagate': True, - } - }, + "sentry": { + "level": "ERROR", + "class": "raven.contrib.django.raven_compat.handlers.SentryHandler", + "formatter": "standard", + }, + }, + "loggers": { + "django.request": { + "handlers": LOGGING_HANDLERS, + "level": "ERROR", + "propagate": True, + }, + "django.db.backends": { + "handlers": LOGGING_HANDLERS, + "level": "ERROR", + "propagate": True, + }, + "dramatiq": { + "handlers": LOGGING_HANDLERS, + "level": "DEBUG", + "propagate": False, + }, + "": { + "handlers": LOGGING_HANDLERS, + "level": "WARNING", + "propagate": True, + }, + }, } REST_FRAMEWORK = { - 'TEST_REQUEST_DEFAULT_FORMAT': 'json', - 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.JSONRenderer', - ) + "TEST_REQUEST_DEFAULT_FORMAT": "json", + "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",), } REDIS_URL = "redis://%s:%s" % (REDIS_CONF["host"], REDIS_CONF["port"]) @@ -207,13 +206,12 @@ def redis_config(db): "LOCATION": f"{REDIS_URL}/{db}", "TIMEOUT": None, "KEY_PREFIX": "", - "KEY_FUNCTION": make_key + "KEY_FUNCTION": make_key, } + if production_env: - CACHES = { - "default": redis_config(db=1) - } + CACHES = {"default": redis_config(db=1)} SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default" @@ -230,8 +228,8 @@ DRAMATIQ_BROKER = { "dramatiq.middleware.Callbacks", "dramatiq.middleware.Retries", # "django_dramatiq.middleware.AdminMiddleware", - "django_dramatiq.middleware.DbConnectionsMiddleware" - ] + "django_dramatiq.middleware.DbConnectionsMiddleware", + ], } DRAMATIQ_RESULT_BACKEND = { @@ -239,15 +237,13 @@ DRAMATIQ_RESULT_BACKEND = { "BACKEND_OPTIONS": { "url": f"{REDIS_URL}/4", }, - "MIDDLEWARE_OPTIONS": { - "result_ttl": None - } + "MIDDLEWARE_OPTIONS": {"result_ttl": None}, } RAVEN_CONFIG = { - 'dsn': 'https://b200023b8aed4d708fb593c5e0a6ad3d:1fddaba168f84fcf97e0d549faaeaff0@sentry.io/263057' + "dsn": "https://b200023b8aed4d708fb593c5e0a6ad3d:1fddaba168f84fcf97e0d549faaeaff0@sentry.io/263057" } IP_HEADER = "HTTP_X_REAL_IP" -DEFAULT_AUTO_FIELD='django.db.models.AutoField' \ No newline at end of file +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/tutorial/views/admin.py b/tutorial/views/admin.py index 13df52a..23becf9 100644 --- a/tutorial/views/admin.py +++ b/tutorial/views/admin.py @@ -1,17 +1,17 @@ from rest_framework import viewsets, permissions -from account.decorators import super_admin_required from ..models import Tutorial from ..serializers import TutorialSerializer + +class IsSuperAdminUser(permissions.BasePermission): + def has_permission(self, request, view): + return bool(request.user and request.user.is_super_admin()) + + class AdminTutorialViewSet(viewsets.ModelViewSet): queryset = Tutorial.objects.all() serializer_class = TutorialSerializer - permission_classes = [permissions.IsAuthenticated] - - def get_permissions(self): - if self.action in ['create', 'update', 'partial_update', 'destroy']: - return [super_admin_required()] - return [permissions.AllowAny()] + permission_classes = [IsSuperAdminUser] def perform_create(self, serializer): serializer.save(created_by=self.request.user) \ No newline at end of file