maya-umbrella 0.4.1__py2.py3-none-any.whl → 0.6.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of maya-umbrella might be problematic. Click here for more details.
- maya_umbrella/__init__.py +6 -2
- maya_umbrella/__version__.py +1 -1
- maya_umbrella/cleaner.py +111 -0
- maya_umbrella/collector.py +411 -0
- maya_umbrella/constants.py +17 -0
- maya_umbrella/defender.py +161 -0
- maya_umbrella/filesystem.py +151 -26
- maya_umbrella/hooks/delete_turtle.py +3 -3
- maya_umbrella/hooks/delete_unknown_plugin_node.py +4 -3
- maya_umbrella/hooks/fix_model_panel.py +2 -2
- maya_umbrella/hooks/fix_on_model_change_3dc.py +3 -3
- maya_umbrella/i18n.py +76 -0
- maya_umbrella/locales/en_US.json +19 -0
- maya_umbrella/locales/zh_CN.json +19 -0
- maya_umbrella/maya_funs.py +136 -0
- maya_umbrella/scanner.py +101 -0
- maya_umbrella/signatures.py +10 -0
- maya_umbrella/vaccine.py +18 -203
- maya_umbrella/vaccines/vaccine1.py +3 -2
- maya_umbrella/vaccines/vaccine2.py +23 -31
- maya_umbrella/vaccines/vaccine3.py +38 -36
- {maya_umbrella-0.4.1.dist-info → maya_umbrella-0.6.0.dist-info}/METADATA +75 -6
- maya_umbrella-0.6.0.dist-info/RECORD +28 -0
- maya_umbrella/core.py +0 -117
- maya_umbrella-0.4.1.dist-info/RECORD +0 -20
- {maya_umbrella-0.4.1.dist-info → maya_umbrella-0.6.0.dist-info}/LICENSE +0 -0
- {maya_umbrella-0.4.1.dist-info → maya_umbrella-0.6.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""In order to facilitate unit testing in CI.
|
|
2
|
+
|
|
3
|
+
we extracted all the interfaces used in Maya and mocked them uniformly.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Import third-party modules
|
|
8
|
+
try:
|
|
9
|
+
# Import third-party modules
|
|
10
|
+
import maya.api.OpenMaya as om
|
|
11
|
+
import maya.cmds as cmds
|
|
12
|
+
import maya.mel as mel
|
|
13
|
+
except ImportError:
|
|
14
|
+
# Backward compatibility to support test in uinstalled maya.
|
|
15
|
+
try:
|
|
16
|
+
# Import built-in modules
|
|
17
|
+
from unittest.mock import MagicMock
|
|
18
|
+
except ImportError:
|
|
19
|
+
# Import third-party modules
|
|
20
|
+
from mock import MagicMock # noqa: UP026
|
|
21
|
+
cmds = MagicMock()
|
|
22
|
+
om = MagicMock()
|
|
23
|
+
mel = MagicMock()
|
|
24
|
+
|
|
25
|
+
# Import built-in modules
|
|
26
|
+
from functools import wraps
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_maya_standalone():
|
|
30
|
+
"""Check if Maya is running in standalone mode.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
bool: True if Maya is running in standalone mode, False otherwise.
|
|
34
|
+
"""
|
|
35
|
+
return cmds.about(batch=True)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def check_reference_node_exists(node_name):
|
|
39
|
+
"""Check if a reference node exists in the Maya scene.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
node_name (str): Name of the reference node.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: True if the reference node exists, False otherwise.
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
return cmds.referenceQuery(node_name, isNodeReferenced=True)
|
|
49
|
+
except RuntimeError:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_reference_file_by_node(node_name):
|
|
54
|
+
"""Get the reference file associated with a node.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
node_name (str): Name of the node.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
str: Path of the reference file, empty string if the node is not associated with a reference file.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
return cmds.referenceQuery(node_name, filename=True)
|
|
64
|
+
except RuntimeError:
|
|
65
|
+
return ""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_attr_value(node_name, attr_name):
|
|
69
|
+
"""Get the value of an attribute of a node.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
node_name (str): Name of the node.
|
|
73
|
+
attr_name (str): Name of the attribute.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Any: Value of the attribute, None if the attribute does not exist.
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
return cmds.getAttr("{node_name}.{attr}".format(node_name=node_name, attr=attr_name))
|
|
80
|
+
except ValueError:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def maya_ui_language():
|
|
85
|
+
"""Get the language of the Maya user interface.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
str: The language of the Maya user interface.
|
|
89
|
+
"""
|
|
90
|
+
return cmds.about(uiLocaleLanguage=True)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def block_prompt(func):
|
|
94
|
+
"""Decorator to block file prompt dialogs in Maya.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
func (function): The function to decorate.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
function: The decorated function.
|
|
101
|
+
"""
|
|
102
|
+
@wraps(func)
|
|
103
|
+
def wrap(*args, **kwargs):
|
|
104
|
+
# Grabs the initial value.
|
|
105
|
+
prompt_val = cmds.file(prompt=True, q=True)
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
cmds.file(prompt=False)
|
|
109
|
+
return func(*args, **kwargs)
|
|
110
|
+
|
|
111
|
+
finally:
|
|
112
|
+
# Resets to the original value, this way you don't suddenly turn the prompt on, when someone wanted it off.
|
|
113
|
+
cmds.file(prompt=prompt_val)
|
|
114
|
+
|
|
115
|
+
return wrap
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@block_prompt
|
|
119
|
+
def open_maya_file(maya_file):
|
|
120
|
+
"""Open a Maya file.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
maya_file (str): Path to the Maya file.
|
|
124
|
+
"""
|
|
125
|
+
cmds.file(maya_file, open=True, force=True, ignoreVersion=True, executeScriptNodes=False)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@block_prompt
|
|
129
|
+
def save_as_file(file_name):
|
|
130
|
+
"""Save the current Maya scene as a file.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
file_name (str): Path to the output file.
|
|
134
|
+
"""
|
|
135
|
+
cmds.file(rename=file_name)
|
|
136
|
+
cmds.file(s=True, f=True)
|
maya_umbrella/scanner.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import glob
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
|
|
7
|
+
# Import local modules
|
|
8
|
+
from maya_umbrella import maya_funs
|
|
9
|
+
from maya_umbrella.defender import context_defender
|
|
10
|
+
from maya_umbrella.filesystem import get_backup_path
|
|
11
|
+
from maya_umbrella.filesystem import read_file
|
|
12
|
+
from maya_umbrella.maya_funs import cmds
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MayaVirusScanner(object):
|
|
16
|
+
"""A class to scan and fix Maya files containing viruses.
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
_failed_files (list): List of files that failed to be fixed.
|
|
20
|
+
_fixed_files (list): List of files that have been fixed.
|
|
21
|
+
logger (Logger): Logger object for logging purposes.
|
|
22
|
+
defender (MayaVirusDefender): MayaVirusDefender object for fixing issues.
|
|
23
|
+
_env (dict): Custom environment variables.
|
|
24
|
+
output_path (str, optional): Path to save the fixed files. Defaults to None, which overwrites the original
|
|
25
|
+
files.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, output_path=None, env=None):
|
|
29
|
+
"""Initialize the MayaVirusScanner.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
output_path (str, optional): Path to save the fixed files. Defaults to None, which overwrites the original
|
|
33
|
+
files.
|
|
34
|
+
env (dict, optional): Custom environment variables. Defaults to None,
|
|
35
|
+
which sets the 'MAYA_COLOR_MANAGEMENT_SYNCOLOR' variable to '1'.
|
|
36
|
+
"""
|
|
37
|
+
self.logger = logging.getLogger(__name__)
|
|
38
|
+
self.defender = None
|
|
39
|
+
self.output_path = output_path
|
|
40
|
+
self._failed_files = []
|
|
41
|
+
self._fixed_files = []
|
|
42
|
+
# Custom env.
|
|
43
|
+
self._env = env or {
|
|
44
|
+
"MAYA_COLOR_MANAGEMENT_SYNCOLOR": "1"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
def scan_files_from_pattern(self, pattern):
|
|
48
|
+
"""Scan and fix Maya files matching a given pattern.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
pattern (str): The file pattern to match.
|
|
52
|
+
"""
|
|
53
|
+
os.environ.update(self._env)
|
|
54
|
+
return self.scan_files_from_list(glob.iglob(pattern))
|
|
55
|
+
|
|
56
|
+
def scan_files_from_list(self, files):
|
|
57
|
+
"""Scan and fix Maya files from a given list.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
files (list): List of file paths to scan and fix.
|
|
61
|
+
"""
|
|
62
|
+
with context_defender() as defender:
|
|
63
|
+
self.defender = defender
|
|
64
|
+
for maya_file in files:
|
|
65
|
+
self._fix(maya_file)
|
|
66
|
+
return self._fixed_files
|
|
67
|
+
|
|
68
|
+
def scan_files_from_file(self, text_file):
|
|
69
|
+
"""Scan and fix Maya files from a given text file containing a list of file paths.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
text_file (str): Path to the text file containing the list of file paths.
|
|
73
|
+
"""
|
|
74
|
+
file_data = read_file(text_file)
|
|
75
|
+
files = file_data.splitlines()
|
|
76
|
+
return self.scan_files_from_list(files)
|
|
77
|
+
|
|
78
|
+
def _fix(self, maya_file):
|
|
79
|
+
"""Fix a single Maya file containing a virus.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
maya_file (str): Path to the Maya file to be fixed.
|
|
83
|
+
"""
|
|
84
|
+
if not maya_file and maya_file in self._fixed_files:
|
|
85
|
+
self.logger.debug("Already fixed: {maya_file}".format(maya_file=maya_file))
|
|
86
|
+
return
|
|
87
|
+
try:
|
|
88
|
+
maya_funs.open_maya_file(maya_file)
|
|
89
|
+
self.defender.collect()
|
|
90
|
+
except Exception:
|
|
91
|
+
self._failed_files.append(maya_file)
|
|
92
|
+
if self.defender.have_issues:
|
|
93
|
+
self.defender.fix()
|
|
94
|
+
backup_path = get_backup_path(maya_file, root_path=self.output_path)
|
|
95
|
+
self.logger.debug("Backup saved to: {backup_path}".format(backup_path=backup_path))
|
|
96
|
+
shutil.copy2(maya_file, backup_path)
|
|
97
|
+
cmds.file(s=True, f=True)
|
|
98
|
+
self._fixed_files.append(maya_file)
|
|
99
|
+
cmds.file(new=True, force=True)
|
|
100
|
+
for ref in self.defender.collector.infected_reference_files:
|
|
101
|
+
self._fix(ref)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
from collections import namedtuple
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
VirusSignature = namedtuple("VirusSignature", ["name", "signature"])
|
|
6
|
+
|
|
7
|
+
# https://regex101.com/r/0MNzF7/1
|
|
8
|
+
virus20240430_sig1 = VirusSignature("virus20240430", "python(.*);.+exec.+(pyCode).+;")
|
|
9
|
+
# https://regex101.com/r/2D14UA/1
|
|
10
|
+
virus20240430_sig2 = VirusSignature("virus20240430", r"^\['.+']")
|
maya_umbrella/vaccine.py
CHANGED
|
@@ -1,207 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import glob
|
|
4
|
-
import logging
|
|
5
|
-
import os
|
|
6
|
-
|
|
7
|
-
# Import third-party modules
|
|
8
|
-
import maya.cmds as cmds
|
|
9
|
-
|
|
10
|
-
# Import local modules
|
|
11
|
-
from maya_umbrella.filesystem import safe_remove_file
|
|
12
|
-
from maya_umbrella.filesystem import safe_rmtree
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class MayaVirusCleaner(object):
|
|
16
|
-
_bad_files = []
|
|
17
|
-
_bad_nodes = []
|
|
18
|
-
_bad_script_nodes = []
|
|
19
|
-
_bad_script_jobs = []
|
|
20
|
-
_registered_callbacks = defaultdict(list)
|
|
21
|
-
_fix_funcs = []
|
|
22
|
-
|
|
23
|
-
def __init__(self, logger=None, auto_fix=True):
|
|
24
|
-
self.logger = logger or logging.getLogger(__name__)
|
|
25
|
-
self.auto_fix = auto_fix
|
|
26
|
-
|
|
27
|
-
@property
|
|
28
|
-
def user_app_dir(self):
|
|
29
|
-
"""Return the user application directory."""
|
|
30
|
-
return cmds.internalVar(userAppDir=True)
|
|
31
|
-
|
|
32
|
-
@property
|
|
33
|
-
def maya_file(self):
|
|
34
|
-
"""Return the current Maya file."""
|
|
35
|
-
return cmds.file(q=True, sn=True)
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def maya_install_root(self):
|
|
39
|
-
"""Return the Maya installation root directory."""
|
|
40
|
-
return os.environ["MAYA_LOCATION"]
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def user_script_path(self):
|
|
44
|
-
"""Return the user script directory."""
|
|
45
|
-
return cmds.internalVar(userScriptDir=True)
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def local_script_path(self):
|
|
49
|
-
"""Return the local script directory."""
|
|
50
|
-
return os.path.join(self.user_app_dir, "scripts")
|
|
51
|
-
|
|
52
|
-
@property
|
|
53
|
-
def bad_files(self):
|
|
54
|
-
"""Return a list of bad files."""
|
|
55
|
-
return [path for path in list(set(self._bad_files)) if os.path.exists(path)]
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def bad_nodes(self):
|
|
59
|
-
"""Return a list of bad nodes."""
|
|
60
|
-
return list(set(self._bad_nodes))
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def bad_script_nodes(self):
|
|
64
|
-
"""Return a list of bad script nodes."""
|
|
65
|
-
return list(set(self._bad_script_nodes))
|
|
66
|
-
|
|
67
|
-
@property
|
|
68
|
-
def bad_script_jobs(self):
|
|
69
|
-
"""Return a list of bad script jobs."""
|
|
70
|
-
return list(set(self._bad_script_jobs))
|
|
71
|
-
|
|
72
|
-
def callback_remove_rename_temp_files(self, *args, **kwargs):
|
|
73
|
-
"""
|
|
74
|
-
Remove temporary files in the local script path.
|
|
75
|
-
"""
|
|
76
|
-
self.logger.info("Removing temporary files in %s", self.local_script_path)
|
|
77
|
-
[safe_remove_file(temp_file) for temp_file in glob.glob(os.path.join(self.local_script_path, "._*"))]
|
|
78
|
-
|
|
79
|
-
@property
|
|
80
|
-
def registered_callbacks(self):
|
|
81
|
-
return self._registered_callbacks
|
|
82
|
-
|
|
83
|
-
def add_bad_files(self, files):
|
|
84
|
-
self._bad_files.extend(files)
|
|
85
|
-
|
|
86
|
-
def add_bad_file(self, file):
|
|
87
|
-
self._bad_files.append(file)
|
|
88
|
-
|
|
89
|
-
def add_bad_nodes(self, nodes):
|
|
90
|
-
self._bad_nodes.extend(nodes)
|
|
91
|
-
|
|
92
|
-
def add_bad_node(self, node):
|
|
93
|
-
self._bad_nodes.append(node)
|
|
94
|
-
|
|
95
|
-
def add_bad_script_jobs(self, jobs):
|
|
96
|
-
self._bad_script_jobs.extend(jobs)
|
|
97
|
-
|
|
98
|
-
def add_bad_script_job(self, job):
|
|
99
|
-
self._bad_script_jobs.append(job)
|
|
100
|
-
|
|
101
|
-
def add_bad_script_nodes(self, nodes):
|
|
102
|
-
self._bad_script_nodes.extend(nodes)
|
|
103
|
-
|
|
104
|
-
def add_bad_script_node(self, node):
|
|
105
|
-
self._bad_script_nodes.append(node)
|
|
106
|
-
|
|
107
|
-
def register_callback(self, callback_name, callback):
|
|
108
|
-
"""Register a callback to be executed before or after processing."""
|
|
109
|
-
self._registered_callbacks[callback_name].append(callback)
|
|
110
|
-
|
|
111
|
-
def add_after_open_callback(self, callback):
|
|
112
|
-
self.register_callback("after_open", callback)
|
|
113
|
-
|
|
114
|
-
def add_maya_initialized_callback(self, callback):
|
|
115
|
-
self.register_callback("maya_initialized", callback)
|
|
116
|
-
|
|
117
|
-
def add_after_import_callback(self, callback):
|
|
118
|
-
self.register_callback("after_import", callback)
|
|
119
|
-
|
|
120
|
-
def add_after_import_reference_callback(self, callback):
|
|
121
|
-
self.register_callback("after_import_reference", callback)
|
|
122
|
-
|
|
123
|
-
def add_after_load_reference_callback(self, callback):
|
|
124
|
-
self.register_callback("after_load_reference", callback)
|
|
125
|
-
|
|
126
|
-
def add_before_save_callback(self, callback):
|
|
127
|
-
self.register_callback("before_save", callback)
|
|
128
|
-
|
|
129
|
-
def add_before_import_callback(self, callback):
|
|
130
|
-
self.register_callback("before_import", callback)
|
|
131
|
-
|
|
132
|
-
def add_before_load_reference_callback(self, callback):
|
|
133
|
-
self.register_callback("before_load_reference", callback)
|
|
134
|
-
|
|
135
|
-
def add_before_import_reference_callback(self, callback):
|
|
136
|
-
self.register_callback("before_import_reference", callback)
|
|
137
|
-
|
|
138
|
-
def add_maya_exiting_callback(self, callback):
|
|
139
|
-
self.register_callback("maya_exiting", callback)
|
|
140
|
-
|
|
141
|
-
def setup_default_callbacks(self):
|
|
142
|
-
self.add_maya_initialized_callback(self.callback_remove_rename_temp_files)
|
|
143
|
-
self.add_maya_exiting_callback(self.callback_remove_rename_temp_files)
|
|
144
|
-
|
|
145
|
-
def add_fix_function(self, func):
|
|
146
|
-
self._fix_funcs.append(func)
|
|
147
|
-
|
|
148
|
-
# fix
|
|
149
|
-
|
|
150
|
-
def fix_script_jobs(self):
|
|
151
|
-
for script_job in self.bad_script_jobs:
|
|
152
|
-
script_num = int(script_job.split(":", 1)[0])
|
|
153
|
-
self.logger.info("Kill script job %s", script_job)
|
|
154
|
-
cmds.scriptJob(kill=script_num, force=True)
|
|
155
|
-
self._bad_script_jobs.remove(script_job)
|
|
156
|
-
|
|
157
|
-
def fix_bad_files(self):
|
|
158
|
-
for file_ in self.bad_files:
|
|
159
|
-
if os.path.exists(file_):
|
|
160
|
-
if os.path.isfile(file_):
|
|
161
|
-
self.logger.info("Removing %s", file_)
|
|
162
|
-
safe_remove_file(file_)
|
|
163
|
-
self._bad_files.remove(file_)
|
|
164
|
-
else:
|
|
165
|
-
self.logger.info("Removing folder %s", file_)
|
|
166
|
-
safe_rmtree(file_)
|
|
167
|
-
self._bad_files.remove(file_)
|
|
168
|
-
|
|
169
|
-
def fix_bad_nodes(self):
|
|
170
|
-
for node in self.bad_nodes:
|
|
171
|
-
self.logger.info("Deleting %s", node)
|
|
172
|
-
try:
|
|
173
|
-
cmds.lockNode(node, lock=False)
|
|
174
|
-
except ValueError:
|
|
175
|
-
pass
|
|
176
|
-
try:
|
|
177
|
-
cmds.delete(node)
|
|
178
|
-
except ValueError:
|
|
179
|
-
pass
|
|
180
|
-
self._bad_nodes.remove(node)
|
|
181
|
-
|
|
182
|
-
def fix_all_issues(self):
|
|
183
|
-
"""Fix all issues related to the Maya virus."""
|
|
184
|
-
self.fix_bad_files()
|
|
185
|
-
self.fix_bad_nodes()
|
|
186
|
-
self.fix_script_jobs()
|
|
187
|
-
for func in self._fix_funcs:
|
|
188
|
-
func()
|
|
189
|
-
|
|
190
|
-
def report_all_issues(self):
|
|
191
|
-
"""Report all issues related to the Maya virus."""
|
|
192
|
-
self.logger.info("Bad files: %s", self.bad_files)
|
|
193
|
-
self.logger.info("Bad nodes: %s", self.bad_nodes)
|
|
194
|
-
self.logger.info("Bad script jobs: %s", self.bad_script_jobs)
|
|
195
|
-
|
|
196
|
-
def reset_all_issues(self):
|
|
197
|
-
"""Reset all issues related to the Maya virus."""
|
|
198
|
-
self._bad_files = []
|
|
199
|
-
self._bad_nodes = []
|
|
200
|
-
self._bad_script_nodes = []
|
|
201
|
-
self._bad_script_jobs = []
|
|
1
|
+
class AbstractVaccine(object):
|
|
2
|
+
"""Abstract base class for Vaccine classes.
|
|
202
3
|
|
|
4
|
+
Attributes:
|
|
5
|
+
virus_name (str): The name of the virus.
|
|
6
|
+
api (MayaVirusCleaner): The VaccineAPI instance.
|
|
7
|
+
logger (Logger): The logger instance.
|
|
8
|
+
"""
|
|
203
9
|
|
|
204
|
-
class AbstractVaccine(object):
|
|
205
10
|
virus_name = None
|
|
206
11
|
|
|
207
12
|
def __init__(self, api, logger):
|
|
@@ -216,7 +21,17 @@ class AbstractVaccine(object):
|
|
|
216
21
|
self.logger = logger
|
|
217
22
|
|
|
218
23
|
def collect_issues(self):
|
|
24
|
+
"""Collect issues related to the virus.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
NotImplementedError: This method must be implemented in the derived classes.
|
|
28
|
+
"""
|
|
219
29
|
raise NotImplementedError
|
|
220
30
|
|
|
221
31
|
def report_issue(self, name):
|
|
222
|
-
|
|
32
|
+
"""Report an issue related to the virus.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
name (str): The name of the issue.
|
|
36
|
+
"""
|
|
37
|
+
self.logger.warning(self.api.translator.translate("report_issue", name=name))
|
|
@@ -6,10 +6,11 @@ from maya_umbrella.vaccine import AbstractVaccine
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Vaccine(AbstractVaccine):
|
|
9
|
-
|
|
9
|
+
"""A class for handling the PuTianTongQi virus."""
|
|
10
|
+
virus_name = "PutTianTongQi"
|
|
10
11
|
|
|
11
12
|
def collect_issues(self):
|
|
12
|
-
self.api.
|
|
13
|
+
self.api.add_malicious_files(
|
|
13
14
|
[
|
|
14
15
|
os.path.join(self.api.local_script_path, "fuckVirus.py"),
|
|
15
16
|
os.path.join(self.api.local_script_path, "fuckVirus.pyc"),
|
|
@@ -1,60 +1,52 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
2
|
import os.path
|
|
3
3
|
|
|
4
|
-
# Import third-party modules
|
|
5
|
-
import maya.cmds as cmds
|
|
6
|
-
|
|
7
4
|
# Import local modules
|
|
8
|
-
from maya_umbrella.
|
|
9
|
-
from maya_umbrella.filesystem import
|
|
5
|
+
from maya_umbrella.constants import JOB_SCRIPTS_VIRUS_SIGNATURES
|
|
6
|
+
from maya_umbrella.filesystem import check_virus_by_signature
|
|
7
|
+
from maya_umbrella.filesystem import check_virus_file_by_signature
|
|
8
|
+
from maya_umbrella.maya_funs import check_reference_node_exists
|
|
9
|
+
from maya_umbrella.maya_funs import cmds
|
|
10
|
+
from maya_umbrella.maya_funs import get_attr_value
|
|
10
11
|
from maya_umbrella.vaccine import AbstractVaccine
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class Vaccine(AbstractVaccine):
|
|
15
|
+
"""A class for handling the ZeiJianKang virus."""
|
|
16
|
+
|
|
14
17
|
virus_name = "zei jian kang"
|
|
15
18
|
|
|
16
|
-
def
|
|
19
|
+
def collect_infected_nodes(self):
|
|
17
20
|
"""Collect all bad nodes related to the virus."""
|
|
18
21
|
for script_node in cmds.ls(type="script"):
|
|
19
|
-
if
|
|
22
|
+
if check_reference_node_exists(script_node):
|
|
20
23
|
continue
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
for script_string in [script_before_string, script_after_string]:
|
|
24
|
+
for attr_name in ("before", "after"):
|
|
25
|
+
script_string = get_attr_value(script_node, attr_name)
|
|
24
26
|
if not script_string:
|
|
25
27
|
continue
|
|
26
|
-
if
|
|
28
|
+
if check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
|
|
27
29
|
self.report_issue(script_node)
|
|
28
|
-
self.api.
|
|
30
|
+
self.api.add_infected_node(script_node)
|
|
29
31
|
|
|
30
32
|
def collect_issues(self):
|
|
31
33
|
"""Collect all issues related to the virus."""
|
|
32
|
-
self.api.
|
|
34
|
+
self.api.add_malicious_files(
|
|
33
35
|
[
|
|
34
36
|
os.path.join(self.api.local_script_path, "vaccine.py"),
|
|
35
37
|
os.path.join(self.api.local_script_path, "vaccine.pyc"),
|
|
36
38
|
],
|
|
37
39
|
)
|
|
38
|
-
self.
|
|
39
|
-
self.
|
|
40
|
+
self.collect_infected_user_setup_py()
|
|
41
|
+
self.collect_infected_nodes()
|
|
40
42
|
|
|
41
|
-
def
|
|
43
|
+
def collect_infected_user_setup_py(self):
|
|
42
44
|
"""Collect all bad userSetup.py files related to the virus."""
|
|
43
|
-
for
|
|
44
|
-
os.path.join(self.api.local_script_path, "vaccine.py"),
|
|
45
|
-
os.path.join(self.api.user_script_path, "vaccine.py"),
|
|
45
|
+
for user_setup_py in [
|
|
46
46
|
os.path.join(self.api.local_script_path, "userSetup.py"),
|
|
47
47
|
os.path.join(self.api.user_script_path, "userSetup.py"),
|
|
48
48
|
]:
|
|
49
|
-
if os.path.exists(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.
|
|
53
|
-
self.api.add_bad_file(rename(usersetup_py))
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
"cmds.evalDeferred('leukocyte = vaccine.phage()')" in data
|
|
57
|
-
and "cmds.evalDeferred('leukocyte.occupation()')" in data
|
|
58
|
-
):
|
|
59
|
-
self.report_issue("userSetup.py")
|
|
60
|
-
self.api.add_bad_file(rename(usersetup_py))
|
|
49
|
+
if os.path.exists(user_setup_py):
|
|
50
|
+
if check_virus_file_by_signature(user_setup_py):
|
|
51
|
+
self.report_issue(user_setup_py)
|
|
52
|
+
self.api.add_infected_file(user_setup_py)
|