init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
233
.venv/lib/python3.8/site-packages/rope/base/oi/doa.py
Normal file
233
.venv/lib/python3.8/site-packages/rope/base/oi/doa.py
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
import marshal
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
|
||||
|
||||
def _compat_compare_digest(a, b):
|
||||
"""Implementation of hmac.compare_digest for python < 2.7.7.
|
||||
|
||||
This function uses an approach designed to prevent timing analysis by
|
||||
avoiding content-based short circuiting behaviour, making it appropriate
|
||||
for cryptography.
|
||||
"""
|
||||
if len(a) != len(b):
|
||||
return False
|
||||
# Computes the bitwise difference of all characters in the two strings
|
||||
# before returning whether or not they are equal.
|
||||
difference = 0
|
||||
for (a_char, b_char) in zip(a, b):
|
||||
difference |= ord(a_char) ^ ord(b_char)
|
||||
return difference == 0
|
||||
|
||||
|
||||
try:
|
||||
from hmac import compare_digest
|
||||
except ImportError:
|
||||
compare_digest = _compat_compare_digest
|
||||
|
||||
|
||||
class PythonFileRunner(object):
|
||||
"""A class for running python project files"""
|
||||
|
||||
def __init__(
|
||||
self, pycore, file_, args=None, stdin=None, stdout=None, analyze_data=None
|
||||
):
|
||||
self.pycore = pycore
|
||||
self.file = file_
|
||||
self.analyze_data = analyze_data
|
||||
self.observers = []
|
||||
self.args = args
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
|
||||
def run(self):
|
||||
"""Execute the process"""
|
||||
env = dict(os.environ)
|
||||
file_path = self.file.real_path
|
||||
path_folders = (
|
||||
self.pycore.project.get_source_folders()
|
||||
+ self.pycore.project.get_python_path_folders()
|
||||
)
|
||||
env["PYTHONPATH"] = os.pathsep.join(folder.real_path for folder in path_folders)
|
||||
runmod_path = self.pycore.project.find_module("rope.base.oi.runmod").real_path
|
||||
self.receiver = None
|
||||
self._init_data_receiving()
|
||||
send_info = "-"
|
||||
if self.receiver:
|
||||
send_info = self.receiver.get_send_info()
|
||||
args = [
|
||||
sys.executable,
|
||||
runmod_path,
|
||||
send_info,
|
||||
self.pycore.project.address,
|
||||
self.file.real_path,
|
||||
]
|
||||
if self.analyze_data is None:
|
||||
del args[1:4]
|
||||
if self.args is not None:
|
||||
args.extend(self.args)
|
||||
self.process = subprocess.Popen(
|
||||
executable=sys.executable,
|
||||
args=args,
|
||||
env=env,
|
||||
cwd=os.path.split(file_path)[0],
|
||||
stdin=self.stdin,
|
||||
stdout=self.stdout,
|
||||
stderr=self.stdout,
|
||||
close_fds=os.name != "nt",
|
||||
)
|
||||
|
||||
def _init_data_receiving(self):
|
||||
if self.analyze_data is None:
|
||||
return
|
||||
# Disabling FIFO data transfer due to blocking when running
|
||||
# unittests in the GUI.
|
||||
# XXX: Handle FIFO data transfer for `rope.ui.testview`
|
||||
if True or os.name == "nt":
|
||||
self.receiver = _SocketReceiver()
|
||||
else:
|
||||
self.receiver = _FIFOReceiver()
|
||||
self.receiving_thread = threading.Thread(target=self._receive_information)
|
||||
self.receiving_thread.setDaemon(True)
|
||||
self.receiving_thread.start()
|
||||
|
||||
def _receive_information(self):
|
||||
# temp = open('/dev/shm/info', 'wb')
|
||||
for data in self.receiver.receive_data():
|
||||
self.analyze_data(data)
|
||||
# temp.write(str(data) + '\n')
|
||||
# temp.close()
|
||||
for observer in self.observers:
|
||||
observer()
|
||||
|
||||
def wait_process(self):
|
||||
"""Wait for the process to finish"""
|
||||
self.process.wait()
|
||||
if self.analyze_data:
|
||||
self.receiving_thread.join()
|
||||
|
||||
def kill_process(self):
|
||||
"""Stop the process"""
|
||||
if self.process.poll() is not None:
|
||||
return
|
||||
try:
|
||||
if hasattr(self.process, "terminate"):
|
||||
self.process.terminate()
|
||||
elif os.name != "nt":
|
||||
os.kill(self.process.pid, 9)
|
||||
else:
|
||||
import ctypes
|
||||
|
||||
handle = int(self.process._handle)
|
||||
ctypes.windll.kernel32.TerminateProcess(handle, -1)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def add_finishing_observer(self, observer):
|
||||
"""Notify this observer when execution finishes"""
|
||||
self.observers.append(observer)
|
||||
|
||||
|
||||
class _MessageReceiver(object):
|
||||
def receive_data(self):
|
||||
pass
|
||||
|
||||
def get_send_info(self):
|
||||
pass
|
||||
|
||||
|
||||
class _SocketReceiver(_MessageReceiver):
|
||||
def __init__(self):
|
||||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.data_port = 3037
|
||||
self.key = os.urandom(32)
|
||||
|
||||
while self.data_port < 4000:
|
||||
try:
|
||||
self.server_socket.bind(("localhost", self.data_port))
|
||||
break
|
||||
except socket.error:
|
||||
self.data_port += 1
|
||||
self.server_socket.listen(1)
|
||||
|
||||
def get_send_info(self):
|
||||
return "%d:%s" % (self.data_port, base64.b64encode(self.key).decode("utf-8"))
|
||||
|
||||
def receive_data(self):
|
||||
conn, addr = self.server_socket.accept()
|
||||
self.server_socket.close()
|
||||
my_file = conn.makefile("rb")
|
||||
while True:
|
||||
# Received messages must meet the following criteria:
|
||||
# 1. Must be contained on a single line.
|
||||
# 2. Must be prefixed with a base64 encoded sha256 message digest
|
||||
# of the base64 encoded pickle data.
|
||||
# 3. Message digest must be computed using the correct key.
|
||||
#
|
||||
# Any messages received that do not meet these criteria will never
|
||||
# be unpickled and will be dropped silently.
|
||||
try:
|
||||
buf = my_file.readline()
|
||||
if len(buf) == 0:
|
||||
break
|
||||
|
||||
try:
|
||||
digest_end = buf.index(b":")
|
||||
buf_digest = base64.b64decode(buf[:digest_end])
|
||||
buf_data = buf[digest_end + 1 : -1]
|
||||
decoded_buf_data = base64.b64decode(buf_data)
|
||||
except:
|
||||
# Corrupted data; the payload cannot be trusted and just has
|
||||
# to be dropped. See CVE-2014-3539.
|
||||
continue
|
||||
|
||||
digest = hmac.new(self.key, buf_data, hashlib.sha256).digest()
|
||||
if not compare_digest(buf_digest, digest):
|
||||
# Signature mismatch; the payload cannot be trusted and just
|
||||
# has to be dropped. See CVE-2014-3539.
|
||||
continue
|
||||
|
||||
yield pickle.loads(decoded_buf_data)
|
||||
except EOFError:
|
||||
break
|
||||
my_file.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
class _FIFOReceiver(_MessageReceiver):
|
||||
def __init__(self):
|
||||
# XXX: this is insecure and might cause race conditions
|
||||
self.file_name = self._get_file_name()
|
||||
os.mkfifo(self.file_name)
|
||||
|
||||
def _get_file_name(self):
|
||||
prefix = tempfile.gettempdir() + "/__rope_"
|
||||
i = 0
|
||||
while os.path.exists(prefix + str(i).rjust(4, "0")):
|
||||
i += 1
|
||||
return prefix + str(i).rjust(4, "0")
|
||||
|
||||
def get_send_info(self):
|
||||
return self.file_name
|
||||
|
||||
def receive_data(self):
|
||||
my_file = open(self.file_name, "rb")
|
||||
while True:
|
||||
try:
|
||||
yield marshal.load(my_file)
|
||||
except EOFError:
|
||||
break
|
||||
my_file.close()
|
||||
os.remove(self.file_name)
|
||||
Loading…
Add table
Add a link
Reference in a new issue