Claude commited on
Commit
02c069f
·
unverified ·
1 Parent(s): 3667292

fix: IPv6 IP 익명화 지원 추가 (anonymize_ip 공통 함수)

Browse files

IPv4만 처리하던 익명화 로직을 IPv6도 지원하도록 개선.
utils.py에 anonymize_ip() 공통 함수 추가,
app.py, opinion_change.py에서 해당 함수 사용.

https://claude.ai/code/session_016DE3uHLsVmA5Uv7gZGGaKT

Files changed (3) hide show
  1. app.py +2 -3
  2. components/opinion_change.py +1 -1
  3. 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
- parts = client_ip.split(".")
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",