diff options
author | 2019-03-25 12:36:33 -0700 | |
---|---|---|
committer | 2019-03-28 13:48:45 -0700 | |
commit | 0e09d10281798dd365364a12af4487fc150844c1 (patch) | |
tree | 028996ba83a000272f05b00f1d974b0942078749 /snekbox.py | |
parent | Replace RMQ with a POST endpoint (#7) (diff) |
Restructure project layout
* Move all code into a "snekbox" package
* Use logging code as __init__.py
* Rename Snekbox class to NsJail
* Create "site" sub-package
* Move templates into this sub-package
* Move Flask code into a new snekapp module
Diffstat (limited to 'snekbox.py')
-rw-r--r-- | snekbox.py | 133 |
1 files changed, 0 insertions, 133 deletions
diff --git a/snekbox.py b/snekbox.py deleted file mode 100644 index 65fc4b3..0000000 --- a/snekbox.py +++ /dev/null @@ -1,133 +0,0 @@ -import os -import subprocess -import sys - -from flask import Flask, jsonify, render_template, request - - -class Snekbox: - """Core snekbox functionality, providing safe execution of Python code.""" - - def __init__(self, - nsjail_binary='nsjail', - python_binary=os.path.dirname(sys.executable) + os.sep + 'python3.6'): - self.nsjail_binary = nsjail_binary - self.python_binary = python_binary - self._nsjail_workaround() - - env = { - 'PATH': ( - '/snekbox/.venv/bin:/usr/local/bin:/usr/local/' - 'sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' - ), - 'LANG': 'en_US.UTF-8', - 'PYTHON_VERSION': '3.6.5', - 'PYTHON_PIP_VERSION': '10.0.1', - 'PYTHONDONTWRITEBYTECODE': '1', - } - - def _nsjail_workaround(self): - dirs = ['/sys/fs/cgroup/pids/NSJAIL', '/sys/fs/cgroup/memory/NSJAIL'] - for d in dirs: - if not os.path.exists(d): - os.makedirs(d) - - def python3(self, cmd): - """ - Execute Python 3 code in a isolated environment. - - The value of ``cmd`` is passed using '-c' to a Python - interpreter that is started in a ``nsjail``, isolating it - from the rest of the system. - - Returns the output of executing the command (stdout) if - successful, or a error message if the execution failed. - """ - - args = [self.nsjail_binary, '-Mo', - '--rlimit_as', '700', - '--chroot', '/', - '-E', 'LANG=en_US.UTF-8', - '-R/usr', '-R/lib', '-R/lib64', - '--user', 'nobody', - '--group', 'nogroup', - '--time_limit', '2', - '--disable_proc', - '--iface_no_lo', - '--cgroup_pids_max=1', - '--cgroup_mem_max=52428800', - '--quiet', '--', - self.python_binary, '-ISq', '-c', cmd] - try: - proc = subprocess.Popen(args, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=self.env, - universal_newlines=True) - except ValueError: - return 'ValueError: embedded null byte' - - stdout, stderr = proc.communicate() - if proc.returncode == 0: - output = stdout - - elif proc.returncode == 1: - try: - filtered = [] - for line in stderr.split('\n'): - if not line.startswith('['): - filtered.append(line) - output = '\n'.join(filtered) - except IndexError: - output = '' - - elif proc.returncode == 109: - return 'timed out or memory limit exceeded' - - elif proc.returncode == 255: - return 'permission denied (root required)' - - elif proc.returncode: - return f'unknown error, code: {proc.returncode}' - - else: - return 'unknown error, no error code' - - return output - - -snekbox = Snekbox() - -# Load app -app = Flask(__name__) -app.use_reloader = False - -# Logging -log = app.logger - - [email protected]('/') -def index(): - """Return a page with a form for inputting code to be executed.""" - - return render_template('index.html') - - [email protected]('/result', methods=["POST", "GET"]) -def result(): - """Execute code and return a page displaying the results.""" - - if request.method == "POST": - code = request.form["Code"] - output = snekbox.python3(code) - return render_template('result.html', code=code, result=output) - - [email protected]('/input', methods=["POST"]) -def code_input(): - """Execute code and return the results.""" - - body = request.get_json() - output = snekbox.python3(body["code"]) - return jsonify(input=body["code"], output=output) |