
    i                     h   d Z ddlZddlZddlZddlmZmZ g dZ ej                  ddj                  e      z   dz         Z
dZ ej                  d	e d
ej                        ZdZ ej                  de dej                        Z ej                  dej                        Z ej                  d      Z ej                  d      Z ej                  dej                        Z ej                  d      ZdedefdZdedefdZ G d dej0                        Zddej4                  dz  ddfdZy)u  런타임 비밀 마스킹 - 로그 및 출력에서 자격증명 자동 제거.

로그 메시지가 파일이나 콘솔에 기록되기 전 API 키, 토큰, 비밀번호 등의
민감 정보를 정규식 패턴으로 감지하여 마스킹합니다.

짧은 토큰(18자 미만)은 *** 로 완전 치환, 긴 토큰은 앞 6자 + ... + 뒤 4자 형식으로
일부 보존하여 디버깅 가능성을 유지합니다.

환경변수 DISABLE_REDACT_SECRETS=1 로 비활성화 가능합니다.

Usage:
    from utils.redact import setup_redacted_logging
    setup_redacted_logging()          # 루트 로거에 적용
    setup_redacted_logging(logger)    # 특정 로거에 적용
    N)Literalcast)zsk-[A-Za-z0-9_-]{10,}zghp_[A-Za-z0-9]{10,}zgithub_pat_[A-Za-z0-9_]{10,}zxox[baprs]-[A-Za-z0-9-]{10,}zAIza[A-Za-z0-9_-]{30,}zpplx-[A-Za-z0-9]{10,}zfal_[A-Za-z0-9_-]{10,}zfc-[A-Za-z0-9]{10,}zbb_live_[A-Za-z0-9_-]{10,}zgAAAA[A-Za-z0-9_=-]{20,}zAKIA[A-Z0-9]{16}zsk_live_[A-Za-z0-9]{10,}zsk_test_[A-Za-z0-9]{10,}zrk_live_[A-Za-z0-9]{10,}zSG\.[A-Za-z0-9_-]{10,}zhf_[A-Za-z0-9]{10,}zr8_[A-Za-z0-9]{10,}znpm_[A-Za-z0-9]{10,}zpypi-[A-Za-z0-9_-]{10,}zdop_v1_[A-Za-z0-9]{10,}zdoo_v1_[A-Za-z0-9]{10,}zam_[A-Za-z0-9_-]{10,}z(?<![A-Za-z0-9_-])(|z)(?![A-Za-z0-9_-])z9(?:API_?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)z([A-Z_]*z[A-Z_]*)\s*=\s*(['\"]?)(\S+)\2z(?:api_?[Kk]ey|token|secret|password|access_token|refresh_token|auth_token|bearer|secret_value|raw_secret|secret_input|key_material)z("z")\s*:\s*"([^"]+)"z!(Authorization:\s*Bearer\s+)(\S+)z#(bot)?(\d{8,}):([-A-Za-z0-9_]{30,})zH-----BEGIN[A-Z ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z ]*PRIVATE KEY-----zK((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp)://[^:]+:)([^@]+)(@)z (\+[1-9]\d{6,14})(?![A-Za-z0-9])tokenreturnc                 :    t        |       dk  ry| dd  d| dd  S )uJ   토큰 마스킹: 18자 미만은 ***, 이상은 앞6 + ... + 뒤4 보존.   ***N   z...)len)r   s    =/home/jay/workspace/.worktrees/task-2116-dev1/utils/redact.py_mask_tokenr   ]   s-    
5zBBQi[E"#J<((    textc                    | yt        | t              st        |       } | s| S t        j                  dd      j	                         dv r| S t
        j                  d |       } dt        j                  t           dt        fd}t        j                  ||       } dt        j                  t           dt        fd	}t        j                  ||       } t        j                  d
 |       } dt        j                  t           dt        fd}t        j                  ||       } t        j                  d|       } t        j                  d |       } dt        j                  t           dt        fd}t        j                  ||       } | S )u   텍스트에서 민감 정보를 감지하여 마스킹합니다.

    DISABLE_REDACT_SECRETS=1 환경변수로 비활성화 가능합니다.
    None 입력은 None 반환, 비문자열은 str()로 변환합니다.
    NDISABLE_REDACT_SECRETS )1trueyesonc                 6    t        | j                  d            S )N   )r   groupms    r   <lambda>z'redact_sensitive_text.<locals>.<lambda>t   s    K
