-
-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathobfuscator.py
More file actions
53 lines (39 loc) · 1.78 KB
/
obfuscator.py
File metadata and controls
53 lines (39 loc) · 1.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from __future__ import annotations
import ast
from .config import ObfuscationConfig
from .techniques.registry import all_technique_names, get_transforms
def _validate_config(config: ObfuscationConfig) -> None:
unknown = config.enabled_techniques - all_technique_names()
if unknown:
raise ValueError(
f"Unknown technique(s): {sorted(unknown)}. "
f"Available: {sorted(all_technique_names())}"
)
def obfuscate(source: str, config: ObfuscationConfig | None = None) -> str:
"""Obfuscate *source* using the techniques described by *config*.
When *config* is ``None`` all registered techniques are applied.
"""
resolved = config if config is not None else ObfuscationConfig.all_enabled()
_validate_config(resolved)
tree = ast.parse(source)
for transform_cls in get_transforms(resolved.enabled_techniques):
tree = transform_cls().apply(tree)
return ast.unparse(tree)
class Obfuscator:
"""Stateful wrapper that pre-builds and caches the transform pipeline.
Prefer this over the module-level :func:`obfuscate` when processing many
files with the same configuration, since the pipeline is validated and
sorted once at construction time.
"""
def __init__(self, config: ObfuscationConfig | None = None) -> None:
self._config = config if config is not None else ObfuscationConfig.all_enabled()
_validate_config(self._config)
self._transforms = get_transforms(self._config.enabled_techniques)
@property
def config(self) -> ObfuscationConfig:
return self._config
def obfuscate(self, source: str) -> str:
tree = ast.parse(source)
for transform_cls in self._transforms:
tree = transform_cls().apply(tree)
return ast.unparse(tree)