maya-umbrella 0.3.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.
- maya_umbrella/__init__.py +5 -0
- maya_umbrella/__version__.py +1 -0
- maya_umbrella/core.py +76 -0
- maya_umbrella/filesystem.py +110 -0
- maya_umbrella/hooks/__init__.py +0 -0
- maya_umbrella/hooks/delete_turtle.py +18 -0
- maya_umbrella/hooks/delete_unknown_plugin_node.py +29 -0
- maya_umbrella/hooks/fix_model_panel.py +14 -0
- maya_umbrella/hooks/fix_on_model_change_3dc.py +14 -0
- maya_umbrella/vaccine.py +80 -0
- maya_umbrella/vaccines/__init__.py +0 -0
- maya_umbrella/vaccines/vaccine1.py +19 -0
- maya_umbrella/vaccines/vaccine2.py +65 -0
- maya_umbrella/vaccines/vaccine3.py +110 -0
- maya_umbrella-0.3.0.dist-info/LICENSE +21 -0
- maya_umbrella-0.3.0.dist-info/METADATA +85 -0
- maya_umbrella-0.3.0.dist-info/RECORD +18 -0
- maya_umbrella-0.3.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
maya_umbrella/core.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
# Import third-party modules
|
|
6
|
+
import maya.api.OpenMaya as om
|
|
7
|
+
|
|
8
|
+
# Import local modules
|
|
9
|
+
from maya_umbrella.filesystem import get_hooks
|
|
10
|
+
from maya_umbrella.filesystem import get_vaccines
|
|
11
|
+
from maya_umbrella.filesystem import load_hook
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Defender(object):
|
|
15
|
+
callback_ids = []
|
|
16
|
+
remove_callbacks = []
|
|
17
|
+
_bad_files = []
|
|
18
|
+
_vaccines = []
|
|
19
|
+
callback_maps = {
|
|
20
|
+
"afterOpen": om.MSceneMessage.kAfterOpen,
|
|
21
|
+
"afterImport": om.MSceneMessage.kAfterImport,
|
|
22
|
+
"afterImportReference": om.MSceneMessage.kAfterImportReference,
|
|
23
|
+
"afterLoadReference": om.MSceneMessage.kAfterLoadReference,
|
|
24
|
+
"beforeSave": om.MSceneMessage.kBeforeSave,
|
|
25
|
+
"beforeImport": om.MSceneMessage.kBeforeImport,
|
|
26
|
+
"beforeLoadReference": om.MSceneMessage.kBeforeLoadReference,
|
|
27
|
+
"beforeImportReference": om.MSceneMessage.kBeforeImportReference,
|
|
28
|
+
"beforeMayaExiting": om.MSceneMessage.kMayaExiting,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.logger = logging.getLogger(__name__)
|
|
33
|
+
self.load_vaccines()
|
|
34
|
+
|
|
35
|
+
def load_vaccines(self):
|
|
36
|
+
for vaccine in get_vaccines():
|
|
37
|
+
self._vaccines.append(load_hook(vaccine).Vaccine(self.logger))
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def vaccines(self):
|
|
41
|
+
return self._vaccines
|
|
42
|
+
|
|
43
|
+
def run_hooks(self):
|
|
44
|
+
for hook in get_hooks():
|
|
45
|
+
self.logger.info("run_hooks: %s", hook)
|
|
46
|
+
load_hook(hook).hook(self.logger)
|
|
47
|
+
|
|
48
|
+
def setup(self):
|
|
49
|
+
for name, callback in self.callback_maps.items():
|
|
50
|
+
matched = re.search(r"(?P<name>(after|before))", name)
|
|
51
|
+
if matched:
|
|
52
|
+
method_name = matched.group("name")
|
|
53
|
+
self.logger.info("setup %s.", name)
|
|
54
|
+
self.callback_ids.append(
|
|
55
|
+
{name: om.MSceneMessage.addCallback(callback, getattr(self, "{0}_callback".format(method_name)))}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self.start()
|
|
59
|
+
|
|
60
|
+
def before_callback(self, *args, **kwargs):
|
|
61
|
+
self.logger.info("before_callback.")
|
|
62
|
+
for vaccine in self.vaccines:
|
|
63
|
+
vaccine.before_callback()
|
|
64
|
+
self.run_hooks()
|
|
65
|
+
|
|
66
|
+
def after_callback(self, *args, **kwargs):
|
|
67
|
+
self.logger.info("after_callback.")
|
|
68
|
+
for vaccine in self.vaccines:
|
|
69
|
+
vaccine.after_callback()
|
|
70
|
+
self.run_hooks()
|
|
71
|
+
|
|
72
|
+
def start(self):
|
|
73
|
+
for vaccine in self.vaccines:
|
|
74
|
+
self.logger.info("process for vaccine: {0}".format(vaccine.virus_name))
|
|
75
|
+
vaccine.process()
|
|
76
|
+
self.run_hooks()
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import glob
|
|
3
|
+
import importlib
|
|
4
|
+
import io
|
|
5
|
+
import os
|
|
6
|
+
import random
|
|
7
|
+
import shutil
|
|
8
|
+
import string
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def this_root():
|
|
12
|
+
"""Return the absolute path of the current file's directory."""
|
|
13
|
+
return os.path.abspath(os.path.dirname(__file__))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def safe_remove_file(file_path):
|
|
17
|
+
"""Remove the file at the given path without raising an error if the file does not exist."""
|
|
18
|
+
try:
|
|
19
|
+
os.remove(file_path)
|
|
20
|
+
except (IOError, OSError):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def safe_rmtree(path):
|
|
25
|
+
"""Remove the directory at the given path without raising an error if the directory does not exist."""
|
|
26
|
+
try:
|
|
27
|
+
shutil.rmtree(path)
|
|
28
|
+
except (IOError, OSError):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def read_file(path):
|
|
33
|
+
"""Read the content of the file at the given path."""
|
|
34
|
+
with io.open(path, "r", encoding="utf-8") as file_:
|
|
35
|
+
content = file_.read()
|
|
36
|
+
return content
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def write_file(path, content):
|
|
40
|
+
"""Write the given content to the file at the given path."""
|
|
41
|
+
with io.open(path, "w", encoding="utf-8", newline="\n") as file_:
|
|
42
|
+
file_.write(content)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def patch_file(source, target, key_values, report_error=True):
|
|
46
|
+
"""Modify the file at the source path with the given key value pairs and write the result to the target path.
|
|
47
|
+
|
|
48
|
+
If report_error is True, raise an IndexError if any of the keys are not found in the source file.
|
|
49
|
+
"""
|
|
50
|
+
key_values = key_values if key_values else {}
|
|
51
|
+
found_keys = []
|
|
52
|
+
file_data = read_file(source)
|
|
53
|
+
for key, value in key_values.items():
|
|
54
|
+
before_ = file_data
|
|
55
|
+
file_data = file_data.replace(key, value)
|
|
56
|
+
if before_ != file_data:
|
|
57
|
+
found_keys.append(key)
|
|
58
|
+
write_file(target, file_data)
|
|
59
|
+
|
|
60
|
+
if report_error:
|
|
61
|
+
not_found = list(set(key_values.keys()) - set(found_keys))
|
|
62
|
+
if not_found:
|
|
63
|
+
raise IndexError("Not found: {0}".format(not_found))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
|
67
|
+
"""Generate a random string of the given size using the given characters."""
|
|
68
|
+
return "".join(random.choice(chars) for _ in range(size))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def rename(src):
|
|
72
|
+
"""Rename the file at the given path to a random name and return the new path."""
|
|
73
|
+
dst = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
|
|
74
|
+
try:
|
|
75
|
+
os.rename(src, dst)
|
|
76
|
+
except OSError:
|
|
77
|
+
return src
|
|
78
|
+
return dst
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def load_hook(hook_file):
|
|
82
|
+
"""Load the Python module from the given hook file."""
|
|
83
|
+
hook_name = os.path.basename(hook_file).split(".py")[0]
|
|
84
|
+
if hasattr(importlib, "machinery"):
|
|
85
|
+
# Python 3
|
|
86
|
+
# Import built-in modules
|
|
87
|
+
from importlib.util import spec_from_loader
|
|
88
|
+
|
|
89
|
+
loader = importlib.machinery.SourceFileLoader(hook_name, hook_file)
|
|
90
|
+
spec = importlib.util.spec_from_loader(loader.name, loader=loader)
|
|
91
|
+
module = importlib.util.module_from_spec(spec)
|
|
92
|
+
loader.exec_module(module)
|
|
93
|
+
else:
|
|
94
|
+
# Python 2
|
|
95
|
+
# Import built-in modules
|
|
96
|
+
import imp
|
|
97
|
+
|
|
98
|
+
module = imp.load_source(hook_name, hook_file)
|
|
99
|
+
return module
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def get_hooks():
|
|
103
|
+
"""Return a list of paths to all hook files in the 'hooks' directory."""
|
|
104
|
+
pattern = os.path.join(this_root(), "hooks", "*.py")
|
|
105
|
+
return [hook for hook in glob.glob(pattern) if "__init__" not in hook]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_vaccines():
|
|
109
|
+
pattern = os.path.join(this_root(), "vaccines", "*.py")
|
|
110
|
+
return [vaccine for vaccine in glob.glob(pattern) if "__init__" not in vaccine]
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Import third-party modules
|
|
2
|
+
import maya.cmds as cmds
|
|
3
|
+
import maya.mel as mel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def hook(logger):
|
|
7
|
+
for plugin in ["Turtle.mll", "mayatomr.mll"]:
|
|
8
|
+
if cmds.pluginInfo(plugin, q=1, loaded=1):
|
|
9
|
+
cmds.unloadPlugin(plugin, f=1)
|
|
10
|
+
turtle_nodes = ["TurtleRenderOptions", "TurtleUIOptions", "TurtleBakeLayerManager", "TurtleDefaultBakeLayer"]
|
|
11
|
+
for node in turtle_nodes:
|
|
12
|
+
if cmds.objExists(node):
|
|
13
|
+
cmds.lockNode(node, lock=1)
|
|
14
|
+
cmds.delete(node)
|
|
15
|
+
if not cmds.about(query=1, batch=1):
|
|
16
|
+
shelves = cmds.tabLayout(mel.eval("$tmpVar=$gShelfTopLevel"), q=1, ca=1)
|
|
17
|
+
if "TURTLE" in shelves:
|
|
18
|
+
cmds.deleteUI("TURTLE", layout=1)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Import third-party modules
|
|
2
|
+
import maya.cmds as cmds
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def hook(logger):
|
|
6
|
+
unknown_node = cmds.ls(type="unknown")
|
|
7
|
+
unknown_plugin = cmds.unknownPlugin(query=True, l=True)
|
|
8
|
+
if unknown_node:
|
|
9
|
+
for nodeObj in unknown_node:
|
|
10
|
+
if cmds.objExists(nodeObj):
|
|
11
|
+
if cmds.referenceQuery(nodeObj, isNodeReferenced=True):
|
|
12
|
+
logger.warning("Node from reference, skip. {}".format(nodeObj))
|
|
13
|
+
continue
|
|
14
|
+
if cmds.lockNode(nodeObj, query=True)[0]:
|
|
15
|
+
try:
|
|
16
|
+
cmds.lockNode(nodeObj, lock=False)
|
|
17
|
+
except Exception as e:
|
|
18
|
+
logger.warning("The node is locked and cannot be unlocked. skip {}".format(nodeObj))
|
|
19
|
+
continue
|
|
20
|
+
try:
|
|
21
|
+
cmds.delete(nodeObj)
|
|
22
|
+
logger.warning("Delete node : {}".format(nodeObj))
|
|
23
|
+
except Exception as e:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
if unknown_plugin:
|
|
27
|
+
for plugObj in unknown_plugin:
|
|
28
|
+
cmds.unknownPlugin(plugObj, remove=True)
|
|
29
|
+
logger.warning("Delete plug-in : {}".format(plugObj))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Import third-party modules
|
|
2
|
+
import maya.cmds as cmds
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def hook(logger):
|
|
6
|
+
for model_panel in cmds.getPanel(typ="modelPanel"):
|
|
7
|
+
|
|
8
|
+
# Get callback of the model editor
|
|
9
|
+
callback = cmds.modelEditor(model_panel, query=True, editorChanged=True)
|
|
10
|
+
|
|
11
|
+
# If the callback is the erroneous `CgAbBlastPanelOptChangeCallback`
|
|
12
|
+
if callback == "CgAbBlastPanelOptChangeCallback":
|
|
13
|
+
# Remove the callbacks from the editor
|
|
14
|
+
cmds.modelEditor(model_panel, edit=True, editorChanged="")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Import third-party modules
|
|
2
|
+
import maya.cmds as cmds
|
|
3
|
+
import maya.mel as mel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def hook(logger):
|
|
7
|
+
mel.eval('global proc onModelChange3dc(string $a){}')
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
cmds.delete("fixCgAbBlastPanelOptChangeCallback")
|
|
11
|
+
except:
|
|
12
|
+
pass
|
|
13
|
+
script = "global proc CgAbBlastPanelOptChangeCallback(string $i){}"
|
|
14
|
+
mel.eval(script)
|
maya_umbrella/vaccine.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import glob
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
# Import third-party modules
|
|
7
|
+
import maya.cmds as cmds
|
|
8
|
+
|
|
9
|
+
# Import local modules
|
|
10
|
+
from maya_umbrella.filesystem import safe_remove_file
|
|
11
|
+
from maya_umbrella.filesystem import safe_rmtree
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseVaccine(object):
|
|
15
|
+
virus_name = None
|
|
16
|
+
|
|
17
|
+
_bad_files = []
|
|
18
|
+
|
|
19
|
+
def __init__(self, logger=None):
|
|
20
|
+
self._logger = logger or logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def user_app_dir(self):
|
|
24
|
+
return cmds.internalVar(userAppDir=True)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def maya_install_root(self):
|
|
28
|
+
return os.environ["MAYA_LOCATION"]
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def user_script_path(self):
|
|
32
|
+
return cmds.internalVar(userScriptDir=True)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def local_script_path(self):
|
|
36
|
+
return os.path.join(self.user_app_dir, "scripts")
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def bad_files(self):
|
|
40
|
+
return []
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def bad_nodes(self):
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def bad_script_nodes(self):
|
|
48
|
+
return []
|
|
49
|
+
|
|
50
|
+
def collect(self):
|
|
51
|
+
self._bad_files.extend([temp_file for temp_file in glob.glob(os.path.join(self.local_script_path, "._*"))])
|
|
52
|
+
|
|
53
|
+
def remove_bad_files(self):
|
|
54
|
+
self.collect()
|
|
55
|
+
for file_ in self.bad_files:
|
|
56
|
+
if os.path.exists(file_):
|
|
57
|
+
if os.path.isfile(file_):
|
|
58
|
+
self._logger.info("Removing {}".format(file_))
|
|
59
|
+
safe_remove_file(file_)
|
|
60
|
+
else:
|
|
61
|
+
self._logger.info("Removing folder {}".format(file_))
|
|
62
|
+
safe_rmtree(file_)
|
|
63
|
+
|
|
64
|
+
def delete_bad_nodes(self):
|
|
65
|
+
for node in self.bad_nodes:
|
|
66
|
+
self._logger.info("Deleting %s", node)
|
|
67
|
+
cmds.lockNode(node, l=False)
|
|
68
|
+
cmds.delete(node)
|
|
69
|
+
|
|
70
|
+
def before_callback(self, *args, **kwargs):
|
|
71
|
+
self.remove_bad_files()
|
|
72
|
+
self.delete_bad_nodes()
|
|
73
|
+
|
|
74
|
+
def after_callback(self, *args, **kwargs):
|
|
75
|
+
self.remove_bad_files()
|
|
76
|
+
self.delete_bad_nodes()
|
|
77
|
+
|
|
78
|
+
def process(self):
|
|
79
|
+
self.before_callback()
|
|
80
|
+
self.after_callback()
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import os.path
|
|
3
|
+
|
|
4
|
+
# Import local modules
|
|
5
|
+
from maya_umbrella.vaccine import BaseVaccine
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Vaccine(BaseVaccine):
|
|
9
|
+
virus_name = "pu tian tong qi"
|
|
10
|
+
|
|
11
|
+
def __init__(self, logger=None):
|
|
12
|
+
super(Vaccine, self).__init__(logger)
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def bad_files(self):
|
|
16
|
+
return [
|
|
17
|
+
os.path.join(self.local_script_path, "fuckVirus.py"),
|
|
18
|
+
os.path.join(self.local_script_path, "fuckVirus.pyc"),
|
|
19
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import os.path
|
|
3
|
+
|
|
4
|
+
# Import third-party modules
|
|
5
|
+
import maya.cmds as cmds
|
|
6
|
+
|
|
7
|
+
# Import local modules
|
|
8
|
+
from maya_umbrella.filesystem import read_file
|
|
9
|
+
from maya_umbrella.filesystem import rename
|
|
10
|
+
from maya_umbrella.vaccine import BaseVaccine
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Vaccine(BaseVaccine):
|
|
14
|
+
virus_name = "zei jian kang"
|
|
15
|
+
_bad_files = []
|
|
16
|
+
|
|
17
|
+
def __init__(self, logger=None):
|
|
18
|
+
super(Vaccine, self).__init__(logger)
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def bad_files(self):
|
|
22
|
+
return [os.path.join(self.local_script_path, "vaccine.py"), os.path.join(self.local_script_path, "vaccine.pyc")]
|
|
23
|
+
|
|
24
|
+
def _get_nodes(self):
|
|
25
|
+
bad_script_nodes = []
|
|
26
|
+
for script_node in cmds.ls(type="script"):
|
|
27
|
+
if cmds.referenceQuery(script_node, isNodeReferenced=True):
|
|
28
|
+
continue
|
|
29
|
+
script_before_string = cmds.getAttr("{}.before".format(script_node))
|
|
30
|
+
script_after_string = cmds.getAttr("{}.after".format(script_node))
|
|
31
|
+
for script_string in [script_before_string, script_after_string]:
|
|
32
|
+
if not script_string:
|
|
33
|
+
continue
|
|
34
|
+
if "internalVar" in script_string or "userSetup" in script_string or "fuckVirus" in script_string:
|
|
35
|
+
self._logger.warning("script node {} has internalVar or userSetup or fuckVirus".format(script_node))
|
|
36
|
+
bad_script_nodes.append(script_node)
|
|
37
|
+
return bad_script_nodes
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def bad_nodes(self):
|
|
41
|
+
return self._get_nodes()
|
|
42
|
+
|
|
43
|
+
def check_usersetup_py(self):
|
|
44
|
+
for usersetup_py in [
|
|
45
|
+
os.path.join(self.local_script_path, "vaccine.py"),
|
|
46
|
+
os.path.join(self.user_script_path, "vaccine.py"),
|
|
47
|
+
os.path.join(self.local_script_path, "userSetup.py"),
|
|
48
|
+
os.path.join(self.user_script_path, "userSetup.py"),
|
|
49
|
+
]:
|
|
50
|
+
if os.path.exists(usersetup_py):
|
|
51
|
+
data = read_file(usersetup_py)
|
|
52
|
+
if "petri_dish_path = cmds.internalVar(userAppDir=True) + 'scripts/userSetup.py" in data:
|
|
53
|
+
self._logger.warning("vaccine.py found : Infected by Malware!")
|
|
54
|
+
self._bad_files.append(rename(usersetup_py))
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
"cmds.evalDeferred('leukocyte = vaccine.phage()')" in data
|
|
58
|
+
and "cmds.evalDeferred('leukocyte.occupation()')" in data
|
|
59
|
+
):
|
|
60
|
+
self._logger.warning("userSetup.py : Infected by Malware!")
|
|
61
|
+
self._bad_files.append(rename(usersetup_py))
|
|
62
|
+
|
|
63
|
+
def before_callback(self, *args, **kwargs):
|
|
64
|
+
self.check_usersetup_py()
|
|
65
|
+
super(Vaccine, self).before_callback(args, kwargs)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import glob
|
|
3
|
+
import os.path
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
# Import third-party modules
|
|
7
|
+
import maya.cmds as cmds
|
|
8
|
+
|
|
9
|
+
# Import local modules
|
|
10
|
+
from maya_umbrella.filesystem import read_file
|
|
11
|
+
from maya_umbrella.filesystem import rename
|
|
12
|
+
from maya_umbrella.vaccine import BaseVaccine
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Vaccine(BaseVaccine):
|
|
16
|
+
virus_name = "virus2024429"
|
|
17
|
+
hik_regex = r"python\(\"import base64;\s*pyCode\s*=\s*base64\.urlsafe_b64decode\([\'\"].*?[\"\']\);\s*exec\s*\(\s*pyCode\s*\)\"\)\s*;"
|
|
18
|
+
_bad_files = []
|
|
19
|
+
|
|
20
|
+
def __init__(self, logger=None):
|
|
21
|
+
super(Vaccine, self).__init__(logger)
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def bad_files(self):
|
|
25
|
+
return self._bad_files
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def get_syssst_dir(self):
|
|
29
|
+
return os.path.join(os.getenv("APPDATA"), "syssst")
|
|
30
|
+
|
|
31
|
+
def _get_nodes(self):
|
|
32
|
+
bad_expression = []
|
|
33
|
+
for script_node in cmds.ls(type="script"):
|
|
34
|
+
if cmds.referenceQuery(script_node, isNodeReferenced=True):
|
|
35
|
+
continue
|
|
36
|
+
# check uifiguration
|
|
37
|
+
if cmds.objExists("{}.KGMScriptProtector".format(script_node)):
|
|
38
|
+
bad_expression.append(script_node)
|
|
39
|
+
# check vaccine
|
|
40
|
+
if "_gene" in script_node:
|
|
41
|
+
bad_expression.append(script_node)
|
|
42
|
+
|
|
43
|
+
return bad_expression
|
|
44
|
+
|
|
45
|
+
def check_usersetup_mel(self):
|
|
46
|
+
# check usersetup.mel
|
|
47
|
+
# C:/Users/hallong/Documents/maya/scripts/usersetup.mel
|
|
48
|
+
# C:/Users/hallong/Documents/maya/xxxx/scripts/usersetup.mel
|
|
49
|
+
for usersetup_mel in [
|
|
50
|
+
os.path.join(self.local_script_path, "usersetup.mel"),
|
|
51
|
+
os.path.join(self.user_script_path, "usersetup.mel"),
|
|
52
|
+
]:
|
|
53
|
+
if os.path.exists(usersetup_mel):
|
|
54
|
+
data = read_file(usersetup_mel)
|
|
55
|
+
if "import base64; pyCode = base64.urlsafe_b64decode" in data:
|
|
56
|
+
self._bad_files.append(rename(usersetup_mel))
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def bad_nodes(self):
|
|
60
|
+
return self._get_nodes()
|
|
61
|
+
|
|
62
|
+
def before_callback(self, *args, **kwargs):
|
|
63
|
+
self._bad_files.extend([self.get_syssst_dir])
|
|
64
|
+
self.check_usersetup_mel()
|
|
65
|
+
self.fix_hik_files()
|
|
66
|
+
self.fix_script_job()
|
|
67
|
+
super(Vaccine, self).before_callback(args, kwargs)
|
|
68
|
+
|
|
69
|
+
def fix_hik_files(self):
|
|
70
|
+
pattern = os.path.join(self.maya_install_root, "resources/l10n/*/plug-ins/mayaHIK.pres.mel")
|
|
71
|
+
for hik_mel in glob.glob(pattern):
|
|
72
|
+
with open(hik_mel, "rb") as f:
|
|
73
|
+
data = f.read()
|
|
74
|
+
try:
|
|
75
|
+
check = re.findall(self.hik_regex, data)
|
|
76
|
+
except TypeError:
|
|
77
|
+
check = []
|
|
78
|
+
if len(check) > 0:
|
|
79
|
+
with open(hik_mel, "wb") as f:
|
|
80
|
+
f.write(re.sub(self.hik_regex, "", data))
|
|
81
|
+
self._logger.warning("Remove virus code from {}".format(hik_mel))
|
|
82
|
+
|
|
83
|
+
def fix_script_job(self):
|
|
84
|
+
virus_gene = [
|
|
85
|
+
"leukocyte",
|
|
86
|
+
"execute",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
def get_virus_script_jobs():
|
|
90
|
+
"""Traverse the list of virus script job name.
|
|
91
|
+
Returns:
|
|
92
|
+
list: Malicious virus script job name.
|
|
93
|
+
"""
|
|
94
|
+
return [
|
|
95
|
+
scriptjob
|
|
96
|
+
for scriptjob in cmds.scriptJob(listJobs=True)
|
|
97
|
+
for virus in virus_gene
|
|
98
|
+
if virus in scriptjob
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
for script_job in get_virus_script_jobs():
|
|
102
|
+
script_num = int(script_job.split(":", 1)[0])
|
|
103
|
+
self._logger.info("Kill script job {}".format(script_job))
|
|
104
|
+
cmds.scriptJob(kill=script_num, force=True)
|
|
105
|
+
|
|
106
|
+
def after_callback(self, *args, **kwargs):
|
|
107
|
+
"""After callback."""
|
|
108
|
+
self.check_usersetup_mel()
|
|
109
|
+
self.fix_hik_files()
|
|
110
|
+
super(Vaccine, self).after_callback(args, kwargs)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Hal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: maya_umbrella
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Check and fix maya virus.
|
|
5
|
+
Home-page: https://github.com/loonghao/maya_umbrella
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: notifiers,python,Maya,dcc
|
|
8
|
+
Author: longhao
|
|
9
|
+
Author-email: hal.long@outlook.com
|
|
10
|
+
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 2
|
|
13
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Project-URL: Documentation, https://github.com/loonghao/maya_umbrella
|
|
23
|
+
Project-URL: Repository, https://github.com/loonghao/maya_umbrella
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# maya_umbrella
|
|
27
|
+
|
|
28
|
+
Check and fix maya virus.
|
|
29
|
+
|
|
30
|
+
[](https://github.com/wntrblm/nox)
|
|
31
|
+
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
32
|
+
[](#contributors-)
|
|
33
|
+
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# 发开环境设置
|
|
40
|
+
python 版本 3.9
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
pip install nox poetry
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
# 开发调试
|
|
47
|
+
|
|
48
|
+
```shell
|
|
49
|
+
nox -s maya-2020
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 在maya中测试
|
|
53
|
+
通过`nox -s maya-xxx`, 启动maya.
|
|
54
|
+
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,那么通过`nox -s maya-2018`
|
|
55
|
+
|
|
56
|
+
启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
|
|
57
|
+
```python
|
|
58
|
+
import manual_test_in_maya
|
|
59
|
+
|
|
60
|
+
manual_test_in_maya.start()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Contributors ✨
|
|
64
|
+
|
|
65
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
66
|
+
|
|
67
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
68
|
+
<!-- prettier-ignore-start -->
|
|
69
|
+
<!-- markdownlint-disable -->
|
|
70
|
+
<table>
|
|
71
|
+
<tbody>
|
|
72
|
+
<tr>
|
|
73
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loonghao"><img src="https://avatars1.githubusercontent.com/u/13111745?v=4?s=100" width="100px;" alt="Hal"/><br /><sub><b>Hal</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=loonghao" title="Code">💻</a></td>
|
|
74
|
+
</tr>
|
|
75
|
+
</tbody>
|
|
76
|
+
</table>
|
|
77
|
+
|
|
78
|
+
<!-- markdownlint-restore -->
|
|
79
|
+
<!-- prettier-ignore-end -->
|
|
80
|
+
|
|
81
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
82
|
+
|
|
83
|
+
This project follows the [all-contributors](https://allcontributors.org) specification.
|
|
84
|
+
Contributions of any kind are welcome!
|
|
85
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
maya_umbrella/__init__.py,sha256=XrGd2g7JVWk-K48K1SHETv1su1cDUj4rzeu36U8VOSc,88
|
|
2
|
+
maya_umbrella/__version__.py,sha256=VrXpHDu3erkzwl_WXrqINBm9xWkcyUy53IQOj042dOs,22
|
|
3
|
+
maya_umbrella/core.py,sha256=YVMYLsWGZZup1FRgRGaMRj25jbopw8kByOSsjxMaLKg,2512
|
|
4
|
+
maya_umbrella/filesystem.py,sha256=U6G4lG4-kbTc2lMVlpg3Umd0u0HVkU2i-AuiEFegDXU,3434
|
|
5
|
+
maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
maya_umbrella/hooks/delete_turtle.py,sha256=EYVXPYi7lBtlUqDFzS0NsftNomZtVBRD-uO705M4KN4,688
|
|
7
|
+
maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=JO0Y2FILrwP7rCW2dOqe_AMhe0OhMtZGHF3w2UAafew,1170
|
|
8
|
+
maya_umbrella/hooks/fix_model_panel.py,sha256=cJ65n0_OnFtyKYTnir6S3EluArb8qen1VoIQCpyHtCM,513
|
|
9
|
+
maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=iXXBZNiNYMnp8J0waBKPsEo_4TsTgD8zsV7mDbMM26E,341
|
|
10
|
+
maya_umbrella/vaccine.py,sha256=8ekUaa0xaizTOeDzDPtnsyVcj1puP_TUqXg5pdf2bGM,2045
|
|
11
|
+
maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
maya_umbrella/vaccines/vaccine1.py,sha256=gWz7wl38Uy8s1gRSgcf5g9kN9WrD510zaLuh8FgxYVk,460
|
|
13
|
+
maya_umbrella/vaccines/vaccine2.py,sha256=dt0CHfHZHmbUCWF58jBpgAVrIikISdkTFrYMcLr82Dw,2659
|
|
14
|
+
maya_umbrella/vaccines/vaccine3.py,sha256=e6sM4JFst_yLkX4wwW7KeHIZkI5i9WoCER1uzUUcPJQ,3756
|
|
15
|
+
maya_umbrella-0.3.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
|
|
16
|
+
maya_umbrella-0.3.0.dist-info/METADATA,sha256=DMn3Ff9evgj3noS6eh1Kh1o2UBeoZRPIljkmKGzVlzA,2818
|
|
17
|
+
maya_umbrella-0.3.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
|
|
18
|
+
maya_umbrella-0.3.0.dist-info/RECORD,,
|