Spaces:
Runtime error
Runtime error
Claude commited on
fix: IPv6 IP 익명화 지원 추가 (anonymize_ip 공통 함수)
Browse filesIPv4만 처리하던 익명화 로직을 IPv6도 지원하도록 개선.
utils.py에 anonymize_ip() 공통 함수 추가,
app.py, opinion_change.py에서 해당 함수 사용.
https://claude.ai/code/session_016DE3uHLsVmA5Uv7gZGGaKT
- app.py +2 -3
- components/opinion_change.py +1 -1
- utils.py +20 -1
app.py
CHANGED
|
@@ -18,7 +18,7 @@ from db import (
|
|
| 18 |
using_service_role_key,
|
| 19 |
)
|
| 20 |
from config import APP_CSS, MAX_STUDENT_NAME_LEN
|
| 21 |
-
from utils import get_client_ip, get_kst_now_str, log_audit
|
| 22 |
from validators import validate_opinion_content, validate_student_name
|
| 23 |
from views.home import render_home_page
|
| 24 |
from views.lobby import render_lobby_page
|
|
@@ -206,8 +206,7 @@ def _render_opinion_input(supabase, room_name, user_role, student_name, student_
|
|
| 206 |
"content": safe_input, "sentiment": sentiment, "author_role": author_role_for_submit,
|
| 207 |
}
|
| 208 |
if debate_ip_column_available() and client_ip:
|
| 209 |
-
|
| 210 |
-
anonymized_ip = f"{parts[0]}.0.0.{parts[3]}" if len(parts) == 4 else None
|
| 211 |
if anonymized_ip:
|
| 212 |
insert_payload["ip_address"] = anonymized_ip
|
| 213 |
try:
|
|
|
|
| 18 |
using_service_role_key,
|
| 19 |
)
|
| 20 |
from config import APP_CSS, MAX_STUDENT_NAME_LEN
|
| 21 |
+
from utils import anonymize_ip, get_client_ip, get_kst_now_str, log_audit
|
| 22 |
from validators import validate_opinion_content, validate_student_name
|
| 23 |
from views.home import render_home_page
|
| 24 |
from views.lobby import render_lobby_page
|
|
|
|
| 206 |
"content": safe_input, "sentiment": sentiment, "author_role": author_role_for_submit,
|
| 207 |
}
|
| 208 |
if debate_ip_column_available() and client_ip:
|
| 209 |
+
anonymized_ip = anonymize_ip(client_ip)
|
|
|
|
| 210 |
if anonymized_ip:
|
| 211 |
insert_payload["ip_address"] = anonymized_ip
|
| 212 |
try:
|
components/opinion_change.py
CHANGED
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
| 3 |
import streamlit as st
|
| 4 |
|
| 5 |
from config import AI_MODEL_NAME, LIVE_BOARD_FETCH_LIMIT
|
| 6 |
-
from utils import create_analysis_image, get_client_ip
|
| 7 |
from db import (
|
| 8 |
ai_feedback_available,
|
| 9 |
fetch_live_messages,
|
|
|
|
| 3 |
import streamlit as st
|
| 4 |
|
| 5 |
from config import AI_MODEL_NAME, LIVE_BOARD_FETCH_LIMIT
|
| 6 |
+
from utils import anonymize_ip, create_analysis_image, get_client_ip
|
| 7 |
from db import (
|
| 8 |
ai_feedback_available,
|
| 9 |
fetch_live_messages,
|
utils.py
CHANGED
|
@@ -66,7 +66,6 @@ def get_client_ip():
|
|
| 66 |
raw_ip = headers.get(key)
|
| 67 |
if raw_ip:
|
| 68 |
return str(raw_ip).split(",")[0].strip()
|
| 69 |
-
# 헤더에서 IP를 찾지 못한 경우 사용 가능한 헤더 목록을 로그로 남김
|
| 70 |
try:
|
| 71 |
all_keys = list(headers.keys()) if headers else []
|
| 72 |
logger.info("get_client_ip: IP 헤더 없음. 수신된 헤더 키: %s", all_keys)
|
|
@@ -75,6 +74,26 @@ def get_client_ip():
|
|
| 75 |
return ""
|
| 76 |
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
def log_audit(event, room_name="", actor_name="", role="", **extra):
|
| 79 |
logger.info(
|
| 80 |
"AUDIT event=%s room=%s actor=%s role=%s extra=%s",
|
|
|
|
| 66 |
raw_ip = headers.get(key)
|
| 67 |
if raw_ip:
|
| 68 |
return str(raw_ip).split(",")[0].strip()
|
|
|
|
| 69 |
try:
|
| 70 |
all_keys = list(headers.keys()) if headers else []
|
| 71 |
logger.info("get_client_ip: IP 헤더 없음. 수신된 헤더 키: %s", all_keys)
|
|
|
|
| 74 |
return ""
|
| 75 |
|
| 76 |
|
| 77 |
+
def anonymize_ip(raw_ip: str) -> str | None:
|
| 78 |
+
"""IP를 익명화하여 반환합니다. 저장 불가 시 None 반환.
|
| 79 |
+
|
| 80 |
+
IPv4: 첫 번째·마지막 옥텟 유지, 중간 0으로 대체 (예: 165.0.0.41)
|
| 81 |
+
IPv6: 앞 4그룹(64비트 프리픽스) 유지, 나머지 :: 처리 (예: 2406:5900:117c:424b::)
|
| 82 |
+
"""
|
| 83 |
+
ip = str(raw_ip or "").strip()
|
| 84 |
+
if not ip:
|
| 85 |
+
return None
|
| 86 |
+
if ":" in ip: # IPv6
|
| 87 |
+
groups = ip.split(":")
|
| 88 |
+
if len(groups) >= 4:
|
| 89 |
+
return ":".join(groups[:4]) + "::"
|
| 90 |
+
return None
|
| 91 |
+
parts = ip.split(".") # IPv4
|
| 92 |
+
if len(parts) == 4:
|
| 93 |
+
return f"{parts[0]}.0.0.{parts[3]}"
|
| 94 |
+
return None
|
| 95 |
+
|
| 96 |
+
|
| 97 |
def log_audit(event, room_name="", actor_name="", role="", **extra):
|
| 98 |
logger.info(
|
| 99 |
"AUDIT event=%s room=%s actor=%s role=%s extra=%s",
|