Merge pull request #1 from BBVA/server-as-subcommand

"kapow route" and "kapow server" in PoC
This commit is contained in:
pancho horrillo
2019-06-05 09:51:14 +00:00
committed by GitHub
11 changed files with 94 additions and 100 deletions
-1
View File
@@ -3,6 +3,5 @@ RUN apk update && apk add bash curl coreutils file
RUN pip install pipenv RUN pip install pipenv
COPY Pipfile Pipfile.lock /tmp/ COPY Pipfile Pipfile.lock /tmp/
RUN cd /tmp && pipenv install --system --deploy RUN cd /tmp && pipenv install --system --deploy
COPY kapow /usr/bin
COPY bin/* /usr/bin/ COPY bin/* /usr/bin/
ENTRYPOINT ["/usr/bin/kapow"] ENTRYPOINT ["/usr/bin/kapow"]
+73 -9
View File
@@ -26,6 +26,9 @@ import shlex
import sys import sys
from aiohttp import web, StreamReader from aiohttp import web, StreamReader
import click
import requests
log = logging.getLogger('kapow') log = logging.getLogger('kapow')
@@ -281,22 +284,21 @@ async def delete_route(request):
######################################################################## ########################################################################
async def run_init_script(app): async def run_init_script(app, scripts):
""" """
Run the init script if given, then wait for the shell to finish. Run the init script if given, then wait for the shell to finish.
""" """
if len(sys.argv) == 1: if not scripts:
# No script given # No script given
cmd = "/bin/bash" cmd = "/bin/bash"
elif len(sys.argv) == 2:
cmd = f"/bin/bash --init-file {sys.argv[1]}"
else: else:
print(f"Usage: {sys.argv[0]} <init-script>") filenames = " ".join(shlex.quote(f) for f in scripts)
os._exit(1) cmd = f"/bin/bash --init-file <(cat {filenames})"
shell_task = await asyncio.create_subprocess_shell( shell_task = await asyncio.create_subprocess_shell(
cmd, cmd,
executable="/bin/bash",
env={**os.environ, env={**os.environ,
"KAPOW_URL": "http://localhost:8080" "KAPOW_URL": "http://localhost:8080"
}) })
@@ -308,11 +310,10 @@ async def run_init_script(app):
async def start_background_tasks(app): async def start_background_tasks(app):
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
app["debug_tasks"] = loop.create_task(run_init_script(app)) app["debug_tasks"] = loop.create_task(run_init_script(app, app["scripts"]))
def kapow(): def start_kapow_server(scripts):
"""Start aiohttp app."""
app = web.Application(client_max_size=1024**3) app = web.Application(client_max_size=1024**3)
app.add_routes([ app.add_routes([
# Control API # Control API
@@ -325,9 +326,72 @@ def kapow():
web.get('/handlers/{id}/{field:.*}', get_field), web.get('/handlers/{id}/{field:.*}', get_field),
web.put('/handlers/{id}/{field:.*}', set_field), web.put('/handlers/{id}/{field:.*}', set_field),
]) ])
app["scripts"] = scripts
app.on_startup.append(start_background_tasks) app.on_startup.append(start_background_tasks)
web.run_app(app) web.run_app(app)
########################################################################
# Command Lineagement #
########################################################################
@click.group()
@click.pass_context
def kapow(ctx):
"""Start aiohttp app."""
pass
@kapow.command()
@click.argument("scripts", nargs=-1)
def server(scripts):
start_kapow_server(scripts)
@kapow.group()
def route():
pass
@route.command()
@click.option("-c", "--command", nargs=1)
@click.option("-e", "--entrypoint", default="/bin/sh -c")
@click.option("-X", "--method", default="GET")
@click.option("--url", envvar='KAPOW_URL')
@click.argument("url_pattern", nargs=1)
@click.argument("command_file", required=False)
def add(url_pattern, entrypoint, command, method, url, command_file):
if command:
# Command is given inline
source = command
elif command_file is None:
# No command
source = ""
elif command_file == '-':
# Read commands from stdin
source = sys.stdin.read()
else:
# Read commands from a file
with open(command_file, 'r', encoding='utf-8') as handler:
source = handler.read()
response = requests.post(f"{url}/routes",
json={"method": method,
"url_pattern": url_pattern,
"entrypoint": entrypoint,
"command": source})
response.raise_for_status()
print(response.json())
@route.command()
@click.option("--url", envvar='KAPOW_URL')
@click.argument("route-id")
def remove(route_id, url):
response = requests.delete(f"{url}/routes/{route_id}")
response.raise_for_status()
print(response.json())
if __name__ == '__main__': if __name__ == '__main__':
kapow() kapow()
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2019 Banco Bilbao Vizcaya Argentaria, S.A.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import click
import requests
@click.group()
def kroute():
pass
@kroute.command()
@click.option("-c", "--command", nargs=1)
@click.option("-e", "--entrypoint", default="/bin/sh -c")
@click.option("-X", "--method", default="GET")
@click.option("--url", envvar='KAPOW_URL')
@click.argument("url_pattern", nargs=1)
@click.argument("command_file", required=False)
def add(url_pattern, entrypoint, command, method, url, command_file):
if command:
# Command is given inline
source = command
elif command_file is None:
# No command
source = ""
elif command_file == '-':
# Read commands from stdin
source = sys.stdin.read()
else:
# Read commands from a file
with open(command_file, 'r', encoding='utf-8') as handler:
source = handler.read()
response = requests.post(f"{url}/routes",
json={"method": method,
"url_pattern": url_pattern,
"entrypoint": entrypoint,
"command": source})
response.raise_for_status()
print(response.json())
@kroute.command()
@click.option("--url", envvar='KAPOW_URL')
@click.argument("route-id")
def remove(route_id, url):
response = requests.delete(f"{url}/routes/{route_id}")
response.raise_for_status()
print(response.json())
if __name__ == '__main__':
kroute()
+1 -1
View File
@@ -16,4 +16,4 @@
# limitations under the License. # limitations under the License.
# #
kroute add -X POST '/eval' -c '$($(request /body) | response /stream)' kapow route add -X POST '/eval' -c '$($(request /body) | response /stream)'
+1 -1
View File
@@ -3,4 +3,4 @@ RUN apk update && apk add nmap
COPY nmap.pow /tmp/ COPY nmap.pow /tmp/
RUN cd /tmp && pipenv install --system --deploy RUN cd /tmp && pipenv install --system --deploy
ENTRYPOINT ["/usr/bin/kapow"] ENTRYPOINT ["/usr/bin/kapow"]
CMD ["/tmp/nmap.pow"] CMD ["server", "/tmp/nmap.pow"]
+1 -1
View File
@@ -16,4 +16,4 @@
# limitations under the License. # limitations under the License.
# #
kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /matches/ip) | response /body' kapow route add -X GET '/list/{ip}' -c 'nmap -sL $(request /matches/ip) | response /body'
+9 -9
View File
@@ -16,26 +16,26 @@
# limitations under the License. # limitations under the License.
# #
kroute add /list/files -c 'ls -la $(request /params/path) | response /body' kapow route add /list/files -c 'ls -la $(request /params/path) | response /body'
kroute add /list/processes -c 'ps -aux | response /body' kapow route add /list/processes -c 'ps -aux | response /body'
kroute add /show/cpuinfo -c 'response /body < /proc/cpuinfo' kapow route add /show/cpuinfo -c 'response /body < /proc/cpuinfo'
kroute add /show/memory -c 'free -m | response /body' kapow route add /show/memory -c 'free -m | response /body'
kroute add /show/disk -c 'df -h | response /body' kapow route add /show/disk -c 'df -h | response /body'
kroute add /show/connections -c 'ss -pluton | response /body' kapow route add /show/connections -c 'ss -pluton | response /body'
kroute add /show/mounts -c 'mount | response /body' kapow route add /show/mounts -c 'mount | response /body'
kroute add /tail/dmesg - <<-'EOF' kapow route add /tail/dmesg - <<-'EOF'
response /headers/Content-Type text/plain response /headers/Content-Type text/plain
dmesg -w | response /stream dmesg -w | response /stream
EOF EOF
kroute add /tail/journal - <<-'EOF' kapow route add /tail/journal - <<-'EOF'
response /headers/Content-Type text/plain response /headers/Content-Type text/plain
journalctl -f | response /stream journalctl -f | response /stream
EOF EOF
+3 -3
View File
@@ -16,11 +16,11 @@
# limitations under the License. # limitations under the License.
# #
kroute add -X POST --entrypoint '/bin/zsh -c' '/convert/{from}/{to}' - <<-'EOF' kapow route add -X POST --entrypoint '/bin/zsh -c' '/convert/{from}/{to}' - <<-'EOF'
pandoc --from=$(request /matches/from) \ pandoc --from=$(request /matches/from) \
--to=$(request /matches/to) \ --to=$(request /matches/to) \
--output=>(response /body) \ --output=>(response /body) \
=(request /body) =(request /body)
EOF EOF
kroute add -X GET '/formats/input' -c 'pandoc --list-input-formats | response /body' kapow route add -X GET '/formats/input' -c 'pandoc --list-input-formats | response /body'
kroute add -X GET '/formats/output' -c 'pandoc --list-output-formats | grep -v pdf | response /body' kapow route add -X GET '/formats/output' -c 'pandoc --list-output-formats | grep -v pdf | response /body'
+2 -2
View File
@@ -16,5 +16,5 @@
# limitations under the License. # limitations under the License.
# #
kroute add -X POST --entrypoint ./topdf '/editor/pdf' kapow route add -X POST --entrypoint ./topdf '/editor/pdf'
kroute add / -c 'response /headers/Content-Type text/html && response /body < pdfeditor.html' kapow route add / -c 'response /headers/Content-Type text/html && response /body < pdfeditor.html'
+3 -3
View File
@@ -16,7 +16,7 @@
# limitations under the License. # limitations under the License.
# #
kroute add / - <<-'EOF' kapow route add / - <<-'EOF'
response /headers/Content-Type text/html response /headers/Content-Type text/html
response /body <<-HTML response /body <<-HTML
<html> <html>
@@ -27,7 +27,7 @@ kroute add / - <<-'EOF'
HTML HTML
EOF EOF
kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF' kapow route add /save/magnet -e '/bin/bash -c' - <<-'EOF'
link=$(request /params/link) link=$(request /params/link)
[ -z $link ] && response /status 400 && exit 0 [ -z $link ] && response /status 400 && exit 0
@@ -40,4 +40,4 @@ kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF'
response /headers/Location /torrent/list response /headers/Location /torrent/list
EOF EOF
kroute add /torrent/list -c 'response /body "Not Implemented Yet"' kapow route add /torrent/list -c 'response /body "Not Implemented Yet"'
+1 -1
View File
@@ -537,7 +537,7 @@ You can run it by ...
Any compliant implementation of Kapow! must provide these commands: Any compliant implementation of Kapow! must provide these commands:
### `kapow` ### `kapow server`
This is the master command, that shows the help if invoked without args, and This is the master command, that shows the help if invoked without args, and
runs the sub-commands when provided to it. runs the sub-commands when provided to it.