$; r   r   r   c                     | j                  d      | j                  d      | j                  d      }}}| d| t        |       | S )Nr         =r   r   )r   namequotevalues       r   _redact_envz*redact_sensitive_text.<locals>._redact_envw   sF    WWQZQWWQZUeqE 23E7;;r   c                 h    | j                  d      | j                  d      }}| dt        |       dS )Nr   r    z: ""r#   )r   keyr&   s      r   _redact_jsonz+redact_sensitive_text.<locals>._redact_json~   s4    WWQZUc+e,-Q//r   c                 Z    | j                  d      t        | j                  d            z   S )Nr   r    r#   r   s    r   r   z'redact_sensitive_text.<locals>.<lambda>   s     !''!*{1771:66 r   c                 \    | j                  d      xs d}| j                  d      }| | dS )Nr   r   r    z:***r   )r   prefixdigitss      r   _redact_telegramz/redact_sensitive_text.<locals>._redact_telegram   s2    !r&&&r   z[REDACTED PRIVATE KEY]c                 L    | j                  d       d| j                  d       S )Nr   r
   r!   r.   r   s    r   r   z'redact_sensitive_text.<locals>.<lambda>   s!    1771:,c!''!*(F r   c                 x    | j                  d      }t        |      dk  r|d d dz   |dd  z   S |d d dz   |dd  z   S )Nr      r    z****   r   )r   r   )r   phones     r   _redact_phonez,redact_sensitive_text.<locals>._redact_phone   sR    
u:?!9v%bc
22Ray6!E"#J..r   )
isinstancestrosgetenvlower
_PREFIX_REsubreMatch_ENV_ASSIGN_RE_JSON_FIELD_RE_AUTH_HEADER_RE_TELEGRAM_RE_PRIVATE_KEY_RE_DB_CONNSTR_RE	_PHONE_RE)r   r'   r+   r1   r8   s        r   redact_sensitive_textrI   d   s_    |dC 4y	yy)2.446:TT >>;TBD<rxx} < < k40D0 0# 0 lD1D 6D'BHHSM 'c '
 ,d3D 7>D FMD/# /3 / ==-DKr   c                   @     e Zd ZdZdej
                  def fdZ xZS )RedactingFormatteru  민감 정보를 자동으로 마스킹하는 로그 포맷터.

    기존 Formatter 위에 래핑하여 format() 출력 결과를 redact_sensitive_text()로 후처리합니다.
    기존 format 문자열, datefmt, style 설정을 모두 그대로 유지합니다.
    recordr   c                 8    t         |   |      }t        |      S N)superformatrI   )selfrL   original	__class__s      r   rP   zRedactingFormatter.format   s    7>&)$X..r   )	__name__
__module____qualname____doc__logging	LogRecordr:   rP   __classcell__)rS   s   @r   rK   rK      s&    /W.. /3 / /r   rK   loggerc                    | | nt        j                         }|j                  D ]  }|j                  }|{t	        |t
              skdddd}t        |j                        j                  }|j                  |d      }t        |j                  |j                  |      }|j                  |       ||j                  t                       y)u  지정된 로거(또는 루트 로거)의 모든 핸들러에 RedactingFormatter를 적용합니다.

    기존 Formatter 설정(fmt, datefmt, style)을 그대로 유지하면서
    RedactingFormatter로 교체합니다. 핸들러에 formatter가 없는 경우
    기본 RedactingFormatter를 새로 생성하여 적용합니다.

    utils/logger.py의 get_logger()로 생성한 로거와 호환됩니다.

    Args:
        logger: RedactingFormatter를 적용할 로거. None이면 루트 로거 사용.
    N%{$)PercentStyleStrFormatStyleStringTemplateStyle)fmtdatefmtstyle)rX   	getLoggerhandlers	formatterr9   rK   type_stylerT   get_fmtrd   setFormatter)r[   targethandlerexisting	style_map
style_type
style_char	redactings           r   setup_redacted_loggingru      s     )Vw/@/@/BF?? 7$$
8=O(P !$"%'*<I
 hoo.77J"z37J*MM (( I
   +  !3!56'7r   rN   )rW   rX   r;   r@   typingr   r   _PREFIX_PATTERNScompilejoinr>   _SECRET_ENV_NAMES
IGNORECASErB   _JSON_KEY_NAMESrC   rD   rE   rF   rG   rH   r:   r   rI   	FormatterrK   Loggerru    r   r   <module>r      sq     	 	  
 2 RZZ.:J1KKNccd
 Q !""@AMMM  	/	,-MM "**(MM rzz*
 "**hi RMM BJJ:;	)s )s )= = =@	/** 	/ 77>>D#8  7D  7r   