From 2657852ee3e97ee2dc233c932bd7c88bceec94b1 Mon Sep 17 00:00:00 2001
From: Scragly <29337040+scragly@users.noreply.github.com>
Date: Sun, 20 Jan 2019 20:42:34 +1000
Subject: Remove RMQ, Add API POST request method.
---
snekbox.py | 65 +++++++++++++++++++++++++++++---------------------------------
1 file changed, 30 insertions(+), 35 deletions(-)
(limited to 'snekbox.py')
diff --git a/snekbox.py b/snekbox.py
index ddde563..4e3e4fa 100644
--- a/snekbox.py
+++ b/snekbox.py
@@ -1,17 +1,14 @@
-import json
-import multiprocessing
import subprocess
import os
import sys
-from rmq import Rmq
+from flask import Flask, render_template, request, jsonify
class Snekbox(object):
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()
@@ -83,34 +80,32 @@ class Snekbox(object):
return output
- def execute(self, body):
- msg = body.decode('utf-8')
- result = ''
- snek_msg = json.loads(msg)
- snekid = snek_msg['snekid']
- snekcode = snek_msg['message'].strip()
-
- result = self.python3(snekcode)
-
- rmq.publish(result,
- queue=snekid,
- routingkey=snekid,
- exchange=snekid)
- exit(0)
-
- def message_handler(self, ch, method, properties, body, thread_ws=None):
- p = multiprocessing.Process(target=self.execute, args=(body,))
- p.daemon = True
- p.start()
-
- ch.basic_ack(delivery_tag=method.delivery_tag)
-
-
-if __name__ == '__main__':
- try:
- rmq = Rmq()
- snkbx = Snekbox()
- rmq.consume(callback=snkbx.message_handler)
- except KeyboardInterrupt:
- print('Exited')
- exit(0)
+
+snekbox = Snekbox()
+
+# Load app
+app = Flask(__name__)
+app.use_reloader = False
+
+# Logging
+log = app.logger
+
+
+@app.route('/')
+def index():
+ return render_template('index.html')
+
+
+@app.route('/result', methods=["POST", "GET"])
+def result():
+ if request.method == "POST":
+ code = request.form["Code"]
+ output = snekbox.python3(code)
+ return render_template('result.html', code=code, result=output)
+
+
+@app.route('/input', methods=["POST"])
+def code_input():
+ body = request.get_json()
+ output = snekbox.python3(body["code"])
+ return jsonify(input=body["code"], output=output)
--
cgit v1.2.3
From 3f679bf41341a2b2546ae667998bd5ea5d80e3fe Mon Sep 17 00:00:00 2001
From: MarkKoz
Date: Mon, 25 Mar 2019 11:52:41 -0700
Subject: Add docstrings to routes
---
snekbox.py | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'snekbox.py')
diff --git a/snekbox.py b/snekbox.py
index 5946e12..bb04987 100644
--- a/snekbox.py
+++ b/snekbox.py
@@ -109,11 +109,15 @@ log = app.logger
@app.route('/')
def index():
+ """Return a page with a form for inputting code to be executed."""
+
return render_template('index.html')
@app.route('/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)
@@ -122,6 +126,8 @@ def result():
@app.route('/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)
--
cgit v1.2.3
From 6b5b430c7fd0ed0398ca8ddbb76ae71b8e3d005f Mon Sep 17 00:00:00 2001
From: MarkKoz
Date: Mon, 25 Mar 2019 12:03:06 -0700
Subject: Fix import order
---
snekbox.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'snekbox.py')
diff --git a/snekbox.py b/snekbox.py
index bb04987..65fc4b3 100644
--- a/snekbox.py
+++ b/snekbox.py
@@ -2,7 +2,7 @@ import os
import subprocess
import sys
-from flask import Flask, render_template, request, jsonify
+from flask import Flask, jsonify, render_template, request
class Snekbox:
--
cgit v1.2.3
From 0e09d10281798dd365364a12af4487fc150844c1 Mon Sep 17 00:00:00 2001
From: MarkKoz
Date: Mon, 25 Mar 2019 12:36:33 -0700
Subject: 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
---
.flake8 | 2 +-
Pipfile | 2 +-
logs.py | 10 ---
snekbox.py | 133 -------------------------------------
snekbox/__init__.py | 10 +++
snekbox/nsjail.py | 95 ++++++++++++++++++++++++++
snekbox/site/snekapp.py | 38 +++++++++++
snekbox/site/templates/index.html | 14 ++++
snekbox/site/templates/result.html | 9 +++
templates/index.html | 14 ----
templates/result.html | 9 ---
tests/test_snekbox.py | 16 ++---
12 files changed, 176 insertions(+), 176 deletions(-)
delete mode 100644 logs.py
delete mode 100644 snekbox.py
create mode 100644 snekbox/__init__.py
create mode 100644 snekbox/nsjail.py
create mode 100644 snekbox/site/snekapp.py
create mode 100644 snekbox/site/templates/index.html
create mode 100644 snekbox/site/templates/result.html
delete mode 100644 templates/index.html
delete mode 100644 templates/result.html
(limited to 'snekbox.py')
diff --git a/.flake8 b/.flake8
index cc5f423..c897cb6 100644
--- a/.flake8
+++ b/.flake8
@@ -1,6 +1,6 @@
[flake8]
max-line-length=100
-application_import_names=snekbox,config,logs
+application_import_names=snekbox
ignore=
P102,B311,W503,E226,S311,
# Missing Docstrings
diff --git a/Pipfile b/Pipfile
index 221263d..3f67b54 100644
--- a/Pipfile
+++ b/Pipfile
@@ -29,7 +29,7 @@ lint = "flake8"
precommit = "pre-commit install"
test = "pytest tests --cov . --cov-report term-missing -v"
report = "pytest tests --cov . --cov-report=html"
-snekbox = "gunicorn -w 2 -b 0.0.0.0:8060 snekbox:app"
+snekbox = "gunicorn -w 2 -b 0.0.0.0:8060 snekbox.site.snekapp:app"
buildbox = "docker build -t pythondiscord/snekbox:latest -f docker/Dockerfile ."
pushbox = "docker push pythondiscord/snekbox:latest"
buildboxbase = "docker build -t pythondiscord/snekbox-base:latest -f docker/base.Dockerfile ."
diff --git a/logs.py b/logs.py
deleted file mode 100644
index fc6070e..0000000
--- a/logs.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import logging
-import sys
-
-logformat = logging.Formatter(fmt='[%(asctime)s] [%(process)s] [%(levelname)s] %(message)s',
- datefmt='%Y-%m-%d %H:%M:%S %z')
-log = logging.getLogger(__name__)
-log.setLevel(logging.DEBUG)
-console = logging.StreamHandler(sys.stdout)
-console.setFormatter(logformat)
-log.addHandler(console)
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
-
-
-@app.route('/')
-def index():
- """Return a page with a form for inputting code to be executed."""
-
- return render_template('index.html')
-
-
-@app.route('/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)
-
-
-@app.route('/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)
diff --git a/snekbox/__init__.py b/snekbox/__init__.py
new file mode 100644
index 0000000..fc6070e
--- /dev/null
+++ b/snekbox/__init__.py
@@ -0,0 +1,10 @@
+import logging
+import sys
+
+logformat = logging.Formatter(fmt='[%(asctime)s] [%(process)s] [%(levelname)s] %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S %z')
+log = logging.getLogger(__name__)
+log.setLevel(logging.DEBUG)
+console = logging.StreamHandler(sys.stdout)
+console.setFormatter(logformat)
+log.addHandler(console)
diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py
new file mode 100644
index 0000000..458a94e
--- /dev/null
+++ b/snekbox/nsjail.py
@@ -0,0 +1,95 @@
+import os
+import subprocess
+import sys
+
+
+class NsJail:
+ """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
diff --git a/snekbox/site/snekapp.py b/snekbox/site/snekapp.py
new file mode 100644
index 0000000..492d703
--- /dev/null
+++ b/snekbox/site/snekapp.py
@@ -0,0 +1,38 @@
+from flask import Flask, jsonify, render_template, request
+
+from snekbox.nsjail import NsJail
+
+nsjail = NsJail()
+
+# Load app
+app = Flask(__name__)
+app.use_reloader = False
+
+# Logging
+log = app.logger
+
+
+@app.route('/')
+def index():
+ """Return a page with a form for inputting code to be executed."""
+
+ return render_template('index.html')
+
+
+@app.route('/result', methods=["POST", "GET"])
+def result():
+ """Execute code and return a page displaying the results."""
+
+ if request.method == "POST":
+ code = request.form["Code"]
+ output = nsjail.python3(code)
+ return render_template('result.html', code=code, result=output)
+
+
+@app.route('/input', methods=["POST"])
+def code_input():
+ """Execute code and return the results."""
+
+ body = request.get_json()
+ output = nsjail.python3(body["code"])
+ return jsonify(input=body["code"], output=output)
diff --git a/snekbox/site/templates/index.html b/snekbox/site/templates/index.html
new file mode 100644
index 0000000..41980d1
--- /dev/null
+++ b/snekbox/site/templates/index.html
@@ -0,0 +1,14 @@
+
+
+
+ snekboxweb
+
+
+
+
diff --git a/snekbox/site/templates/result.html b/snekbox/site/templates/result.html
new file mode 100644
index 0000000..e339605
--- /dev/null
+++ b/snekbox/site/templates/result.html
@@ -0,0 +1,9 @@
+
+
+
+ snekboxweb
+
+ Code Evaluated:
{{ code }}
+ Results:
{{ result }}
+
+
diff --git a/templates/index.html b/templates/index.html
deleted file mode 100644
index 41980d1..0000000
--- a/templates/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- snekboxweb
-
-
-
-
diff --git a/templates/result.html b/templates/result.html
deleted file mode 100644
index e339605..0000000
--- a/templates/result.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- snekboxweb
-
- Code Evaluated:
{{ code }}
- Results:
{{ result }}
-
-
diff --git a/tests/test_snekbox.py b/tests/test_snekbox.py
index cc79a2a..c08178f 100644
--- a/tests/test_snekbox.py
+++ b/tests/test_snekbox.py
@@ -1,20 +1,20 @@
import unittest
-from snekbox import Snekbox
+from snekbox.nsjail import NsJail
-snek = Snekbox()
+nsjail = NsJail()
class SnekTests(unittest.TestCase):
def test_nsjail(self):
- result = snek.python3('print("test")')
+ result = nsjail.python3('print("test")')
self.assertEquals(result.strip(), 'test')
# def test_memory_error(self):
# code = ('x = "*"\n'
# 'while True:\n'
# ' x = x * 99\n')
- # result = snek.python3(code)
+ # result = nsjail.python3(code)
# self.assertEquals(result.strip(), 'timed out or memory limit exceeded')
def test_timeout(self):
@@ -27,13 +27,13 @@ class SnekTests(unittest.TestCase):
' continue\n'
)
- result = snek.python3(code)
+ result = nsjail.python3(code)
self.assertEquals(result.strip(), 'timed out or memory limit exceeded')
def test_kill(self):
code = ('import subprocess\n'
'print(subprocess.check_output("kill -9 6", shell=True).decode())')
- result = snek.python3(code)
+ result = nsjail.python3(code)
if 'ModuleNotFoundError' in result.strip():
self.assertIn('ModuleNotFoundError', result.strip())
else:
@@ -43,7 +43,7 @@ class SnekTests(unittest.TestCase):
code = ('import os\n'
'while 1:\n'
' os.fork()')
- result = snek.python3(code)
+ result = nsjail.python3(code)
self.assertIn('Resource temporarily unavailable', result.strip())
def test_juan_golf(self): # in honour of Juan
@@ -52,5 +52,5 @@ class SnekTests(unittest.TestCase):
"bytecode = CodeType(0,1,0,0,0,b'',(),(),(),'','',1,b'')\n"
"exec(bytecode)")
- result = snek.python3(code)
+ result = nsjail.python3(code)
self.assertEquals('unknown error, code: 111', result.strip())
--
cgit v1.2.3