From c93ae27f32b1b802fc038c16b5df54431eb6c0af Mon Sep 17 00:00:00 2001 From: icurfer Date: Sun, 8 Jun 2025 22:49:39 +0900 Subject: [PATCH] Add, Logger --- auth_prj/settings.py | 58 ++++++++++++++++++++-- users/{views_after.py => _unused_views.py} | 22 ++------ users/views.py | 26 +++++++++- version | 2 +- 4 files changed, 84 insertions(+), 24 deletions(-) rename users/{views_after.py => _unused_views.py} (83%) diff --git a/auth_prj/settings.py b/auth_prj/settings.py index 7c6ae75..4c4bc91 100644 --- a/auth_prj/settings.py +++ b/auth_prj/settings.py @@ -13,19 +13,21 @@ import os from dotenv import load_dotenv from pathlib import Path from datetime import timedelta +import sys # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # 우선순위: .env.dev > .env.prd > .env if os.path.exists(os.path.join(BASE_DIR, '.env.dev')): - print("Read Environment File > Used : .env.dev") + # print("Read Environment File > Used : .env.dev") load_dotenv(os.path.join(BASE_DIR, '.env.dev')) elif os.path.exists(os.path.join(BASE_DIR, '.env.prd')): - print("Read Environment File > Used : .env.prd") + # print("Read Environment File > Used : .env.prd") load_dotenv(os.path.join(BASE_DIR, '.env.prd')) else: - print("None Environment File > Used : local_env") + pass + # print("None Environment File > Used : local_env") # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ @@ -36,6 +38,56 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-ec9me^z%x7-2vwee5#qq( # SECURITY WARNING: don't run with debug turned on in production! DEBUG = int(os.environ.get('DEBUG', 1)) +LOG_LEVEL = "DEBUG" if DEBUG else "INFO" + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, # Django 기본 로거 유지 + 'formatters': { + 'standard': { + 'format': '[{asctime}] {levelname} {name}:{lineno} {message}', + 'style': '{', + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', # 콘솔 출력 + 'formatter': 'standard', + 'stream': sys.stdout, # 표준 출력 스트림 + 'level': LOG_LEVEL, # 콘솔 출력 레벨 설정 + # 'filters': [], # 필터 설정 (필요시 추가) + # 'encoding': 'utf-8', # UTF-8 인코딩 설정 + # 'force': True, # 강제로 콘솔 출력 + }, + }, + 'root': { + 'handlers': ['console'], + 'level': LOG_LEVEL, # 루트 로거 레벨 설정 + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'level': 'INFO', # Django 프레임워크 전반 + 'propagate': False, + }, + 'django.request': { + 'handlers': ['console'], + 'level': 'ERROR', # 요청 관련 에러만 (500 에러 같은 것) + 'propagate': False, + }, + 'django.db.backends': { + 'handlers': ['console'], + 'level': 'WARNING', # DB 쿼리 경고만 + 'propagate': False, + }, + 'django.security': { + 'handlers': ['console'], + 'level': 'WARNING', # 보안 관련 경고 + 'propagate': False, + }, + }, +} + AUTH_VERIFY_URL = os.environ.get('AUTH_VERIFY_URL', 'NONE') ALLOWED_HOSTS = ["*"] diff --git a/users/views_after.py b/users/_unused_views.py similarity index 83% rename from users/views_after.py rename to users/_unused_views.py index 898d6a5..2426b25 100644 --- a/users/views_after.py +++ b/users/_unused_views.py @@ -7,16 +7,6 @@ from rest_framework_simplejwt.views import TokenObtainPairView from .serializers import RegisterSerializer, CustomTokenObtainPairSerializer -# ✅ 2025-05-20 Fernet 암호화 적용 (SECRET_KEY 사용) -from cryptography.fernet import Fernet -from django.conf import settings -import base64, hashlib - -# SECRET_KEY 기반으로 Fernet 키 생성 -hashed = hashlib.sha256(settings.SECRET_KEY.encode()).digest() -fernet_key = base64.urlsafe_b64encode(hashed[:32]) -fernet = Fernet(fernet_key) - class RegisterView(APIView): def post(self, request): @@ -63,14 +53,10 @@ class SSHKeyUploadView(APIView): user = request.user try: - # ✅ 암호화 처리 - encrypted_key = fernet.encrypt(private_key.encode()).decode() - - # ✅ 저장 - user.encrypted_private_key = encrypted_key + # ✅ 모델 메서드로 암호화 저장 처리 + user.save_private_key(private_key) user.encrypted_private_key_name = key_name user.save(update_fields=["encrypted_private_key", "encrypted_private_key_name"]) - return Response({"message": "SSH key 저장 완료."}, status=201) except Exception as e: return Response({"error": f"암호화 또는 저장 실패: {str(e)}"}, status=500) @@ -105,8 +91,8 @@ class SSHKeyRetrieveView(APIView): return Response({"error": "SSH 키가 등록되어 있지 않습니다."}, status=404) try: - # ✅ 복호화 - decrypted_key = fernet.decrypt(user.encrypted_private_key.encode()).decode() + # ✅ 모델 메서드로 복호화 처리 + decrypted_key = user.decrypt_private_key() return Response({"ssh_key": decrypted_key}) except Exception as e: return Response({"error": f"복호화 실패: {str(e)}"}, status=500) diff --git a/users/views.py b/users/views.py index 2426b25..a04ce5c 100644 --- a/users/views.py +++ b/users/views.py @@ -1,4 +1,5 @@ # views.py +import logging # ✅ 로그 추가 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status @@ -7,13 +8,17 @@ from rest_framework_simplejwt.views import TokenObtainPairView from .serializers import RegisterSerializer, CustomTokenObtainPairSerializer +logger = logging.getLogger(__name__) # ✅ 로그 추가 class RegisterView(APIView): def post(self, request): + logger.info("RegisterView POST called. data=%s", request.data) # ✅ 로그 추가 serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() + logger.info("User registered: %s", user.email if hasattr(user, "email") else str(user)) # ✅ 로그 추가 return Response({"message": "User registered successfully."}, status=status.HTTP_201_CREATED) + logger.warning("Registration failed: %s", serializer.errors) # ✅ 로그 추가 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -21,31 +26,41 @@ class MeView(APIView): permission_classes = [IsAuthenticated] def get(self, request): + logger.debug("MeView GET called by user: %s", request.user) # ✅ 로그 추가 user = request.user serializer = RegisterSerializer(user) return Response(serializer.data) def put(self, request): + logger.info("MeView PUT called by user: %s", request.user) # ✅ 로그 추가 user = request.user serializer = RegisterSerializer(user, data=request.data, partial=True) if serializer.is_valid(): serializer.save() + logger.info("User profile updated: %s", request.user) # ✅ 로그 추가 return Response(serializer.data) + logger.warning("Profile update failed: %s", serializer.errors) # ✅ 로그 추가 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class CustomTokenObtainPairView(TokenObtainPairView): serializer_class = CustomTokenObtainPairSerializer + def post(self, request, *args, **kwargs): + logger.info("Login attempt: %s", request.data.get("email")) # ✅ 로그 추가 (비밀번호 제외) + return super().post(request, *args, **kwargs) + class SSHKeyUploadView(APIView): permission_classes = [IsAuthenticated] def post(self, request): + logger.info("SSHKeyUploadView POST called by user: %s", request.user) # ✅ 로그 추가 private_key = request.data.get("private_key") key_name = request.data.get("key_name") if not private_key or not key_name: + logger.warning("Missing SSH key or key name in request") # ✅ 로그 추가 return Response( {"error": "private_key와 key_name 모두 필요합니다."}, status=status.HTTP_400_BAD_REQUEST @@ -53,20 +68,23 @@ class SSHKeyUploadView(APIView): user = request.user try: - # ✅ 모델 메서드로 암호화 저장 처리 user.save_private_key(private_key) user.encrypted_private_key_name = key_name user.save(update_fields=["encrypted_private_key", "encrypted_private_key_name"]) + logger.info("SSH key saved for user: %s", user) # ✅ 로그 추가 return Response({"message": "SSH key 저장 완료."}, status=201) except Exception as e: + logger.exception("SSH key 저장 중 오류 발생") # ✅ 로그 추가 return Response({"error": f"암호화 또는 저장 실패: {str(e)}"}, status=500) def delete(self, request): + logger.info("SSHKeyUploadView DELETE called by user: %s", request.user) # ✅ 로그 추가 user = request.user user.encrypted_private_key = None user.encrypted_private_key_name = None user.last_used_at = None user.save(update_fields=["encrypted_private_key", "encrypted_private_key_name", "last_used_at"]) + logger.info("SSH key deleted for user: %s", user) # ✅ 로그 추가 return Response({"message": "SSH key deleted."}, status=200) @@ -74,6 +92,7 @@ class SSHKeyInfoView(APIView): permission_classes = [IsAuthenticated] def get(self, request): + logger.debug("SSHKeyInfoView GET called by user: %s", request.user) # ✅ 로그 추가 user = request.user return Response({ "has_key": bool(user.encrypted_private_key), @@ -86,13 +105,16 @@ class SSHKeyRetrieveView(APIView): permission_classes = [IsAuthenticated] def get(self, request): + logger.info("SSHKeyRetrieveView GET called by user: %s", request.user) # ✅ 로그 추가 user = request.user if not user.encrypted_private_key: + logger.warning("User tried to retrieve non-existent SSH key: %s", user) # ✅ 로그 추가 return Response({"error": "SSH 키가 등록되어 있지 않습니다."}, status=404) try: - # ✅ 모델 메서드로 복호화 처리 decrypted_key = user.decrypt_private_key() + logger.info("SSH key successfully decrypted for user: %s", user) # ✅ 로그 추가 return Response({"ssh_key": decrypted_key}) except Exception as e: + logger.exception("SSH key 복호화 실패") # ✅ 로그 추가 return Response({"error": f"복호화 실패: {str(e)}"}, status=500) diff --git a/version b/version index b0a1227..7838fb1 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.0.10 \ No newline at end of file +0.0.11_rc1 \ No newline at end of file