diff --git a/account/middleware.py b/account/middleware.py index 1ef78ccf..245c32a0 100644 --- a/account/middleware.py +++ b/account/middleware.py @@ -3,6 +3,18 @@ from django.utils.timezone import now from django.utils.deprecation import MiddlewareMixin from utils.api import JSONResponse +from account.models import User + + +class APITokenAuthMiddleware(MiddlewareMixin): + def process_request(self, request): + appkey = request.META.get("HTTP_APPKEY") + if appkey: + try: + request.user = User.objects.get(open_api_appkey=appkey, open_api=True, is_disabled=False) + request.csrf_processing_done = True + except User.DoesNotExist: + pass class SessionRecordMiddleware(MiddlewareMixin): diff --git a/account/tests.py b/account/tests.py index 43a09fe2..97880aac 100644 --- a/account/tests.py +++ b/account/tests.py @@ -611,3 +611,19 @@ class GenerateUserAPITest(APITestCase): resp = self.client.post(self.url, data=self.data) self.assertSuccess(resp) mock_workbook.assert_called() + + +class OpenAPIAppkeyAPITest(APITestCase): + def setUp(self): + self.user = self.create_super_admin() + self.url = self.reverse("open_api_appkey_api") + + def test_reset_appkey(self): + resp = self.client.post(self.url, data={}) + self.assertFailed(resp) + + self.user.open_api = True + self.user.save() + resp = self.client.post(self.url, data={}) + self.assertSuccess(resp) + self.assertEqual(resp.data["data"]["appkey"], User.objects.get(username=self.user.username).open_api_appkey) diff --git a/account/urls/oj.py b/account/urls/oj.py index a92dd5be..1b26e14c 100644 --- a/account/urls/oj.py +++ b/account/urls/oj.py @@ -5,7 +5,7 @@ from ..views.oj import (ApplyResetPasswordAPI, ResetPasswordAPI, UserLoginAPI, UserLogoutAPI, UsernameOrEmailCheck, AvatarUploadAPI, TwoFactorAuthAPI, UserProfileAPI, UserRankAPI, CheckTFARequiredAPI, SessionManagementAPI, - ProfileProblemDisplayIDRefreshAPI) + ProfileProblemDisplayIDRefreshAPI, OpenAPIAppkeyAPI) from utils.captcha.views import CaptchaAPIView @@ -25,5 +25,6 @@ urlpatterns = [ url(r"^tfa_required/?$", CheckTFARequiredAPI.as_view(), name="tfa_required_check"), url(r"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api"), url(r"^user_rank/?$", UserRankAPI.as_view(), name="user_rank_api"), - url(r"^sessions/?$", SessionManagementAPI.as_view(), name="session_management_api") + url(r"^sessions/?$", SessionManagementAPI.as_view(), name="session_management_api"), + url(r"^open_api_appkey/?$", OpenAPIAppkeyAPI.as_view(), name="open_api_appkey_api"), ] diff --git a/account/views/oj.py b/account/views/oj.py index 344a4196..5f258178 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -401,3 +401,15 @@ class ProfileProblemDisplayIDRefreshAPI(APIView): v["_id"] = id_map[k] profile.save(update_fields=["acm_problems_status", "oi_problems_status"]) return self.success() + + +class OpenAPIAppkeyAPI(APIView): + @login_required + def post(self, request): + user = request.user + if not user.open_api: + return self.error("Permission denied") + api_appkey = rand_str() + user.open_api_appkey = api_appkey + user.save() + return self.success({"appkey": api_appkey}) diff --git a/oj/settings.py b/oj/settings.py index d1ab2115..43aa1d6f 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -49,6 +49,7 @@ MIDDLEWARE_CLASSES = ( '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',