aboutsummaryrefslogtreecommitdiffstats
path: root/snekbox.py
diff options
context:
space:
mode:
authorGravatar MarkKoz <[email protected]>2019-03-25 12:36:33 -0700
committerGravatar MarkKoz <[email protected]>2019-03-28 13:48:45 -0700
commit0e09d10281798dd365364a12af4487fc150844c1 (patch)
tree028996ba83a000272f05b00f1d974b0942078749 /snekbox.py
parentReplace 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.py133
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
-
-
-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)