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
COPY Pipfile Pipfile.lock /tmp/
RUN cd /tmp && pipenv install --system --deploy
COPY kapow /usr/bin
COPY bin/* /usr/bin/
ENTRYPOINT ["/usr/bin/kapow"]
+73 -9
View File
@@ -26,6 +26,9 @@ import shlex
import sys
from aiohttp import web, StreamReader
import click
import requests
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.
"""
if len(sys.argv) == 1:
if not scripts:
# No script given
cmd = "/bin/bash"
elif len(sys.argv) == 2:
cmd = f"/bin/bash --init-file {sys.argv[1]}"
else:
print(f"Usage: {sys.argv[0]} <init-script>")
os._exit(1)
filenames = " ".join(shlex.quote(f) for f in scripts)
cmd = f"/bin/bash --init-file <(cat {filenames})"
shell_task = await asyncio.create_subprocess_shell(
cmd,
executable="/bin/bash",
env={**os.environ,
"KAPOW_URL": "http://localhost:8080"
})
@@ -308,11 +310,10 @@ async def run_init_script(app):
async def start_background_tasks(app):
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():
"""Start aiohttp app."""
def start_kapow_server(scripts):
app = web.Application(client_max_size=1024**3)
app.add_routes([
# Control API
@@ -325,9 +326,72 @@ def kapow():
web.get('/handlers/{id}/{field:.*}', get_field),
web.put('/handlers/{id}/{field:.*}', set_field),
])
app["scripts"] = scripts
app.on_startup.append(start_background_tasks)
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__':
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.
#
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/
RUN cd /tmp && pipenv install --system --deploy
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.
#
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.
#
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
dmesg -w | response /stream
EOF
kroute add /tail/journal - <<-'EOF'
kapow route add /tail/journal - <<-'EOF'
response /headers/Content-Type text/plain
journalctl -f | response /stream
EOF
+3 -3
View File
@@ -16,11 +16,11 @@
# 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) \
--to=$(request /matches/to) \
--output=>(response /body) \
=(request /body)
EOF
kroute 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/input' -c 'pandoc --list-input-formats | 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.
#
kroute add -X POST --entrypoint ./topdf '/editor/pdf'
kroute add / -c 'response /headers/Content-Type text/html && response /body < pdfeditor.html'
kapow route add -X POST --entrypoint ./topdf '/editor/pdf'
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.
#
kroute add / - <<-'EOF'
kapow route add / - <<-'EOF'
response /headers/Content-Type text/html
response /body <<-HTML
<html>
@@ -27,7 +27,7 @@ kroute add / - <<-'EOF'
HTML
EOF
kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF'
kapow route add /save/magnet -e '/bin/bash -c' - <<-'EOF'
link=$(request /params/link)
[ -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
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:
### `kapow`
### `kapow server`
This is the master command, that shows the help if invoked without args, and
runs the sub-commands when provided to it.