11#!/usr/bin/env python3
22
33import argparse as ap
4+ import json
45from pathlib import Path
5- from regex import DOTALL , MULTILINE , match , sub , findall
6- from typing import Union
76from random import choice
7+ from typing import Union
8+
9+ from regex import DOTALL , MULTILINE , findall , match , sub
810
911
1012def parse_args ():
@@ -19,6 +21,11 @@ def parse_args():
1921 )
2022 parser .add_argument ("input" , type = str , help = "Input Groovy Script" )
2123 parser .add_argument ("output" , type = str , help = "Output FileBot File" )
24+ parser .add_argument (
25+ "--forget" ,
26+ action = "store_true" ,
27+ help = "Do not use or save keyword mapping from .compiler.keywords.json" ,
28+ )
2229 return parser .parse_args ()
2330
2431
@@ -123,7 +130,7 @@ def resolve_imports(script_path: Union[str, Path]) -> str:
123130 import_path = Path (script_path ).parent / match (
124131 r"^@(.*\.groovy)" , line
125132 ).group (1 )
126- print (f" @ { script_path } :{ i + 1 } <- { import_path .absolute ()} " )
133+ print (f" @ { script_path } :{ i + 1 } <- { import_path .absolute ()} " )
127134 sli [i ] = resolve_imports (import_path )
128135
129136 return "" .join (sli )
@@ -188,18 +195,51 @@ def clean_characters(text: str) -> str:
188195 return text
189196
190197
191- def obfuscate_variables (text : str ) -> str :
198+ def load_keyword_mapping (json_path : Path ) -> dict [str , str ]:
199+ """
200+ Load keyword mapping from JSON file
201+
202+ Args:
203+ json_path (Path): Path to JSON file
204+
205+ Returns:
206+ dict[str, str]: Keyword mapping
207+ """
208+ if json_path .exists ():
209+ with open (json_path , "r" , encoding = "utf8" ) as f :
210+ return json .load (f )
211+ return {}
212+
213+
214+ def save_keyword_mapping (json_path : Path , mapping : dict [str , str ]) -> None :
215+ """
216+ Save keyword mapping to JSON file
217+
218+ Args:
219+ json_path (Path): Path to JSON file
220+ mapping (dict[str, str]): Keyword mapping to save
221+ """
222+ with open (json_path , "w" , encoding = "utf8" ) as f :
223+ json .dump (mapping , f , ensure_ascii = False )
224+
225+
226+ def obfuscate_variables (text : str , use_json : bool = True ) -> str :
192227 """
193228 Obfuscate variables in the input text, replacing them with 1-3 character strings.
194229
195230 Args:
196231 text (str): Text to sanitize
232+ use_json (bool): Whether to use external keyword mapping file
197233
198234 Returns:
199235 str: Sanitized text
200236 """
237+ json_path = Path (".compiler.keywords.json" )
201238
202- variables = {}
239+ if use_json :
240+ variables = load_keyword_mapping (json_path )
241+ else :
242+ variables = {}
203243
204244 # Find all variables in the text, excluding function definitions
205245 # fmt: off
@@ -237,6 +277,9 @@ def obfuscate_variables(text: str) -> str:
237277 continue
238278 text = sub (rf"\b{ var } \b" , obf , text )
239279
280+ if use_json :
281+ save_keyword_mapping (json_path , variables )
282+
240283 return text
241284
242285
@@ -253,7 +296,7 @@ def key_finder(banned_list: list[str], known_keys: dict[str, str]) -> str:
253296 """
254297 char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
255298 while True :
256- key = "" .join (choice (char ) for _ in range (1 , choice ([2 , 3 ])+ 1 ))
299+ key = "" .join (choice (char ) for _ in range (1 , choice ([2 , 3 ]) + 1 ))
257300 if key not in banned_list and key not in known_keys .values ():
258301 break
259302 return key
@@ -291,7 +334,7 @@ def main():
291334 script = remove_blank_lines (script )
292335 script = array_stringify (remove_leading_whitespace (script ))
293336 script = clean_characters (script )
294- script = obfuscate_variables (script )
337+ script = obfuscate_variables (script , use_json = not args . forget )
295338 # script = reformat_array(script)
296339 # script = dequoter(script)
297340
0 commit comments