diff --git a/src/renatoxsr-py/utils/zwid.py b/src/renatoxsr-py/utils/zwid.py new file mode 100644 index 0000000..64c9528 --- /dev/null +++ b/src/renatoxsr-py/utils/zwid.py @@ -0,0 +1,72 @@ +import base64 + +# Marcadores de fronteira (Não alteram o visual do texto) +ZW_START = '\u200a' # Hair Space (usado como marcador de início) +ZW_END = '\u202f' # Narrow No-Break Space (usado como marcador de fim) + +# Lista com exatamente 32 caracteres invisíveis para os dados (Base32) +ZW_CHARS = [ + '\u200b', '\u200c', '\u200d', '\ufeff', '\u200e', '\u200f', '\u202a', '\u202b', + '\u202c', '\u202d', '\u202e', '\u2060', '\u2061', '\u2062', '\u2063', '\u2064', + '\u2066', '\u2067', '\u2068', '\u2069', '\u206a', '\u206b', '\u206c', '\u206d', + '\u206e', '\u206f', '\ufe00', '\ufe01', '\ufe02', '\ufe03', '\ufe04', '\ufe05', +] + +B32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" + +# Mapeamentos para conversão rápida +B32_TO_ZW = {B32_ALPHABET[i]: ZW_CHARS[i] for i in range(32)} +ZW_TO_B32 = {ZW_CHARS[i]: B32_ALPHABET[i] for i in range(32)} + +def ocultar_texto(texto_visivel: str, texto_oculto: str) -> str: + """Codifica o texto oculto e o envelopa com marcadores de início e fim.""" + # Converte o texto oculto para Base32 sem padding + b32_data = base64.b32encode(texto_oculto.encode('utf-8')).decode('utf-8').replace('=', '') + + # Converte para a sequência invisível e adiciona as fronteiras START e END + zw_encoded = ZW_START + "".join(B32_TO_ZW[char] for char in b32_data) + ZW_END + + # Insere o bloco invisível de forma segura no início do texto visível + return zw_encoded + texto_visivel + +def revelar_texto(texto_com_marca: str) -> str: + """Localiza os marcadores de início e fim para extrair e decodificar o payload.""" + # Encontra os índices dos delimitadores + try: + inicio = texto_com_marca.index(ZW_START) + 1 + fim = texto_com_marca.index(ZW_END, inicio) + except ValueError: + return "" # Marcadores não encontrados ou incompletos + + # Extrai apenas o bloco que está estritamente entre o início e o fim + bloco_invisivel = texto_com_marca[inicio:fim] + + # Filtra apenas os caracteres válidos do nosso alfabeto de dados + zw_extraido = [char for char in bloco_invisivel if char in ZW_TO_B32] + + # Reconstrói a string Base32 + b32_data = "".join(ZW_TO_B32[char] for char in zw_extraido) + + if not b32_data: + return "" + + # Ajusta o padding do Base32 + mod = len(b32_data) % 8 + if mod: + b32_data += '=' * (8 - mod) + + return base64.b32decode(b32_data.encode('utf-8')).decode('utf-8') + +# --- Exemplo de Uso --- +if __name__ == "__main__": + texto_original = "Mensagem importante que será enviada ao cliente." + id_secreto = "ID-999-STRICT" + + # Injetando + texto_com_payload = ocultar_texto(texto_original, id_secreto) + print(f"Texto gerado (Total de caracteres: {len(texto_com_payload)}):") + print(f"-> {texto_com_payload} <-\n") + + # Extraindo + id_descoberto = revelar_texto(texto_com_payload) + print(f"ID isolado e extraído com sucesso: '{id_descoberto}'")