maya-umbrella 0.12.1__py2.py3-none-any.whl → 0.14.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/__version__.py +1 -1
- maya_umbrella/_vendor/atomicwrites/LICENSE +19 -0
- maya_umbrella/_vendor/atomicwrites/__init__.py +229 -0
- maya_umbrella/_vendor/atomicwrites.pyi +1 -0
- maya_umbrella/_vendor/vendor.txt +1 -0
- maya_umbrella/cleaner.py +7 -0
- maya_umbrella/collector.py +1 -1
- maya_umbrella/filesystem.py +53 -49
- maya_umbrella/locales/en_US.json +18 -17
- maya_umbrella/locales/zh_CN.json +4 -3
- maya_umbrella/vaccines/vaccine3.py +2 -2
- {maya_umbrella-0.12.1.dist-info → maya_umbrella-0.14.0.dist-info}/METADATA +1 -1
- {maya_umbrella-0.12.1.dist-info → maya_umbrella-0.14.0.dist-info}/RECORD +15 -12
- {maya_umbrella-0.12.1.dist-info → maya_umbrella-0.14.0.dist-info}/LICENSE +0 -0
- {maya_umbrella-0.12.1.dist-info → maya_umbrella-0.14.0.dist-info}/WHEEL +0 -0
maya_umbrella/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.14.0"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2015-2016 Markus Unterwaditzer
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
5
|
+
the Software without restriction, including without limitation the rights to
|
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
8
|
+
so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import io
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import fcntl
|
|
9
|
+
except ImportError:
|
|
10
|
+
fcntl = None
|
|
11
|
+
|
|
12
|
+
# `fspath` was added in Python 3.6
|
|
13
|
+
try:
|
|
14
|
+
from os import fspath
|
|
15
|
+
except ImportError:
|
|
16
|
+
fspath = None
|
|
17
|
+
|
|
18
|
+
__version__ = '1.4.1'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
PY2 = sys.version_info[0] == 2
|
|
22
|
+
|
|
23
|
+
text_type = unicode if PY2 else str # noqa
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _path_to_unicode(x):
|
|
27
|
+
if not isinstance(x, text_type):
|
|
28
|
+
return x.decode(sys.getfilesystemencoding())
|
|
29
|
+
return x
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
DEFAULT_MODE = "wb" if PY2 else "w"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_proper_fsync = os.fsync
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if sys.platform != 'win32':
|
|
39
|
+
if hasattr(fcntl, 'F_FULLFSYNC'):
|
|
40
|
+
def _proper_fsync(fd):
|
|
41
|
+
# https://lists.apple.com/archives/darwin-dev/2005/Feb/msg00072.html
|
|
42
|
+
# https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fsync.2.html
|
|
43
|
+
# https://github.com/untitaker/python-atomicwrites/issues/6
|
|
44
|
+
fcntl.fcntl(fd, fcntl.F_FULLFSYNC)
|
|
45
|
+
|
|
46
|
+
def _sync_directory(directory):
|
|
47
|
+
# Ensure that filenames are written to disk
|
|
48
|
+
fd = os.open(directory, 0)
|
|
49
|
+
try:
|
|
50
|
+
_proper_fsync(fd)
|
|
51
|
+
finally:
|
|
52
|
+
os.close(fd)
|
|
53
|
+
|
|
54
|
+
def _replace_atomic(src, dst):
|
|
55
|
+
os.rename(src, dst)
|
|
56
|
+
_sync_directory(os.path.normpath(os.path.dirname(dst)))
|
|
57
|
+
|
|
58
|
+
def _move_atomic(src, dst):
|
|
59
|
+
os.link(src, dst)
|
|
60
|
+
os.unlink(src)
|
|
61
|
+
|
|
62
|
+
src_dir = os.path.normpath(os.path.dirname(src))
|
|
63
|
+
dst_dir = os.path.normpath(os.path.dirname(dst))
|
|
64
|
+
_sync_directory(dst_dir)
|
|
65
|
+
if src_dir != dst_dir:
|
|
66
|
+
_sync_directory(src_dir)
|
|
67
|
+
else:
|
|
68
|
+
from ctypes import windll, WinError
|
|
69
|
+
|
|
70
|
+
_MOVEFILE_REPLACE_EXISTING = 0x1
|
|
71
|
+
_MOVEFILE_WRITE_THROUGH = 0x8
|
|
72
|
+
_windows_default_flags = _MOVEFILE_WRITE_THROUGH
|
|
73
|
+
|
|
74
|
+
def _handle_errors(rv):
|
|
75
|
+
if not rv:
|
|
76
|
+
raise WinError()
|
|
77
|
+
|
|
78
|
+
def _replace_atomic(src, dst):
|
|
79
|
+
_handle_errors(windll.kernel32.MoveFileExW(
|
|
80
|
+
_path_to_unicode(src), _path_to_unicode(dst),
|
|
81
|
+
_windows_default_flags | _MOVEFILE_REPLACE_EXISTING
|
|
82
|
+
))
|
|
83
|
+
|
|
84
|
+
def _move_atomic(src, dst):
|
|
85
|
+
_handle_errors(windll.kernel32.MoveFileExW(
|
|
86
|
+
_path_to_unicode(src), _path_to_unicode(dst),
|
|
87
|
+
_windows_default_flags
|
|
88
|
+
))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def replace_atomic(src, dst):
|
|
92
|
+
'''
|
|
93
|
+
Move ``src`` to ``dst``. If ``dst`` exists, it will be silently
|
|
94
|
+
overwritten.
|
|
95
|
+
|
|
96
|
+
Both paths must reside on the same filesystem for the operation to be
|
|
97
|
+
atomic.
|
|
98
|
+
'''
|
|
99
|
+
return _replace_atomic(src, dst)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def move_atomic(src, dst):
|
|
103
|
+
'''
|
|
104
|
+
Move ``src`` to ``dst``. There might a timewindow where both filesystem
|
|
105
|
+
entries exist. If ``dst`` already exists, :py:exc:`FileExistsError` will be
|
|
106
|
+
raised.
|
|
107
|
+
|
|
108
|
+
Both paths must reside on the same filesystem for the operation to be
|
|
109
|
+
atomic.
|
|
110
|
+
'''
|
|
111
|
+
return _move_atomic(src, dst)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class AtomicWriter(object):
|
|
115
|
+
'''
|
|
116
|
+
A helper class for performing atomic writes. Usage::
|
|
117
|
+
|
|
118
|
+
with AtomicWriter(path).open() as f:
|
|
119
|
+
f.write(...)
|
|
120
|
+
|
|
121
|
+
:param path: The destination filepath. May or may not exist.
|
|
122
|
+
:param mode: The filemode for the temporary file. This defaults to `wb` in
|
|
123
|
+
Python 2 and `w` in Python 3.
|
|
124
|
+
:param overwrite: If set to false, an error is raised if ``path`` exists.
|
|
125
|
+
Errors are only raised after the file has been written to. Either way,
|
|
126
|
+
the operation is atomic.
|
|
127
|
+
:param open_kwargs: Keyword-arguments to pass to the underlying
|
|
128
|
+
:py:func:`open` call. This can be used to set the encoding when opening
|
|
129
|
+
files in text-mode.
|
|
130
|
+
|
|
131
|
+
If you need further control over the exact behavior, you are encouraged to
|
|
132
|
+
subclass.
|
|
133
|
+
'''
|
|
134
|
+
|
|
135
|
+
def __init__(self, path, mode=DEFAULT_MODE, overwrite=False,
|
|
136
|
+
**open_kwargs):
|
|
137
|
+
if 'a' in mode:
|
|
138
|
+
raise ValueError(
|
|
139
|
+
'Appending to an existing file is not supported, because that '
|
|
140
|
+
'would involve an expensive `copy`-operation to a temporary '
|
|
141
|
+
'file. Open the file in normal `w`-mode and copy explicitly '
|
|
142
|
+
'if that\'s what you\'re after.'
|
|
143
|
+
)
|
|
144
|
+
if 'x' in mode:
|
|
145
|
+
raise ValueError('Use the `overwrite`-parameter instead.')
|
|
146
|
+
if 'w' not in mode:
|
|
147
|
+
raise ValueError('AtomicWriters can only be written to.')
|
|
148
|
+
|
|
149
|
+
# Attempt to convert `path` to `str` or `bytes`
|
|
150
|
+
if fspath is not None:
|
|
151
|
+
path = fspath(path)
|
|
152
|
+
|
|
153
|
+
self._path = path
|
|
154
|
+
self._mode = mode
|
|
155
|
+
self._overwrite = overwrite
|
|
156
|
+
self._open_kwargs = open_kwargs
|
|
157
|
+
|
|
158
|
+
def open(self):
|
|
159
|
+
'''
|
|
160
|
+
Open the temporary file.
|
|
161
|
+
'''
|
|
162
|
+
return self._open(self.get_fileobject)
|
|
163
|
+
|
|
164
|
+
@contextlib.contextmanager
|
|
165
|
+
def _open(self, get_fileobject):
|
|
166
|
+
f = None # make sure f exists even if get_fileobject() fails
|
|
167
|
+
try:
|
|
168
|
+
success = False
|
|
169
|
+
with get_fileobject(**self._open_kwargs) as f:
|
|
170
|
+
yield f
|
|
171
|
+
self.sync(f)
|
|
172
|
+
self.commit(f)
|
|
173
|
+
success = True
|
|
174
|
+
finally:
|
|
175
|
+
if not success:
|
|
176
|
+
try:
|
|
177
|
+
self.rollback(f)
|
|
178
|
+
except Exception:
|
|
179
|
+
pass
|
|
180
|
+
|
|
181
|
+
def get_fileobject(self, suffix="", prefix=tempfile.gettempprefix(),
|
|
182
|
+
dir=None, **kwargs):
|
|
183
|
+
'''Return the temporary file to use.'''
|
|
184
|
+
if dir is None:
|
|
185
|
+
dir = os.path.normpath(os.path.dirname(self._path))
|
|
186
|
+
descriptor, name = tempfile.mkstemp(suffix=suffix, prefix=prefix,
|
|
187
|
+
dir=dir)
|
|
188
|
+
# io.open() will take either the descriptor or the name, but we need
|
|
189
|
+
# the name later for commit()/replace_atomic() and couldn't find a way
|
|
190
|
+
# to get the filename from the descriptor.
|
|
191
|
+
os.close(descriptor)
|
|
192
|
+
kwargs['mode'] = self._mode
|
|
193
|
+
kwargs['file'] = name
|
|
194
|
+
return io.open(**kwargs)
|
|
195
|
+
|
|
196
|
+
def sync(self, f):
|
|
197
|
+
'''responsible for clearing as many file caches as possible before
|
|
198
|
+
commit'''
|
|
199
|
+
f.flush()
|
|
200
|
+
_proper_fsync(f.fileno())
|
|
201
|
+
|
|
202
|
+
def commit(self, f):
|
|
203
|
+
'''Move the temporary file to the target location.'''
|
|
204
|
+
if self._overwrite:
|
|
205
|
+
replace_atomic(f.name, self._path)
|
|
206
|
+
else:
|
|
207
|
+
move_atomic(f.name, self._path)
|
|
208
|
+
|
|
209
|
+
def rollback(self, f):
|
|
210
|
+
'''Clean up all temporary resources.'''
|
|
211
|
+
os.unlink(f.name)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def atomic_write(path, writer_cls=AtomicWriter, **cls_kwargs):
|
|
215
|
+
'''
|
|
216
|
+
Simple atomic writes. This wraps :py:class:`AtomicWriter`::
|
|
217
|
+
|
|
218
|
+
with atomic_write(path) as f:
|
|
219
|
+
f.write(...)
|
|
220
|
+
|
|
221
|
+
:param path: The target path to write to.
|
|
222
|
+
:param writer_cls: The writer class to use. This parameter is useful if you
|
|
223
|
+
subclassed :py:class:`AtomicWriter` to change some behavior and want to
|
|
224
|
+
use that new subclass.
|
|
225
|
+
|
|
226
|
+
Additional keyword arguments are passed to the writer class. See
|
|
227
|
+
:py:class:`AtomicWriter`.
|
|
228
|
+
'''
|
|
229
|
+
return writer_cls(path, **cls_kwargs).open()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from atomicwrites import *
|
maya_umbrella/_vendor/vendor.txt
CHANGED
maya_umbrella/cleaner.py
CHANGED
|
@@ -22,6 +22,7 @@ class MayaVirusCleaner(object):
|
|
|
22
22
|
translator (Translator): Translator object for translation purposes.
|
|
23
23
|
collector (MayaVirusCollector): MayaVirusCollector object for collecting issues.
|
|
24
24
|
"""
|
|
25
|
+
|
|
25
26
|
def __init__(self, collector, logger=None):
|
|
26
27
|
"""Initialize the MayaVirusCleaner.
|
|
27
28
|
|
|
@@ -50,6 +51,9 @@ class MayaVirusCleaner(object):
|
|
|
50
51
|
def fix_malicious_files(self):
|
|
51
52
|
"""Fix malicious files."""
|
|
52
53
|
for file_ in self.collector.malicious_files:
|
|
54
|
+
if not os.access(file_, os.W_OK):
|
|
55
|
+
self.logger.debug(self.translator.translate("file_not_writable", name=file_))
|
|
56
|
+
continue
|
|
53
57
|
if os.path.exists(file_):
|
|
54
58
|
if os.path.isfile(file_):
|
|
55
59
|
self.logger.debug(self.translator.translate("remove_file", name=file_))
|
|
@@ -94,6 +98,9 @@ class MayaVirusCleaner(object):
|
|
|
94
98
|
"""Fix infected files."""
|
|
95
99
|
for file_path in self.collector.infected_files:
|
|
96
100
|
self.logger.info(self.translator.translate("fix_infected_files", name=file_path))
|
|
101
|
+
if not os.access(file_path, os.W_OK):
|
|
102
|
+
self.logger.debug(self.translator.translate("file_not_writable", name=file_path))
|
|
103
|
+
continue
|
|
97
104
|
remove_virus_file_by_signature(file_path, FILE_VIRUS_SIGNATURES)
|
|
98
105
|
self.collector.remove_infected_file(file_path)
|
|
99
106
|
|
maya_umbrella/collector.py
CHANGED
|
@@ -74,7 +74,7 @@ class MayaVirusCollector(object):
|
|
|
74
74
|
@property
|
|
75
75
|
def maya_install_root(self):
|
|
76
76
|
"""Return the Maya installation root directory."""
|
|
77
|
-
return os.environ
|
|
77
|
+
return os.environ.get("MAYA_LOCATION", "")
|
|
78
78
|
|
|
79
79
|
@property
|
|
80
80
|
def user_script_path(self):
|
maya_umbrella/filesystem.py
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
-
from contextlib import contextmanager
|
|
3
2
|
import glob
|
|
4
3
|
import importlib
|
|
5
4
|
import json
|
|
6
5
|
import logging
|
|
7
6
|
import os
|
|
8
|
-
import random
|
|
9
7
|
import re
|
|
10
8
|
import shutil
|
|
11
|
-
import string
|
|
12
9
|
import tempfile
|
|
13
10
|
|
|
14
11
|
# Import local modules
|
|
15
12
|
from maya_umbrella._vendor import six
|
|
13
|
+
from maya_umbrella._vendor.atomicwrites import atomic_write
|
|
16
14
|
from maya_umbrella.constants import PACKAGE_NAME
|
|
17
15
|
from maya_umbrella.signatures import FILE_VIRUS_SIGNATURES
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
def this_root():
|
|
21
|
-
"""Return the absolute path of the current file's directory.
|
|
19
|
+
"""Return the absolute path of the current file's directory.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: The absolute path of the current file's directory.
|
|
23
|
+
"""
|
|
22
24
|
return os.path.abspath(os.path.dirname(__file__))
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
def safe_remove_file(file_path):
|
|
26
|
-
"""Remove the file at the given path without raising an error if the file does not exist.
|
|
28
|
+
"""Remove the file at the given path without raising an error if the file does not exist.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
file_path (str): Path to the file to remove.
|
|
32
|
+
"""
|
|
27
33
|
try:
|
|
28
34
|
os.remove(file_path)
|
|
29
35
|
except (OSError, IOError): # noqa: UP024
|
|
@@ -31,7 +37,11 @@ def safe_remove_file(file_path):
|
|
|
31
37
|
|
|
32
38
|
|
|
33
39
|
def safe_rmtree(path):
|
|
34
|
-
"""Remove the directory at the given path without raising an error if the directory does not exist.
|
|
40
|
+
"""Remove the directory at the given path without raising an error if the directory does not exist.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
path (str): Path to the directory to remove.
|
|
44
|
+
"""
|
|
35
45
|
try:
|
|
36
46
|
shutil.rmtree(path)
|
|
37
47
|
except (OSError, IOError): # noqa: UP024
|
|
@@ -54,7 +64,14 @@ def read_file(path):
|
|
|
54
64
|
|
|
55
65
|
|
|
56
66
|
def read_json(path):
|
|
57
|
-
"""Read the content of
|
|
67
|
+
"""Read the content of a JSON file at the given path.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
path (str): Path to the JSON file.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
dict: The content of the JSON file as a dictionary, or an empty dictionary if the file could not be read.
|
|
74
|
+
"""
|
|
58
75
|
options = {"encoding": "utf-8"} if six.PY3 else {}
|
|
59
76
|
with open(path, **options) as file_:
|
|
60
77
|
try:
|
|
@@ -65,53 +82,28 @@ def read_json(path):
|
|
|
65
82
|
|
|
66
83
|
|
|
67
84
|
def write_file(path, content):
|
|
68
|
-
"""Write the given content to the file at the given path.
|
|
69
|
-
with atomic_writes(path, "wb") as file_:
|
|
70
|
-
file_.write(six.ensure_binary(content))
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@contextmanager
|
|
74
|
-
def atomic_writes(src, mode):
|
|
75
|
-
"""Context manager for atomic writes to a file.
|
|
76
|
-
|
|
77
|
-
This context manager ensures that the file is only written to disk if the write operation completes without errors.
|
|
85
|
+
"""Write the given content to the file at the given path.
|
|
78
86
|
|
|
79
87
|
Args:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
**options: Arbitrary keyword arguments that are passed to the built-in open() function.
|
|
83
|
-
|
|
84
|
-
Yields:
|
|
85
|
-
file object: The opened file object.
|
|
86
|
-
|
|
87
|
-
Raises:
|
|
88
|
-
AttributeError: If the os module does not have the 'replace' function (Python 2 compatibility).
|
|
88
|
+
path (str): Path to the file to write.
|
|
89
|
+
content (str): Content to write to the file.
|
|
89
90
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
except AttributeError:
|
|
96
|
-
shutil.move(temp_path, src)
|
|
97
|
-
|
|
98
|
-
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
|
99
|
-
"""Generate a random string of the given size using the given characters."""
|
|
100
|
-
return "".join(random.choice(chars) for _ in range(size))
|
|
91
|
+
root = os.path.dirname(path)
|
|
92
|
+
if not os.path.exists(root):
|
|
93
|
+
os.makedirs(root)
|
|
94
|
+
with atomic_write(path, mode="wb", overwrite=True) as file_:
|
|
95
|
+
file_.write(six.ensure_binary(content))
|
|
101
96
|
|
|
102
97
|
|
|
103
|
-
def
|
|
104
|
-
"""
|
|
105
|
-
dst = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
|
|
106
|
-
try:
|
|
107
|
-
os.rename(src, dst)
|
|
108
|
-
except (OSError, IOError): # noqa: UP024
|
|
109
|
-
return src
|
|
110
|
-
return dst
|
|
98
|
+
def load_hook(hook_file):
|
|
99
|
+
"""Load the Python module from the given hook file.
|
|
111
100
|
|
|
101
|
+
Args:
|
|
102
|
+
hook_file (str): Path to the Python file to load.
|
|
112
103
|
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
Returns:
|
|
105
|
+
module: The loaded Python module.
|
|
106
|
+
"""
|
|
115
107
|
hook_name = os.path.basename(hook_file).split(".py")[0]
|
|
116
108
|
if hasattr(importlib, "machinery"):
|
|
117
109
|
# Python 3
|
|
@@ -132,7 +124,11 @@ def load_hook(hook_file):
|
|
|
132
124
|
|
|
133
125
|
|
|
134
126
|
def get_hooks():
|
|
135
|
-
"""Return a list of paths to all hook files in the 'hooks' directory.
|
|
127
|
+
"""Return a list of paths to all hook files in the 'hooks' directory.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
list: A list of paths to all hook files in the 'hooks' directory.
|
|
131
|
+
"""
|
|
136
132
|
pattern = os.path.join(this_root(), "hooks", "*.py")
|
|
137
133
|
return [hook for hook in glob.glob(pattern) if "__init__" not in hook]
|
|
138
134
|
|
|
@@ -187,6 +183,7 @@ def remove_virus_file_by_signature(file_path, signatures, output_file_path=None,
|
|
|
187
183
|
fixed_data = replace_content_by_signatures(data, signatures).strip()
|
|
188
184
|
if fixed_data:
|
|
189
185
|
write_file(output_file_path or file_path, fixed_data)
|
|
186
|
+
|
|
190
187
|
else:
|
|
191
188
|
# Auto remove empty files.
|
|
192
189
|
if auto_remove:
|
|
@@ -273,7 +270,14 @@ def get_backup_path(path, root_path=None):
|
|
|
273
270
|
|
|
274
271
|
|
|
275
272
|
def get_maya_install_root(maya_version):
|
|
276
|
-
"""Get the Maya install root path.
|
|
273
|
+
"""Get the Maya install root path for the specified version.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
maya_version (str): The version of Maya to find the install root for.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
str: The Maya install root path, or None if not found.
|
|
280
|
+
"""
|
|
277
281
|
logger = logging.getLogger(__name__)
|
|
278
282
|
maya_location = os.getenv("MAYA_LOCATION")
|
|
279
283
|
try:
|
maya_umbrella/locales/en_US.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
"start_fix_issues": "Start fixing all problems related to Maya virus $name",
|
|
3
|
+
"finish_fix_issues": "Repair completed.",
|
|
4
|
+
"init_message": "Successfully loaded <hl>maya_umbrella</hl> protection.",
|
|
5
|
+
"init_standalone_message": "----------------------- successfully loaded maya_umbrella-----------------------",
|
|
6
|
+
"report_issue": "$name: Maliciously infected!",
|
|
7
|
+
"infected_nodes": "Infected node: $name:",
|
|
8
|
+
"bad_files": "Files to be cleaned up: $name",
|
|
9
|
+
"infected_script_jobs": "Infected Script jobs: $name",
|
|
10
|
+
"infected_files": "Infected file: $name",
|
|
11
|
+
"infected_reference_files": "Infected reference file: $name",
|
|
12
|
+
"fix_infected_files": "Clean up infected files: $name",
|
|
13
|
+
"fix_infected_nodes": "Delete infected node: $name",
|
|
14
|
+
"fix_infected_reference_nodes": "Attempt to repair the infected reference node: $name",
|
|
15
|
+
"delete": "Delete infected files: $name",
|
|
16
|
+
"remove_file": "Delete file: $name",
|
|
17
|
+
"remove_path": "Delete folder: $name",
|
|
18
|
+
"fix_script_job": "Delete infected node: $name",
|
|
19
|
+
"file_not_writable": "The file is not writable: $name"
|
|
19
20
|
}
|
maya_umbrella/locales/zh_CN.json
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"report_issue": "$name:被恶意感染!",
|
|
7
7
|
"infected_nodes": "被感染节点:$name: ",
|
|
8
8
|
"bad_files": "需要被清理的文件:$name",
|
|
9
|
-
"infected_script_jobs": "被感染的
|
|
10
|
-
"infected_files": "
|
|
9
|
+
"infected_script_jobs": "被感染的Script jobs:$name",
|
|
10
|
+
"infected_files": "被感染的文件:$name",
|
|
11
11
|
"infected_reference_files": "被感染的参考文件:$name",
|
|
12
12
|
"fix_infected_files": "清理被感染的文件:$name",
|
|
13
13
|
"fix_infected_nodes": "删除被感染的节点:$name",
|
|
@@ -15,5 +15,6 @@
|
|
|
15
15
|
"delete": "删除感染文件:$name",
|
|
16
16
|
"remove_file": "删除文件:$name",
|
|
17
17
|
"remove_path": "删除文件夹:$name",
|
|
18
|
-
"fix_script_job": "删除被感染的节点:$name"
|
|
18
|
+
"fix_script_job": "删除被感染的节点:$name",
|
|
19
|
+
"file_not_writable": "文件不可写:$name"
|
|
19
20
|
}
|
|
@@ -71,7 +71,7 @@ class Vaccine(AbstractVaccine):
|
|
|
71
71
|
if virus in script_job:
|
|
72
72
|
self.api.add_infected_script_job(script_job)
|
|
73
73
|
|
|
74
|
-
def
|
|
74
|
+
def collect_infected_hik_files(self):
|
|
75
75
|
"""Fix all bad HIK files related to the virus."""
|
|
76
76
|
pattern = os.path.join(self.api.maya_install_root, "resources/l10n/*/plug-ins/mayaHIK.pres.mel")
|
|
77
77
|
for hik_mel in glob.glob(pattern):
|
|
@@ -83,8 +83,8 @@ class Vaccine(AbstractVaccine):
|
|
|
83
83
|
"""Collect all issues related to the virus."""
|
|
84
84
|
self.api.add_malicious_file(os.path.join(os.getenv("APPDATA"), "syssst"))
|
|
85
85
|
self.collect_infected_mel_files()
|
|
86
|
+
self.collect_infected_hik_files()
|
|
86
87
|
self.collect_infected_nodes()
|
|
87
88
|
# This only works for Maya Gui model.
|
|
88
89
|
if not is_maya_standalone():
|
|
89
90
|
self.collect_script_jobs()
|
|
90
|
-
self.api.add_additionally_fix_function(self.fix_bad_hik_files)
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
maya_umbrella/__init__.py,sha256=rcCnFWmELeJsGoKvLHyzC_GmZu-eT1QXjQCHRGj6HuQ,529
|
|
2
|
-
maya_umbrella/__version__.py,sha256=
|
|
2
|
+
maya_umbrella/__version__.py,sha256=EVkhkQ4Bbkx92jXuCmt2_JDjQExgnrq2d3eBQIP9UAo,23
|
|
3
3
|
maya_umbrella/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
maya_umbrella/_vendor/atomicwrites/LICENSE,sha256=h4Mp8L2HitAVEpzovagvSB6G7C6Agx6QnA1nFx2SLnM,1069
|
|
5
|
+
maya_umbrella/_vendor/atomicwrites/__init__.py,sha256=myvxvKRBb7vebPTSUiAopsRrvsm6VojiAvET1xohT-4,6970
|
|
6
|
+
maya_umbrella/_vendor/atomicwrites.pyi,sha256=kofmo9N_ix4812ioT1GEwo8HTtOWvnmarf_FIKY2czg,27
|
|
4
7
|
maya_umbrella/_vendor/six/__init__.pyi,sha256=tU6T1qIa_1HEM5lYdk7qw9E3GdDokvpzy5D06PhlMfA,18
|
|
5
8
|
maya_umbrella/_vendor/six/moves/__init__.pyi,sha256=jVS195D1cetBSWcwZ61-NYkaaI-EKlXjoF1o0I_pG9I,24
|
|
6
9
|
maya_umbrella/_vendor/six/moves/configparser.pyi,sha256=OOloYod0yM3pPe0YlqnFSkiWejxtFwN-Gs0YPYHY1Nc,37
|
|
7
10
|
maya_umbrella/_vendor/six.LICENSE,sha256=i7hQxWWqOJ_cFvOkaWWtI9gq3_YPI5P8J2K2MYXo5sk,1066
|
|
8
11
|
maya_umbrella/_vendor/six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549
|
|
9
|
-
maya_umbrella/_vendor/vendor.txt,sha256=
|
|
10
|
-
maya_umbrella/cleaner.py,sha256=
|
|
11
|
-
maya_umbrella/collector.py,sha256=
|
|
12
|
+
maya_umbrella/_vendor/vendor.txt,sha256=9yyM8r0ibzfkXqgcAehZId0IsvELLV18YTxi6cwF7KA,32
|
|
13
|
+
maya_umbrella/cleaner.py,sha256=T_-QgF7Or9Bqoa463YZm2trhwGu0-KfbyiozXj3G86o,5384
|
|
14
|
+
maya_umbrella/collector.py,sha256=SiC-wpDjer7w6ofsyWTFJmUF8pPz233xDXeANNz-LrY,13119
|
|
12
15
|
maya_umbrella/constants.py,sha256=SuD8OP8e0Kh3a9ohyS5_MXjo5pHNQ8MWEPtJ6puZfIU,130
|
|
13
16
|
maya_umbrella/defender.py,sha256=eT4uK23uOB1V8Y3uiaU1C2Tp-s1SngrGo3TWDbSIVJY,6008
|
|
14
|
-
maya_umbrella/filesystem.py,sha256=
|
|
17
|
+
maya_umbrella/filesystem.py,sha256=E1bs4WguYI9cKr6JnfyERu2fVE9Ii9qYUv-DcfVZa1k,9194
|
|
15
18
|
maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
19
|
maya_umbrella/hooks/delete_turtle.py,sha256=OPFRFH1iwonHvETndrP87MZQlJLhxpe564AJE3KyJY8,761
|
|
17
20
|
maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=5YXaOem-t9Em1sr3wmBqWk5He1Lm8CsOMQsSQ3ixLfs,1293
|
|
@@ -19,8 +22,8 @@ maya_umbrella/hooks/fix_model_panel.py,sha256=dLuMOz5uQ1nqAboNWMCx-Bi_gHM3FQNTlG
|
|
|
19
22
|
maya_umbrella/hooks/fix_no_scene_name.py,sha256=isE7_uOcByVbg9YG6FenzmJrodoteo8sheVzyDnrFqY,381
|
|
20
23
|
maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=o4WEQPcHNzaTMXdNnHZWWNCYlHfLxcSFYXR4YW0ZLwk,484
|
|
21
24
|
maya_umbrella/i18n.py,sha256=aWaIncHh5Zq02hErMbHHLoQm_8Fu-YfBWQ15sUgsBJk,2642
|
|
22
|
-
maya_umbrella/locales/en_US.json,sha256=
|
|
23
|
-
maya_umbrella/locales/zh_CN.json,sha256=
|
|
25
|
+
maya_umbrella/locales/en_US.json,sha256=Kcgg5BrNFSw7kUFkbepRIhXcUek4Kb0m43b0NmAkT2g,1095
|
|
26
|
+
maya_umbrella/locales/zh_CN.json,sha256=eQbsZsUj87B5HhHi_usTNGzwo01MLjkHKM11KWhhSwM,1056
|
|
24
27
|
maya_umbrella/log.py,sha256=SLgBPpnDpkDhOU94UHNPqanhKr6aZiJn4XdwIsoXD4M,1355
|
|
25
28
|
maya_umbrella/maya_funs.py,sha256=_4LaMO4cRTCcbgNj2ei7UtSLAnCRY_ylHiLGKgvM4sE,3652
|
|
26
29
|
maya_umbrella/scanner.py,sha256=1-GY-Jx1iECnAo-L2Lw5e5t5zaQsMwWDH0A4TOjlIww,4428
|
|
@@ -29,8 +32,8 @@ maya_umbrella/vaccine.py,sha256=aBW6pdT4tD4OMBPZ-d3E4_n16Rylz-2gb7JWzMZVPK0,1022
|
|
|
29
32
|
maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
33
|
maya_umbrella/vaccines/vaccine1.py,sha256=WLo1uJElTLSjVCf5CBtRNU4HKs63my5mkHiGqTfnNEE,489
|
|
31
34
|
maya_umbrella/vaccines/vaccine2.py,sha256=qYiI_-BSojgN7j4esYCGBDLeyBSneDOGUwZhKHccxh8,2170
|
|
32
|
-
maya_umbrella/vaccines/vaccine3.py,sha256=
|
|
33
|
-
maya_umbrella-0.
|
|
34
|
-
maya_umbrella-0.
|
|
35
|
-
maya_umbrella-0.
|
|
36
|
-
maya_umbrella-0.
|
|
35
|
+
maya_umbrella/vaccines/vaccine3.py,sha256=f1jO9pyyZ_Ep18HR-fCQfGEi-TnNKXzjdCi9ORSZUx0,3613
|
|
36
|
+
maya_umbrella-0.14.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
|
|
37
|
+
maya_umbrella-0.14.0.dist-info/METADATA,sha256=CPasuVog_jZMUHuIdjwgvGcgItpIYkrV3HXP7are7Vg,11722
|
|
38
|
+
maya_umbrella-0.14.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
|
|
39
|
+
maya_umbrella-0.14.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|