1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import os
import sys
import subprocess
import time
from flask import Flask, Response, request, jsonify
app = Flask(__name__)
import logging
logging.basicConfig(format='%(asctime)s %(levelname)s - %(message)s', level=logging.INFO)
from yaml import load, dump
if "CONFIG_PATH" in os.environ:
filename = os.environ["CONFIG_PATH"]
else:
filename = "config.yaml"
try:
with open(filename) as f:
text = f.read()
config = load(text)
except:
print("Could not open file {}".format(filename))
sys.exit(1)
config_keys = config.keys()
@app.route("/<key>", methods=["POST"])
def key(key):
logging.info("User requested route \"{}\"".format(key))
if not key in config_keys:
logging.warning("Route \"{}\" does not exist!".format(key))
return Response("", status=404)
options = config[key]
protocol = request.url.split("://")[0]
logging.info("User uses protocol {}".format(protocol))
if protocol != "https":
logging.error("Using plain HTTP is strongly discouraged! Please upgrade to HTTPS.")
# return Response("HTTP requests not allowed! Use HTTPS!", status=400)
auth_header = request.headers.get('Authorization')
auth = options["auth"]
if auth != auth_header:
logging.warning("User request rejected due to incorrect Authorization header!")
return Response("", status=401)
if request.content_type != "application/json":
logging.warning("User request rejected due to incorrect content type (must be application/json)!")
return Response("", status=400)
content = request.json
cmd = options["command"]
for content_key in content:
cmd = cmd.replace("${" + str(content_key) + "}", content[content_key])
logging.info("User runs command:")
logging.info(cmd)
success = True
start = time.time()
try:
output = subprocess.check_output(cmd, shell=True)
except Exception as e:
success = False
output = str(e)
end = time.time()
duration = "{:.2f}".format(end - start)
output = output.decode("utf-8") if type(output) == bytes else output
output = output.encode("unicode_escape").decode("utf-8")
logging.info("Command output:")
logging.info(output)
logging.info("Command duration: {}".format(duration))
return jsonify({
"command": cmd,
"output": str(output),
"duration": duration,
"success": success
})
@app.route("/")
def hello():
return "Welcome to remote HTTPS runner API!"
|