From 021d36264bce20a1b8c3eb99176dc049483e5b7b Mon Sep 17 00:00:00 2001 From: Tagptroll1 Date: Thu, 14 Feb 2019 18:40:00 +0100 Subject: flake8 linelength change --- snekbox.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'snekbox.py') diff --git a/snekbox.py b/snekbox.py index ddde563..37d7993 100644 --- a/snekbox.py +++ b/snekbox.py @@ -17,7 +17,10 @@ class Snekbox(object): self.nsjail_workaround() env = { - 'PATH': '/snekbox/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + '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', -- cgit v1.2.3 From 42f9140c413aba70b62c085f1d1f6b5356a684a0 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 19 Mar 2019 18:48:33 -0600 Subject: Add docstrings --- config.py | 5 +---- rmq.py | 11 +++++------ snekbox.py | 28 +++++++++++++++++++++++++--- snekweb.py | 2 ++ 4 files changed, 33 insertions(+), 13 deletions(-) (limited to 'snekbox.py') diff --git a/config.py b/config.py index 846ad4a..10218eb 100644 --- a/config.py +++ b/config.py @@ -1,10 +1,10 @@ import os import docker from docker.errors import NotFound -# import traceback def autodiscover(): + """Search for the snekbox container and return it's IPv4 address.""" container_names = ["rmq", "pdrmq", "snekbox_pdrmq_1"] client = docker.from_env() @@ -15,13 +15,10 @@ def autodiscover(): host = list(container.attrs.get('NetworkSettings').get('Networks').values()) host = host[0]['IPAddress'] return host - except NotFound: continue - except Exception: pass - # print(traceback.format_exc()) return '127.0.0.1' diff --git a/rmq.py b/rmq.py index 493a38f..a0dade7 100644 --- a/rmq.py +++ b/rmq.py @@ -16,7 +16,8 @@ from config import EXCHANGE from logs import log -class Rmq(object): +class Rmq: + """Rabbit MQ (RMQ) implementation used for communication with the bot.""" def __init__(self, username=USERNAME, @@ -42,6 +43,7 @@ class Rmq(object): auto_delete=True) # Delete queue when all connection are closed def consume(self, queue=QUEUE, callback=None, thread_ws=None, run_once=False): + """Subscribe to read from a RMQ channel.""" while True: try: connection = pika.BlockingConnection(self.con_params) @@ -86,11 +88,8 @@ class Rmq(object): time.sleep(2) - def publish(self, - message, - queue=QUEUE, - routingkey=ROUTING_KEY, - exchange=EXCHANGE): + def publish(self, message, queue=QUEUE, routingkey=ROUTING_KEY, exchange=EXCHANGE): + """Open a connection to publish (write) to a RMQ channel.""" try: connection = pika.BlockingConnection(self.con_params) diff --git a/snekbox.py b/snekbox.py index 37d7993..5f7b42f 100644 --- a/snekbox.py +++ b/snekbox.py @@ -7,14 +7,16 @@ import sys from rmq import Rmq -class Snekbox(object): +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() + self._nsjail_workaround() env = { 'PATH': ( @@ -27,13 +29,23 @@ class Snekbox(object): 'PYTHONDONTWRITEBYTECODE': '1', } - def nsjail_workaround(self): + 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', '/', @@ -87,6 +99,15 @@ class Snekbox(object): return output def execute(self, body): + """ + Handles execution of a raw JSON-formatted RMQ message, contained in ``body``. + + The message metadata, including the Python code to be executed, is + extracted from the message body. The code is then executed in the + isolated environment, and the results of the execution published + to RMQ. Once published, the system exits, since the snekboxes + are created and disposed of per-execution. + """ msg = body.decode('utf-8') result = '' snek_msg = json.loads(msg) @@ -102,6 +123,7 @@ class Snekbox(object): exit(0) def message_handler(self, ch, method, properties, body, thread_ws=None): + """Spawns a daemon process that handles RMQ messages.""" p = multiprocessing.Process(target=self.execute, args=(body,)) p.daemon = True p.start() diff --git a/snekweb.py b/snekweb.py index 92e0436..2ed1034 100644 --- a/snekweb.py +++ b/snekweb.py @@ -24,11 +24,13 @@ log = app.logger @app.route('/') def index(): + """Root path returns standard index.html.""" return render_template('index.html') @sockets.route('/ws/') def websocket_route(ws, snekboxid): + """Opens a websocket that spawns and connects to a snekbox daemon.""" localdata = threading.local() localdata.thread_ws = ws -- cgit v1.2.3 From 78552b961535578b38c5c8fe79698179a6eac31d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 19 Mar 2019 18:59:53 -0600 Subject: Fix ordering of imports --- .flake8 | 2 +- config.py | 2 +- rmq.py | 11 +++++------ snekbox.py | 2 +- snekweb.py | 8 +++----- 5 files changed, 11 insertions(+), 14 deletions(-) (limited to 'snekbox.py') diff --git a/.flake8 b/.flake8 index ee465ff..b2b4bb1 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,6 @@ [flake8] max-line-length=100 -application_import_names=snekbox +application_import_names=snekbox,config,logs ignore=P102,B311,W503,E226,S311 exclude=__pycache__, venv, .venv, tests import-order-style=pycharm diff --git a/config.py b/config.py index 846ad4a..138c25c 100644 --- a/config.py +++ b/config.py @@ -1,7 +1,7 @@ import os + import docker from docker.errors import NotFound -# import traceback def autodiscover(): diff --git a/rmq.py b/rmq.py index 493a38f..72e0e9a 100644 --- a/rmq.py +++ b/rmq.py @@ -1,18 +1,17 @@ -import pika import time import traceback +import pika from pika.exceptions import ConnectionClosed -from config import USERNAME -from config import PASSWORD +from config import EXCHANGE +from config import EXCHANGE_TYPE from config import HOST +from config import PASSWORD from config import PORT -from config import EXCHANGE_TYPE from config import QUEUE from config import ROUTING_KEY -from config import EXCHANGE - +from config import USERNAME from logs import log diff --git a/snekbox.py b/snekbox.py index 37d7993..59147a8 100644 --- a/snekbox.py +++ b/snekbox.py @@ -1,7 +1,7 @@ import json import multiprocessing -import subprocess import os +import subprocess import sys from rmq import Rmq diff --git a/snekweb.py b/snekweb.py index 92e0436..57d79e2 100644 --- a/snekweb.py +++ b/snekweb.py @@ -1,13 +1,11 @@ -import traceback -import threading -import logging import json +import logging +import threading +import traceback from flask import Flask from flask import render_template from flask_sockets import Sockets - - from rmq import Rmq # Load app -- cgit v1.2.3 From 1f49e3edd7a1167eb81438c57dc1dd3789bb0b3b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sun, 24 Mar 2019 17:35:43 -0600 Subject: More formatting fixes --- config.py | 1 + rmq.py | 1 + snekbox.py | 6 ++++-- snekweb.py | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) (limited to 'snekbox.py') diff --git a/config.py b/config.py index 5ca23bb..5e4f648 100644 --- a/config.py +++ b/config.py @@ -6,6 +6,7 @@ from docker.errors import NotFound def autodiscover(): """Search for the snekbox container and return its IPv4 address.""" + container_names = ["rmq", "pdrmq", "snekbox_pdrmq_1"] client = docker.from_env() diff --git a/rmq.py b/rmq.py index b4cb90a..919ef19 100644 --- a/rmq.py +++ b/rmq.py @@ -25,6 +25,7 @@ class Rmq: def consume(self, queue=QUEUE, callback=None, thread_ws=None, run_once=False): """Subscribe to read from a RMQ channel.""" + while True: try: connection = pika.BlockingConnection(self.con_params) diff --git a/snekbox.py b/snekbox.py index a5cebde..f8d7c31 100644 --- a/snekbox.py +++ b/snekbox.py @@ -12,8 +12,7 @@ class Snekbox: def __init__(self, nsjail_binary='nsjail', - python_binary=os.path.dirname(sys.executable)+os.sep+'python3.6'): - + python_binary=os.path.dirname(sys.executable) + os.sep + 'python3.6'): self.nsjail_binary = nsjail_binary self.python_binary = python_binary self._nsjail_workaround() @@ -46,6 +45,7 @@ class Snekbox: 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', '/', @@ -108,6 +108,7 @@ class Snekbox: to RMQ. Once published, the system exits, since the snekboxes are created and disposed of per-execution. """ + msg = body.decode('utf-8') result = '' snek_msg = json.loads(msg) @@ -124,6 +125,7 @@ class Snekbox: def message_handler(self, ch, method, properties, body, thread_ws=None): """Spawns a daemon process that handles RMQ messages.""" + p = multiprocessing.Process(target=self.execute, args=(body,)) p.daemon = True p.start() diff --git a/snekweb.py b/snekweb.py index 3e20fda..ff1a72c 100644 --- a/snekweb.py +++ b/snekweb.py @@ -22,12 +22,14 @@ log = app.logger @app.route('/') def index(): """Root path returns standard index.html.""" + return render_template('index.html') @sockets.route('/ws/') def websocket_route(ws, snekboxid): """Opens a websocket that spawns and connects to a snekbox daemon.""" + localdata = threading.local() localdata.thread_ws = ws -- cgit v1.2.3