54 lines
1.3 KiB
Python
54 lines
1.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import re
|
||
|
|
|
||
|
|
_IRC_CONTROL_START = 0x00
|
||
|
|
_IRC_CONTROL_END = 0x1F
|
||
|
|
_IRC_DEL = 0x7F
|
||
|
|
|
||
|
|
_LITERAL_ESCAPE_PATTERN = re.compile(r"\\x[0-9a-fA-F]{2}")
|
||
|
|
|
||
|
|
|
||
|
|
def is_irc_control_char(ch: str) -> bool:
|
||
|
|
if len(ch) != 1:
|
||
|
|
return False
|
||
|
|
cp = ord(ch)
|
||
|
|
return cp < 0x20 or cp == 0x7F
|
||
|
|
|
||
|
|
|
||
|
|
def has_irc_control_chars(text: str) -> bool:
|
||
|
|
return any(is_irc_control_char(c) for c in text)
|
||
|
|
|
||
|
|
|
||
|
|
def strip_irc_control_chars(text: str) -> str:
|
||
|
|
return "".join(c for c in text if not is_irc_control_char(c))
|
||
|
|
|
||
|
|
|
||
|
|
def decode_literal_escapes(text: str) -> str:
|
||
|
|
"""Strip literal escape sequences (\\xNN) from inbound text.
|
||
|
|
|
||
|
|
Prevents attackers from injecting IRC control characters via literal
|
||
|
|
backslash-x escape representations (e.g. \\x01 for CTCP delimiter).
|
||
|
|
"""
|
||
|
|
return _LITERAL_ESCAPE_PATTERN.sub("", text)
|
||
|
|
|
||
|
|
|
||
|
|
def has_literal_escapes(text: str) -> bool:
|
||
|
|
return bool(_LITERAL_ESCAPE_PATTERN.search(text))
|
||
|
|
|
||
|
|
|
||
|
|
def sanitize_outbound_text(text: str) -> str:
|
||
|
|
text = text.replace("\n", " ").replace("\r", " ")
|
||
|
|
return strip_irc_control_chars(text)
|
||
|
|
|
||
|
|
|
||
|
|
def sanitize_inbound_text(text: str) -> str:
|
||
|
|
text = decode_literal_escapes(text)
|
||
|
|
return strip_irc_control_chars(text)
|
||
|
|
|
||
|
|
|
||
|
|
def sanitize_irc_target(target: str) -> str:
|
||
|
|
cleaned = strip_irc_control_chars(target)
|
||
|
|
cleaned = cleaned.replace(" ", "_")
|
||
|
|
return cleaned
|