/Flask-Shell2HTTP

A minimalist REST API wrapper for python's subprocess API. Map shell commands to flask's endpoints and query asynchronously.

Primary LanguagePythonBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Flask-Shell2HTTP

flask-shell2http on pypi

A minimalist Flask extension that serves as a REST API wrapper for python's subprocess API.

  • Convert any command-line tool into a REST API service.
  • Execute pre-defined shell commands asynchronously and securely from flask's endpoints.
  • Designed for development, prototyping or remote control.

Inspired by the work of awesome folks over at msoap/shell2http.

Use Cases

  • Set a script that runs on a succesful POST request to an endpoint of your choice. See Example code.
  • Map a base command to an endpoint and pass dynamic arguments to it. See Example code.
  • Can also process multiple uploaded files in one command. See Example code.
  • This is useful for internal docker-to-docker communications if you have lots of different binaries. See real-life example.
  • Currently, all commands are run asynchronously, so result is not available directly. An option would be provided for this in future release.

Note: This module is primarily meant for running long-running shell commands/scripts (like nmap, code-analysis' tools) in background and getting the result at a later time.

Quick Start

Dependencies

Install

$ pip install flask flask_shell2http

Example

from flask import Flask
from flask_executor import Executor
from flask_shell2http import Shell2HTTP

# Flask application instance
app = Flask(__name__)

executor = Executor(app)
shell2http = Shell2HTTP(app=app, executor=executor, base_url_prefix="/commands/")

shell2http.register_command(endpoint="saythis", command_name="echo")

Run the application server with, $ flask run -p 4000.

Make HTTP calls

$ curl -X POST -d '{"args": ["Hello", "World!"]}' http://localhost:4000/commands/saythis
or using python's requests module,
data = {"args": ["Hello", "World!"]}
resp = requests.post("http://localhost:4000/commands/saythis", json=data)
print("Result:", resp.json())

returns JSON,

{
   "key": "ddbe0a94847c65f9b8198424ffd07c50",
   "status": "running"
}

Then using this key you can query for the result,

$ curl http://localhost:4000/commands/saythis?key=ddbe0a94847c65f9b8198424ffd07c50

Returns result in JSON,

{
  "end_time": 1593019807.782958, 
  "error": "", 
  "md5": "ddbe0a94847c65f9b8198424ffd07c50", 
  "process_time": 0.00748753547668457, 
  "report": {
    "result": "Hello World!\n"
  }, 
  "start_time": 1593019807.7754705, 
  "status": "success"
}

Why?

This was initially made to integrate various command-line tools easily with IntelOwl.

Example usage

You can find various examples under examples.