Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/setuptools/sandbox.py
4798 views
1
import os
2
import sys
3
import tempfile
4
import operator
5
import functools
6
import itertools
7
import re
8
import contextlib
9
import pickle
10
import textwrap
11
import builtins
12
13
import pkg_resources
14
from distutils.errors import DistutilsError
15
from pkg_resources import working_set
16
17
if sys.platform.startswith('java'):
18
import org.python.modules.posix.PosixModule as _os
19
else:
20
_os = sys.modules[os.name]
21
try:
22
_file = file
23
except NameError:
24
_file = None
25
_open = open
26
27
28
__all__ = [
29
"AbstractSandbox",
30
"DirectorySandbox",
31
"SandboxViolation",
32
"run_setup",
33
]
34
35
36
def _execfile(filename, globals, locals=None):
37
"""
38
Python 3 implementation of execfile.
39
"""
40
mode = 'rb'
41
with open(filename, mode) as stream:
42
script = stream.read()
43
if locals is None:
44
locals = globals
45
code = compile(script, filename, 'exec')
46
exec(code, globals, locals)
47
48
49
@contextlib.contextmanager
50
def save_argv(repl=None):
51
saved = sys.argv[:]
52
if repl is not None:
53
sys.argv[:] = repl
54
try:
55
yield saved
56
finally:
57
sys.argv[:] = saved
58
59
60
@contextlib.contextmanager
61
def save_path():
62
saved = sys.path[:]
63
try:
64
yield saved
65
finally:
66
sys.path[:] = saved
67
68
69
@contextlib.contextmanager
70
def override_temp(replacement):
71
"""
72
Monkey-patch tempfile.tempdir with replacement, ensuring it exists
73
"""
74
os.makedirs(replacement, exist_ok=True)
75
76
saved = tempfile.tempdir
77
78
tempfile.tempdir = replacement
79
80
try:
81
yield
82
finally:
83
tempfile.tempdir = saved
84
85
86
@contextlib.contextmanager
87
def pushd(target):
88
saved = os.getcwd()
89
os.chdir(target)
90
try:
91
yield saved
92
finally:
93
os.chdir(saved)
94
95
96
class UnpickleableException(Exception):
97
"""
98
An exception representing another Exception that could not be pickled.
99
"""
100
101
@staticmethod
102
def dump(type, exc):
103
"""
104
Always return a dumped (pickled) type and exc. If exc can't be pickled,
105
wrap it in UnpickleableException first.
106
"""
107
try:
108
return pickle.dumps(type), pickle.dumps(exc)
109
except Exception:
110
# get UnpickleableException inside the sandbox
111
from setuptools.sandbox import UnpickleableException as cls
112
113
return cls.dump(cls, cls(repr(exc)))
114
115
116
class ExceptionSaver:
117
"""
118
A Context Manager that will save an exception, serialized, and restore it
119
later.
120
"""
121
122
def __enter__(self):
123
return self
124
125
def __exit__(self, type, exc, tb):
126
if not exc:
127
return
128
129
# dump the exception
130
self._saved = UnpickleableException.dump(type, exc)
131
self._tb = tb
132
133
# suppress the exception
134
return True
135
136
def resume(self):
137
"restore and re-raise any exception"
138
139
if '_saved' not in vars(self):
140
return
141
142
type, exc = map(pickle.loads, self._saved)
143
raise exc.with_traceback(self._tb)
144
145
146
@contextlib.contextmanager
147
def save_modules():
148
"""
149
Context in which imported modules are saved.
150
151
Translates exceptions internal to the context into the equivalent exception
152
outside the context.
153
"""
154
saved = sys.modules.copy()
155
with ExceptionSaver() as saved_exc:
156
yield saved
157
158
sys.modules.update(saved)
159
# remove any modules imported since
160
del_modules = (
161
mod_name
162
for mod_name in sys.modules
163
if mod_name not in saved
164
# exclude any encodings modules. See #285
165
and not mod_name.startswith('encodings.')
166
)
167
_clear_modules(del_modules)
168
169
saved_exc.resume()
170
171
172
def _clear_modules(module_names):
173
for mod_name in list(module_names):
174
del sys.modules[mod_name]
175
176
177
@contextlib.contextmanager
178
def save_pkg_resources_state():
179
saved = pkg_resources.__getstate__()
180
try:
181
yield saved
182
finally:
183
pkg_resources.__setstate__(saved)
184
185
186
@contextlib.contextmanager
187
def setup_context(setup_dir):
188
temp_dir = os.path.join(setup_dir, 'temp')
189
with save_pkg_resources_state():
190
with save_modules():
191
with save_path():
192
hide_setuptools()
193
with save_argv():
194
with override_temp(temp_dir):
195
with pushd(setup_dir):
196
# ensure setuptools commands are available
197
__import__('setuptools')
198
yield
199
200
201
_MODULES_TO_HIDE = {
202
'setuptools',
203
'distutils',
204
'pkg_resources',
205
'Cython',
206
'_distutils_hack',
207
}
208
209
210
def _needs_hiding(mod_name):
211
"""
212
>>> _needs_hiding('setuptools')
213
True
214
>>> _needs_hiding('pkg_resources')
215
True
216
>>> _needs_hiding('setuptools_plugin')
217
False
218
>>> _needs_hiding('setuptools.__init__')
219
True
220
>>> _needs_hiding('distutils')
221
True
222
>>> _needs_hiding('os')
223
False
224
>>> _needs_hiding('Cython')
225
True
226
"""
227
base_module = mod_name.split('.', 1)[0]
228
return base_module in _MODULES_TO_HIDE
229
230
231
def hide_setuptools():
232
"""
233
Remove references to setuptools' modules from sys.modules to allow the
234
invocation to import the most appropriate setuptools. This technique is
235
necessary to avoid issues such as #315 where setuptools upgrading itself
236
would fail to find a function declared in the metadata.
237
"""
238
_distutils_hack = sys.modules.get('_distutils_hack', None)
239
if _distutils_hack is not None:
240
_distutils_hack.remove_shim()
241
242
modules = filter(_needs_hiding, sys.modules)
243
_clear_modules(modules)
244
245
246
def run_setup(setup_script, args):
247
"""Run a distutils setup script, sandboxed in its directory"""
248
setup_dir = os.path.abspath(os.path.dirname(setup_script))
249
with setup_context(setup_dir):
250
try:
251
sys.argv[:] = [setup_script] + list(args)
252
sys.path.insert(0, setup_dir)
253
# reset to include setup dir, w/clean callback list
254
working_set.__init__()
255
working_set.callbacks.append(lambda dist: dist.activate())
256
257
with DirectorySandbox(setup_dir):
258
ns = dict(__file__=setup_script, __name__='__main__')
259
_execfile(setup_script, ns)
260
except SystemExit as v:
261
if v.args and v.args[0]:
262
raise
263
# Normal exit, just return
264
265
266
class AbstractSandbox:
267
"""Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
268
269
_active = False
270
271
def __init__(self):
272
self._attrs = [
273
name
274
for name in dir(_os)
275
if not name.startswith('_') and hasattr(self, name)
276
]
277
278
def _copy(self, source):
279
for name in self._attrs:
280
setattr(os, name, getattr(source, name))
281
282
def __enter__(self):
283
self._copy(self)
284
if _file:
285
builtins.file = self._file
286
builtins.open = self._open
287
self._active = True
288
289
def __exit__(self, exc_type, exc_value, traceback):
290
self._active = False
291
if _file:
292
builtins.file = _file
293
builtins.open = _open
294
self._copy(_os)
295
296
def run(self, func):
297
"""Run 'func' under os sandboxing"""
298
with self:
299
return func()
300
301
def _mk_dual_path_wrapper(name):
302
original = getattr(_os, name)
303
304
def wrap(self, src, dst, *args, **kw):
305
if self._active:
306
src, dst = self._remap_pair(name, src, dst, *args, **kw)
307
return original(src, dst, *args, **kw)
308
309
return wrap
310
311
for name in ["rename", "link", "symlink"]:
312
if hasattr(_os, name):
313
locals()[name] = _mk_dual_path_wrapper(name)
314
315
def _mk_single_path_wrapper(name, original=None):
316
original = original or getattr(_os, name)
317
318
def wrap(self, path, *args, **kw):
319
if self._active:
320
path = self._remap_input(name, path, *args, **kw)
321
return original(path, *args, **kw)
322
323
return wrap
324
325
if _file:
326
_file = _mk_single_path_wrapper('file', _file)
327
_open = _mk_single_path_wrapper('open', _open)
328
for name in [
329
"stat",
330
"listdir",
331
"chdir",
332
"open",
333
"chmod",
334
"chown",
335
"mkdir",
336
"remove",
337
"unlink",
338
"rmdir",
339
"utime",
340
"lchown",
341
"chroot",
342
"lstat",
343
"startfile",
344
"mkfifo",
345
"mknod",
346
"pathconf",
347
"access",
348
]:
349
if hasattr(_os, name):
350
locals()[name] = _mk_single_path_wrapper(name)
351
352
def _mk_single_with_return(name):
353
original = getattr(_os, name)
354
355
def wrap(self, path, *args, **kw):
356
if self._active:
357
path = self._remap_input(name, path, *args, **kw)
358
return self._remap_output(name, original(path, *args, **kw))
359
return original(path, *args, **kw)
360
361
return wrap
362
363
for name in ['readlink', 'tempnam']:
364
if hasattr(_os, name):
365
locals()[name] = _mk_single_with_return(name)
366
367
def _mk_query(name):
368
original = getattr(_os, name)
369
370
def wrap(self, *args, **kw):
371
retval = original(*args, **kw)
372
if self._active:
373
return self._remap_output(name, retval)
374
return retval
375
376
return wrap
377
378
for name in ['getcwd', 'tmpnam']:
379
if hasattr(_os, name):
380
locals()[name] = _mk_query(name)
381
382
def _validate_path(self, path):
383
"""Called to remap or validate any path, whether input or output"""
384
return path
385
386
def _remap_input(self, operation, path, *args, **kw):
387
"""Called for path inputs"""
388
return self._validate_path(path)
389
390
def _remap_output(self, operation, path):
391
"""Called for path outputs"""
392
return self._validate_path(path)
393
394
def _remap_pair(self, operation, src, dst, *args, **kw):
395
"""Called for path pairs like rename, link, and symlink operations"""
396
return (
397
self._remap_input(operation + '-from', src, *args, **kw),
398
self._remap_input(operation + '-to', dst, *args, **kw),
399
)
400
401
402
if hasattr(os, 'devnull'):
403
_EXCEPTIONS = [os.devnull]
404
else:
405
_EXCEPTIONS = []
406
407
408
class DirectorySandbox(AbstractSandbox):
409
"""Restrict operations to a single subdirectory - pseudo-chroot"""
410
411
write_ops = dict.fromkeys(
412
[
413
"open",
414
"chmod",
415
"chown",
416
"mkdir",
417
"remove",
418
"unlink",
419
"rmdir",
420
"utime",
421
"lchown",
422
"chroot",
423
"mkfifo",
424
"mknod",
425
"tempnam",
426
]
427
)
428
429
_exception_patterns = []
430
"exempt writing to paths that match the pattern"
431
432
def __init__(self, sandbox, exceptions=_EXCEPTIONS):
433
self._sandbox = os.path.normcase(os.path.realpath(sandbox))
434
self._prefix = os.path.join(self._sandbox, '')
435
self._exceptions = [
436
os.path.normcase(os.path.realpath(path)) for path in exceptions
437
]
438
AbstractSandbox.__init__(self)
439
440
def _violation(self, operation, *args, **kw):
441
from setuptools.sandbox import SandboxViolation
442
443
raise SandboxViolation(operation, args, kw)
444
445
if _file:
446
447
def _file(self, path, mode='r', *args, **kw):
448
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
449
self._violation("file", path, mode, *args, **kw)
450
return _file(path, mode, *args, **kw)
451
452
def _open(self, path, mode='r', *args, **kw):
453
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
454
self._violation("open", path, mode, *args, **kw)
455
return _open(path, mode, *args, **kw)
456
457
def tmpnam(self):
458
self._violation("tmpnam")
459
460
def _ok(self, path):
461
active = self._active
462
try:
463
self._active = False
464
realpath = os.path.normcase(os.path.realpath(path))
465
return (
466
self._exempted(realpath)
467
or realpath == self._sandbox
468
or realpath.startswith(self._prefix)
469
)
470
finally:
471
self._active = active
472
473
def _exempted(self, filepath):
474
start_matches = (
475
filepath.startswith(exception) for exception in self._exceptions
476
)
477
pattern_matches = (
478
re.match(pattern, filepath) for pattern in self._exception_patterns
479
)
480
candidates = itertools.chain(start_matches, pattern_matches)
481
return any(candidates)
482
483
def _remap_input(self, operation, path, *args, **kw):
484
"""Called for path inputs"""
485
if operation in self.write_ops and not self._ok(path):
486
self._violation(operation, os.path.realpath(path), *args, **kw)
487
return path
488
489
def _remap_pair(self, operation, src, dst, *args, **kw):
490
"""Called for path pairs like rename, link, and symlink operations"""
491
if not self._ok(src) or not self._ok(dst):
492
self._violation(operation, src, dst, *args, **kw)
493
return (src, dst)
494
495
def open(self, file, flags, mode=0o777, *args, **kw):
496
"""Called for low-level os.open()"""
497
if flags & WRITE_FLAGS and not self._ok(file):
498
self._violation("os.open", file, flags, mode, *args, **kw)
499
return _os.open(file, flags, mode, *args, **kw)
500
501
502
WRITE_FLAGS = functools.reduce(
503
operator.or_,
504
[
505
getattr(_os, a, 0)
506
for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()
507
],
508
)
509
510
511
class SandboxViolation(DistutilsError):
512
"""A setup script attempted to modify the filesystem outside the sandbox"""
513
514
tmpl = textwrap.dedent(
515
"""
516
SandboxViolation: {cmd}{args!r} {kwargs}
517
518
The package setup script has attempted to modify files on your system
519
that are not within the EasyInstall build area, and has been aborted.
520
521
This package cannot be safely installed by EasyInstall, and may not
522
support alternate installation locations even if you run its setup
523
script by hand. Please inform the package's author and the EasyInstall
524
maintainers to find out if a fix or workaround is available.
525
"""
526
).lstrip()
527
528
def __str__(self):
529
cmd, args, kwargs = self.args
530
return self.tmpl.format(**locals())
531
532