From dc253f748526a4bca9745eed586a32dbf2ee3564 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Mon, 27 May 2019 11:56:25 +0200 Subject: [PATCH 01/16] Sync poc to spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- poc/bin/request | 2 +- poc/bin/response | 6 ++--- poc/examples/nmap/nmap.pow | 2 +- poc/examples/operator.pow | 6 ++--- poc/examples/pandoc/pandoc.pow | 4 +-- poc/examples/pdfeditor/pdfeditor.pow | 2 +- poc/examples/pdfeditor/topdf | 2 +- poc/examples/torrent.pow | 6 ++--- poc/kapow | 37 +++++++++++++++------------- 9 files changed, 35 insertions(+), 32 deletions(-) diff --git a/poc/bin/request b/poc/bin/request index 3268445..0ebf854 100755 --- a/poc/bin/request +++ b/poc/bin/request @@ -16,4 +16,4 @@ # limitations under the License. # -curl -sf ${KAPOW_URL}/connections/${KAPOW_CONNECTION}/request$1 +curl -sf "${KAPOW_URL}/handlers/${KAPOW_HANDLER_ID}/request$1" diff --git a/poc/bin/response b/poc/bin/response index c0961e4..75dc091 100755 --- a/poc/bin/response +++ b/poc/bin/response @@ -24,17 +24,17 @@ import requests @click.command() @click.option("--url", envvar='KAPOW_URL') -@click.option("--connection", envvar='KAPOW_CONNECTION') +@click.option("--handler-id", envvar='KAPOW_HANDLER_ID') @click.argument("path", nargs=1) @click.argument("value", required=False) -def response(url, connection, path, value): +def response(url, handler_id, path, value): if value is None: data = sys.stdin.buffer else: data = value.encode('utf-8') try: - response = requests.put(f"{url}/connections/{connection}/response{path}", + response = requests.put(f"{url}/handlers/{handler_id}/response{path}", data=data) except requests.exceptions.ConnectionError: return False diff --git a/poc/examples/nmap/nmap.pow b/poc/examples/nmap/nmap.pow index 6df7789..b493921 100644 --- a/poc/examples/nmap/nmap.pow +++ b/poc/examples/nmap/nmap.pow @@ -16,4 +16,4 @@ # limitations under the License. # -kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /match/ip) | response /body' +kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /matches/ip) | response /body' diff --git a/poc/examples/operator.pow b/poc/examples/operator.pow index 6e86640..926d27e 100755 --- a/poc/examples/operator.pow +++ b/poc/examples/operator.pow @@ -16,7 +16,7 @@ # limitations under the License. # -kroute add /list/files -c 'ls -la $(request /param/path) | response /body' +kroute add /list/files -c 'ls -la $(request /params/path) | response /body' kroute add /list/processes -c 'ps -aux | response /body' @@ -31,11 +31,11 @@ kroute add /show/connections -c 'ss -pluton | response /body' kroute add /show/mounts -c 'mount | response /body' kroute add /tail/dmesg - <<-'EOF' - response /header/Content-Type text/plain + response /headers/Content-Type text/plain dmesg -w | response /stream EOF kroute add /tail/journal - <<-'EOF' - response /header/Content-Type text/plain + response /headers/Content-Type text/plain journalctl -f | response /stream EOF diff --git a/poc/examples/pandoc/pandoc.pow b/poc/examples/pandoc/pandoc.pow index 4bd2bbf..67d308d 100755 --- a/poc/examples/pandoc/pandoc.pow +++ b/poc/examples/pandoc/pandoc.pow @@ -17,8 +17,8 @@ # kroute add -X POST --entrypoint '/bin/zsh -c' '/convert/{from}/{to}' - <<-'EOF' - pandoc --from=$(request /match/from) \ - --to=$(request /match/to) \ + pandoc --from=$(request /matches/from) \ + --to=$(request /matches/to) \ --output=>(response /body) \ =(request /body) EOF diff --git a/poc/examples/pdfeditor/pdfeditor.pow b/poc/examples/pdfeditor/pdfeditor.pow index 7b26f7e..e1749db 100644 --- a/poc/examples/pdfeditor/pdfeditor.pow +++ b/poc/examples/pdfeditor/pdfeditor.pow @@ -17,4 +17,4 @@ # kroute add -X POST --entrypoint ./topdf '/editor/pdf' -kroute add / -c 'response /header/Content-Type text/html && response /body < pdfeditor.html' +kroute add / -c 'response /headers/Content-Type text/html && response /body < pdfeditor.html' diff --git a/poc/examples/pdfeditor/topdf b/poc/examples/pdfeditor/topdf index 722cd20..d05b2dc 100755 --- a/poc/examples/pdfeditor/topdf +++ b/poc/examples/pdfeditor/topdf @@ -19,7 +19,7 @@ tmpfile=$(mktemp --suffix=.pdf) pandoc --from=$(request /form/from) --to=pdf --output=${tmpfile} -t latex =(request /form/content) if [ $? -eq 0 ]; then - response /header/Content-Type application/pdf + response /headers/Content-Type application/pdf response /body < ${tmpfile} response /status 200 else diff --git a/poc/examples/torrent.pow b/poc/examples/torrent.pow index b6b4a39..2813641 100644 --- a/poc/examples/torrent.pow +++ b/poc/examples/torrent.pow @@ -17,7 +17,7 @@ # kroute add / - <<-'EOF' - response /header/Content-Type text/html + response /headers/Content-Type text/html response /body <<-HTML @@ -28,7 +28,7 @@ kroute add / - <<-'EOF' EOF kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF' - link=$(request /param/link) + link=$(request /params/link) [ -z $link ] && response /status 400 && exit 0 watch_folder=/tmp @@ -37,7 +37,7 @@ kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF' echo "d10:magnet-uri${#link}:${link}e" > "meta-${BASH_REMATCH[1]}.torrent" response /status 302 - response /header/Location /torrent/list + response /headers/Location /torrent/list EOF kroute add /torrent/list -c 'response /body "Not Implemented Yet"' diff --git a/poc/kapow b/poc/kapow index c2183c0..6832c9e 100755 --- a/poc/kapow +++ b/poc/kapow @@ -69,17 +69,17 @@ class Connection: return self.request.content elif res.path == 'request/path': return self.request.path.encode('utf-8') - elif res.path.startswith('request/match/'): + elif res.path.startswith('request/matches/'): return self.request.match_info[nth(2)].encode('utf-8') - elif res.path.startswith('request/param/'): + elif res.path.startswith('request/params/'): return self.request.rel_url.query[nth(2)].encode('utf-8') - elif res.path.startswith('request/header/'): + elif res.path.startswith('request/headers/'): return self.request.headers[nth(2)].encode('utf-8') - elif res.path.startswith('request/cookie/'): + elif res.path.startswith('request/cookies/'): return self.request.cookies[nth(2)].encode('utf-8') elif res.path.startswith('request/form/'): return (await self.request.post())[nth(2)].encode('utf-8') - elif res.path.startswith('request/file/'): + elif res.path.startswith('request/files/'): name = nth(2) content = nth(3) # filename / content field = (await self.request.post())[name] @@ -109,10 +109,10 @@ class Connection: self._status = int((await content.read()).decode('utf-8')) elif res.path == 'response/body': self._body.write(await content.read()) - elif res.path.startswith('response/header/'): + elif res.path.startswith('response/headers/'): clean = (await content.read()).rstrip(b'\n').decode('utf-8') self._headers[nth(2)] = clean - elif res.path.startswith('response/cookie/'): + elif res.path.startswith('response/cookies/'): clean = (await content.read()).rstrip(b'\n').decode('utf-8') self._cookies[nth(2)] = clean elif res.path == 'response/stream': @@ -227,8 +227,8 @@ def handle_route(entrypoint, command): shell_task = await asyncio.create_subprocess_shell( args, env={**os.environ, - "KAPOW_URL": "http://localhost:8080/kapow", - "KAPOW_CONNECTION": id + "KAPOW_URL": "http://localhost:8080", + "KAPOW_HANDLER_ID": id }, stdin=asyncio.subprocess.DEVNULL) @@ -253,7 +253,7 @@ async def get_routes(request): return web.json_response(list(request.app.router)) -async def create_route(request): +async def append_route(request): """Create a new Kapow! route.""" request.app.router._frozen = False content = await request.json() @@ -298,7 +298,7 @@ async def run_init_script(app): shell_task = await asyncio.create_subprocess_shell( cmd, env={**os.environ, - "KAPOW_URL": "http://localhost:8080/kapow" + "KAPOW_URL": "http://localhost:8080" }) await shell_task.wait() @@ -315,12 +315,15 @@ def kapow(): """Start aiohttp app.""" app = web.Application(client_max_size=1024**3) app.add_routes([ - web.get('/kapow/routes', get_routes), - web.post('/kapow/routes', create_route), - web.delete('/kapow/routes/{id}', delete_route), - web.get('/kapow/connections/{id}/{field:.*}', get_field), - # web.post('/kapow/connections/{id}/{field:.*}', append_field), - web.put('/kapow/connections/{id}/{field:.*}', set_field), + # Control API + web.get('/routes', get_routes), + web.post('/routes', append_route), # TODO: return route index + # web.put('/routes', insert_route), # TODO: return route index + web.delete('/routes/{id}', delete_route), + + # Data API + web.get('/handlers/{id}/{field:.*}', get_field), + web.put('/handlers/{id}/{field:.*}', set_field), ]) app.on_startup.append(start_background_tasks) web.run_app(app) From 0938fc225ef1460a511faf8109939ccbc1d8c232 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Mon, 27 May 2019 16:20:04 +0200 Subject: [PATCH 02/16] poc: add tester for pandoc example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- poc/examples/pandoc/testme | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 poc/examples/pandoc/testme diff --git a/poc/examples/pandoc/testme b/poc/examples/pandoc/testme new file mode 100755 index 0000000..e2fabd3 --- /dev/null +++ b/poc/examples/pandoc/testme @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +curl -X POST --data-binary @- http://localhost:8080/convert/markdown/man < Date: Mon, 27 May 2019 16:41:47 +0200 Subject: [PATCH 03/16] poc: add tester to eval example --- poc/examples/eval.testme | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 poc/examples/eval.testme diff --git a/poc/examples/eval.testme b/poc/examples/eval.testme new file mode 100755 index 0000000..a17bfc9 --- /dev/null +++ b/poc/examples/eval.testme @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +curl -X POST --data-binary @- http://localhost:8080/eval < Date: Mon, 27 May 2019 16:42:41 +0200 Subject: [PATCH 04/16] poc: fix executable permissions to .pow scripts --- poc/examples/eval.pow | 0 poc/examples/nmap/nmap.pow | 0 poc/examples/pdfeditor/pdfeditor.pow | 0 poc/examples/torrent.pow | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 poc/examples/eval.pow mode change 100644 => 100755 poc/examples/nmap/nmap.pow mode change 100644 => 100755 poc/examples/pdfeditor/pdfeditor.pow mode change 100644 => 100755 poc/examples/torrent.pow diff --git a/poc/examples/eval.pow b/poc/examples/eval.pow old mode 100644 new mode 100755 diff --git a/poc/examples/nmap/nmap.pow b/poc/examples/nmap/nmap.pow old mode 100644 new mode 100755 diff --git a/poc/examples/pdfeditor/pdfeditor.pow b/poc/examples/pdfeditor/pdfeditor.pow old mode 100644 new mode 100755 diff --git a/poc/examples/torrent.pow b/poc/examples/torrent.pow old mode 100644 new mode 100755 From 019356b7ae9ecae44aa88e115236db3f65dd1996 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 08:17:13 +0200 Subject: [PATCH 05/16] spec: misc style tweaks --- spec/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/spec/README.md b/spec/README.md index f9d18d4..0365edb 100644 --- a/spec/README.md +++ b/spec/README.md @@ -13,7 +13,7 @@ Because we think that: ## How? -So, how we can mix the **web** and the **shell**? Let's see... +So, how we can mix the **web** and the **shell**? Let's see... The **web** and the **shell** are two different beasts, both packed with history. @@ -22,14 +22,14 @@ There are some concepts in HTTP and the shell that **resemble each other**. ``` +------------------------+-------------------------+ - | HTTP | SHELL | + | HTTP | Shell | +--------------+------------------------+-------------------------+ | Input | POST form-encoding | Command line parameters | | Parameters | GET parameters | Environment variables | | | Headers | | | | Serialized body (JSON) | | +--------------+------------------------+-------------------------+ - | Data Streams | Response/Request Body | Stdin/Stdout/Stderr | + | Data Streams | Response/Request Body | stdin/stdout/stderr | | | Websocket | Input/Output files | | | Uploaded files | | +--------------+------------------------+-------------------------+ @@ -39,11 +39,11 @@ There are some concepts in HTTP and the shell that **resemble each other**. ``` Any tool designed to give an HTTP interface to an existing shell command -**must map concepts of boths**. For example: +**must map concepts from both domains**. For example: - "GET parameters" to "Command line parameters" - "Headers" to "Environment variables" -- "Stdout" to "Response body" +- "stdout" to "Response body" Kapow! is not opinionated about the different ways you can map both worlds. Instead, it provides a concise set of tools, with a set of sensible defaults, @@ -52,8 +52,8 @@ allowing the user to express the desired mapping in an explicit way. ### Why not tool "X"? -All the alternatives we found are **rigid** about how they match between HTTP -and shell concepts. +All the alternatives we found are **rigid** about the way they match between +HTTP and shell concepts. * [shell2http](https://github.com/msoap/shell2http): HTTP-server to execute shell commands. Designed for development, prototyping or remote control. @@ -78,7 +78,7 @@ incapable in others. * Boilerplate * Custom code = More bugs -* Security issues (Command injection, etc) +* Security issues (command injection, etc) * Dependency on developers * **"A programming language is low level when its programs require attention to the irrelevant"** *Alan Perlis* @@ -111,7 +111,7 @@ TODO: Intro to Architecture ### API Kapow! server interacts with the outside world only through its HTTP API. Any -program making the correct HTTP request to a Kapow! server, can change its +program making the correct HTTP request to a Kapow! server can change its behavior. Kapow! exposes two distinct APIs, a control API and a data API, described @@ -135,7 +135,7 @@ whole lifetime of the server. operating the client. The human can use this information to make a decision on how to proceed. * All successful API calls will return a representation of the *final* state - attained by the objects which have been addressed (requested, set or + attained by the objects which have been addressed (either requested, set or deleted). For instance, given this request: @@ -169,7 +169,7 @@ Kapow! provides a way to control its internal state through these elements. ### Routes Routes are the mechanism that allows Kapow! to find the correct program to -respond to an external event (e.g. an incomming HTTP request). +respond to an external event (e.g. an incoming HTTP request). #### List routes @@ -266,8 +266,8 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Sample Call**: TODO * **Notes**: * Route numbering starts at zero. - * When `index` is not provided or is less than 0 the route will be inserted - first, effectively making it index 0. + * When `index` is not provided or is less than `0` the route will be inserted + first, effectively making it index `0`. * Conversely, when `index` is greater than the number of entries on the route table, it will be inserted last. * A successful request will yield a response containing all the effective From af0d8658d9fdd6cfa6dc3cdb7c89561796775c66 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 11:49:14 +0200 Subject: [PATCH 06/16] spec: fix OK status code for POST (200->201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: César Gallego Rodríguez --- spec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/README.md b/spec/README.md index 0365edb..33a64c2 100644 --- a/spec/README.md +++ b/spec/README.md @@ -202,7 +202,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. } ``` * **Success Responses**: - * **Code**: `200 OK`
+ * **Code**: `201 Created`
**Header**: `Content-Type: application/json`
**Content**:
``` From 6ad5417a664d7bd53ab0707b17db2dba1371184e Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 12:57:05 +0200 Subject: [PATCH 07/16] spec: resolve a bunch of TODOs and add some tweaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: César Gallego Rodríguez --- spec/README.md | 89 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/spec/README.md b/spec/README.md index 33a64c2..6996198 100644 --- a/spec/README.md +++ b/spec/README.md @@ -180,8 +180,24 @@ Returns JSON data about the current routes. * **Method**: `GET` * **Success Responses**: * **Code**: `200 OK`
- **Content**: TODO -* **Sample Call**: TODO + **Content**:
+ ``` + [ + { + "method": "GET", + "url_pattern": "/hello", + "entrypoint": null, + "command": "echo Hello World | response /body" + }, + { + "method": "POST", + "url_pattern": "/bye", + "entrypoint": null, + "command": "echo Bye World | response /body" + } + ] + ``` +* **Sample Call**: `$ curl $KAPOW_URL/routes` * **Notes**: Currently all routes are returned; in the future, a filter may be accepted. @@ -217,13 +233,35 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Error Responses**: * **Code**: `400 Malformed JSON` * **Code**: `400 Invalid Data Type` + * **Code**: `400 Invalid Route Spec` * **Code**: `400 Missing Mandatory Field`
**Header**: `Content-Type: application/json`
- **Content**: `{ "mandatory_fields": ["field1", "field2", "and so on"] }` -* **Sample Call**: TODO + **Content**: + ``` + { + "missing_mandatory_fields": [ + "url_pattern", + "command" + ] + } + ``` +* **Sample Call**: + ``` + $ curl -X POST --data-binary @- $KAPOW_URL/routes < **Header**: `Content-Type: application/json`
- **Content**: `{ "mandatory_fields": ["field1", "field2", "and so on"] }` + **Content**: + ``` + { + "missing_mandatory_fields": [ + "url_pattern", + "command" + ] + } + ``` * **Code**: `400 Invalid Index Type` -* **Sample Call**: TODO + * **Code**: `400 Index Already in Use` + * **Code**: `404 Invalid Index` + * **Code**: `404 Invalid Route Spec` +* **Sample Call**: + ``` + $ curl -X PUT --data-binary @- $KAPOW_URL/routes < - **Content**: TODO + **Content**: + ``` + { + "method": "GET", + "url_pattern": "/hello", + "entrypoint": null, + "command": "echo Hello World | response /body", + "index": 0 + } + ``` * **Error Responses**: * **Code**: `404 Not Found` -* **Sample Call**: TODO +* **Sample Call**: + ``` + $ curl -X DELETE $KAPOW_URL/routes/ROUTE_1f186c92_f906_4506_9788_a1f541b11d0f + ``` * **Notes**: From 49a3dea0910663b30a690b54a16e86555d635b5f Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 14:40:26 +0200 Subject: [PATCH 08/16] spec: render table with native github-flavoured markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: César Gallego Rodríguez --- spec/README.md | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/spec/README.md b/spec/README.md index 6996198..c767e1b 100644 --- a/spec/README.md +++ b/spec/README.md @@ -20,23 +20,11 @@ history. There are some concepts in HTTP and the shell that **resemble each other**. -``` - +------------------------+-------------------------+ - | HTTP | Shell | - +--------------+------------------------+-------------------------+ - | Input | POST form-encoding | Command line parameters | - | Parameters | GET parameters | Environment variables | - | | Headers | | - | | Serialized body (JSON) | | - +--------------+------------------------+-------------------------+ - | Data Streams | Response/Request Body | stdin/stdout/stderr | - | | Websocket | Input/Output files | - | | Uploaded files | | - +--------------+------------------------+-------------------------+ - | Control | Status codes | Signals | - | | HTTP Methods | Exit Codes | - +--------------+------------------------+-------------------------+ -``` + | | HTTP | Shell | + |------------------------|--------------------------------------------------------------------------------|----------------------------------------------------| + | Input
Parameters | POST form-encoding
Get parameters
Headers
Serialized body (JSON) | Command line parameters
Environment variables | + | Data Streams | Response/Request Body
Websocket
Uploaded files | stdin/stdout/stderr
Input/Output files | + | Control | Status codes
HTTP Methods | Signals
Exit Codes | Any tool designed to give an HTTP interface to an existing shell command **must map concepts from both domains**. For example: From 8e97efda3154d501c8479dfdb099fa4ba4b34394 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 15:32:07 +0200 Subject: [PATCH 09/16] spec: resolve a couple more TODOs --- spec/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/README.md b/spec/README.md index c767e1b..22b3a4c 100644 --- a/spec/README.md +++ b/spec/README.md @@ -489,7 +489,10 @@ Returns the value of the requested resource path, or an error if the resource pa **Code**: `400 Invalid Resource Path`
**Notes**: Check the list of valid resource paths at the top of this section. * **Code**: `404 Not Found` -* **Sample Call**: TODO +* **Sample Call**: + ``` + $ curl /handlers/$KAPOW_HANDLER_ID/request/body + ``` * **Notes**: TODO @@ -509,6 +512,10 @@ Returns the value of the requested resource path, or an error if the resource pa * **Code**: `404 Name Not Found`
**Notes**: Although the resource path is correct, no such name is present in the request. For instance, `/request/headers/Foo`, when no `Foo` header is not present in the request. * **Sample Call**: + ``` + FIXME: python snippet instead? + $ curl -X PUT /handlers/$KAPOW_HANDLER_ID/response/body < /tmp/some_file + ``` * **Notes**: From 0384d81b9fd6d5f09151afbbc4412e22bedf94ef Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 29 May 2019 07:15:13 +0200 Subject: [PATCH 10/16] =?UTF-8?q?spec:=20add=20UNIX=C2=AE=20registered=20s?= =?UTF-8?q?ign?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/README.md b/spec/README.md index 22b3a4c..59ae196 100644 --- a/spec/README.md +++ b/spec/README.md @@ -5,8 +5,8 @@ Because we think that: -- UNIX is great and we love it -- The UNIX shell is great +- UNIX® is great and we love it +- The UNIX® shell is great - HTTP interfaces are convenient and everywhere - CGI is not a good way to mix them @@ -76,7 +76,7 @@ incapable in others. ### Why not CGI? -* CGI is also **rigid** about how it matches between HTTP and UNIX process +* CGI is also **rigid** about how it matches between HTTP and UNIX® process concepts. Notably CGI *meta-variables* are injected into the script's environment; this behavior can and has been exploited by nasty attacks such as [Shellshock](https://en.wikipedia.org/wiki/Shellshock_(software_bug)). @@ -89,7 +89,7 @@ incapable in others. ## What? We named it Kapow!. It is pronounceable, short and meaningless... like every -good UNIX command ;-) +good UNIX® command ;-) TODO: Definition From 823974551d07de91bcc8e4b815b7938b5a97e6b4 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 29 May 2019 10:05:32 +0200 Subject: [PATCH 11/16] spec: enable syntax highlighting for code snippets --- spec/README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/README.md b/spec/README.md index 59ae196..de56d70 100644 --- a/spec/README.md +++ b/spec/README.md @@ -127,12 +127,12 @@ whole lifetime of the server. deleted). For instance, given this request: -``` +```http HTTP/1.1 GET /routes ``` an appropiate reponse may look like this: -``` +```http 200 OK Content-Type: application/json Content-Length: 189 @@ -169,7 +169,7 @@ Returns JSON data about the current routes. * **Success Responses**: * **Code**: `200 OK`
**Content**:
- ``` + ```json [ { "method": "GET", @@ -197,7 +197,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Method**: `POST` * **Header**: `Content-Type: application/json` * **Data Params**:
- ``` + ```json { "method": "GET", "url_pattern": "/hello", @@ -209,7 +209,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `201 Created`
**Header**: `Content-Type: application/json`
**Content**:
- ``` + ```json { "method": "GET", "url_pattern": "/hello", @@ -225,7 +225,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `400 Missing Mandatory Field`
**Header**: `Content-Type: application/json`
**Content**: - ``` + ```json { "missing_mandatory_fields": [ "url_pattern", @@ -234,7 +234,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. } ``` * **Sample Call**: - ``` + ```sh $ curl -X POST --data-binary @- $KAPOW_URL/routes < - ``` + ```json { "method": "GET", "url_pattern": "/hello", @@ -273,7 +273,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `200 OK`
**Header**: `Content-Type: application/json`
**Content**:
- ``` + ```json { "method": "GET", "url_pattern": "/hello", @@ -289,7 +289,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `400 Missing Mandatory Field`
**Header**: `Content-Type: application/json`
**Content**: - ``` + ```json { "missing_mandatory_fields": [ "url_pattern", @@ -302,7 +302,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `404 Invalid Index` * **Code**: `404 Invalid Route Spec` * **Sample Call**: - ``` + ```sh $ curl -X PUT --data-binary @- $KAPOW_URL/routes < **Content**: - ``` + ```json { "method": "GET", "url_pattern": "/hello", @@ -344,7 +344,7 @@ Removes the route identified by `:id`. * **Error Responses**: * **Code**: `404 Not Found` * **Sample Call**: - ``` + ```sh $ curl -X DELETE $KAPOW_URL/routes/ROUTE_1f186c92_f906_4506_9788_a1f541b11d0f ``` * **Notes**: @@ -442,7 +442,7 @@ following resource paths: - Comment: That would provide read-only access to the value of the request header `Content-Type`. - Read a field from a form. - Scenario: A request generated by submitting this form:
- ``` + ```html
First name:

@@ -490,7 +490,7 @@ Returns the value of the requested resource path, or an error if the resource pa **Notes**: Check the list of valid resource paths at the top of this section. * **Code**: `404 Not Found` * **Sample Call**: - ``` + ```sh $ curl /handlers/$KAPOW_HANDLER_ID/request/body ``` * **Notes**: TODO @@ -512,7 +512,7 @@ Returns the value of the requested resource path, or an error if the resource pa * **Code**: `404 Name Not Found`
**Notes**: Although the resource path is correct, no such name is present in the request. For instance, `/request/headers/Foo`, when no `Foo` header is not present in the request. * **Sample Call**: - ``` + ```sh FIXME: python snippet instead? $ curl -X PUT /handlers/$KAPOW_HANDLER_ID/response/body < /tmp/some_file ``` From da72ccbf707afb015fd14d6a0734637e2a0a7d2b Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 29 May 2019 10:14:54 +0200 Subject: [PATCH 12/16] spec: add missing explicit line breaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- spec/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/README.md b/spec/README.md index de56d70..3fd741d 100644 --- a/spec/README.md +++ b/spec/README.md @@ -224,7 +224,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `400 Invalid Route Spec` * **Code**: `400 Missing Mandatory Field`
**Header**: `Content-Type: application/json`
- **Content**: + **Content**:
```json { "missing_mandatory_fields": [ @@ -233,7 +233,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. ] } ``` -* **Sample Call**: +* **Sample Call**:
```sh $ curl -X POST --data-binary @- $KAPOW_URL/routes < **Header**: `Content-Type: application/json`
- **Content**: + **Content**:
```json { "missing_mandatory_fields": [ @@ -301,7 +301,7 @@ Accepts JSON data that defines a new route to be appended to the current routes. * **Code**: `400 Index Already in Use` * **Code**: `404 Invalid Index` * **Code**: `404 Invalid Route Spec` -* **Sample Call**: +* **Sample Call**:
```sh $ curl -X PUT --data-binary @- $KAPOW_URL/routes < - **Content**: + **Content**:
```json { "method": "GET", @@ -343,7 +343,7 @@ Removes the route identified by `:id`. ``` * **Error Responses**: * **Code**: `404 Not Found` -* **Sample Call**: +* **Sample Call**:
```sh $ curl -X DELETE $KAPOW_URL/routes/ROUTE_1f186c92_f906_4506_9788_a1f541b11d0f ``` @@ -489,7 +489,7 @@ Returns the value of the requested resource path, or an error if the resource pa **Code**: `400 Invalid Resource Path`
**Notes**: Check the list of valid resource paths at the top of this section. * **Code**: `404 Not Found` -* **Sample Call**: +* **Sample Call**:
```sh $ curl /handlers/$KAPOW_HANDLER_ID/request/body ``` @@ -511,7 +511,7 @@ Returns the value of the requested resource path, or an error if the resource pa * **Code**: `404 Handler Not Found` * **Code**: `404 Name Not Found`
**Notes**: Although the resource path is correct, no such name is present in the request. For instance, `/request/headers/Foo`, when no `Foo` header is not present in the request. -* **Sample Call**: +* **Sample Call**:
```sh FIXME: python snippet instead? $ curl -X PUT /handlers/$KAPOW_HANDLER_ID/response/body < /tmp/some_file From f45e1be1942180d48d0cd651d4a2bfe7a5be9b7e Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 29 May 2019 15:55:10 +0200 Subject: [PATCH 13/16] spec: add missing note on handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: César Gallego Rodríguez Co-authored-by: Roberto Abdelkader Martínez Pérez --- spec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/README.md b/spec/README.md index 3fd741d..9212994 100644 --- a/spec/README.md +++ b/spec/README.md @@ -493,7 +493,7 @@ Returns the value of the requested resource path, or an error if the resource pa ```sh $ curl /handlers/$KAPOW_HANDLER_ID/request/body ``` -* **Notes**: TODO +* **Notes**: The content may be empty. #### Overwrite the value of a resource From 02fce053031f164780abdc9fecfa2db0d1c3d64c Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 29 May 2019 16:33:10 +0200 Subject: [PATCH 14/16] spec: resolve a FIXUP regarding a sample call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- spec/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/README.md b/spec/README.md index 9212994..dc5352e 100644 --- a/spec/README.md +++ b/spec/README.md @@ -513,8 +513,7 @@ Returns the value of the requested resource path, or an error if the resource pa **Notes**: Although the resource path is correct, no such name is present in the request. For instance, `/request/headers/Foo`, when no `Foo` header is not present in the request. * **Sample Call**:
```sh - FIXME: python snippet instead? - $ curl -X PUT /handlers/$KAPOW_HANDLER_ID/response/body < /tmp/some_file + $ curl -X --data-binary '

Hello!

' PUT /handlers/$KAPOW_HANDLER_ID/response/body ``` * **Notes**: From 60e7a57622aaf1f7f2d86bed45e64d21e4bfa20e Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Tue, 28 May 2019 16:08:12 +0200 Subject: [PATCH 15/16] spec: explanation of the executables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: César Gallego Rodríguez --- spec/README.md | 139 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/spec/README.md b/spec/README.md index dc5352e..5d3f7de 100644 --- a/spec/README.md +++ b/spec/README.md @@ -539,32 +539,167 @@ Any compliant implementation of Kapow! must provide these commands: ### `kapow` -This implements the server, XXX +This is the master command, that shows the help if invoked without args, and +runs the sub-commands when provided to it. #### Example +```sh +$ kapow +Usage: kapow [OPTIONS] COMMAND [ARGS]... + +Options: + TBD + +Commands: + start starts a Kapow! server + route operates on routes +... +``` + + +### `kapow start` + +This command runs the Kapow! server, which is the core of Kapow!. If +run without parameters, it will run an unconfigured server. It can accept a path +to a `.pow` file, which is a shell script that contains commands to configure +the Kapow! server. + +The `.pow` can leverage the `kapow route` command, which is used to define a route. +The `kapow route` command needs a way to reach the Kapow! server, and for that, +`kapow` provides the `KAPOW_URL` variable in the environment of the +aforementioned shell script. + +Every time the kapow server receives a request, it will spawn a process to +handle it, according to the specified entrypoint, `/bin/sh -c` by default, and then +execute the specified command. This command is tasked with processing the +incoming request, and can leverage the `request` and `response` commands to +easily access the `HTTP Request` and `HTTP Response`, respectively. + +In order for `request` and `response` to do their job, they require a way to +reach the Kapow! server, as well as a way to identify the current request being +served. Thus, the Kapow! server adds the `KAPOW_URL` and `KAPOW_HANDLER_ID` to the +process' environment. + + +#### Example +```sh +$ kapow start /path/to/service.pow +``` ### `kapow route` +To serve an endpoint, you must first register it. + +`kapow route` registers/deregisters a route, which maps an +`HTTP` method and a URL pattern to the code that will handle the request. + +When registering, you can specify an *entrypoint*, which defaults to `/bin/sh -c`, +and an argument to it, the *command*. + +To deregister a route you must provide a *route_id*. + +**Notes**: + * The entrypoint definition matches *Docker*'s. + * The index matches the way *netfilter*'s `iptables` handles rule numbering. + + +#### **Environment** +- `KAPOW_URL` + + +#### **Help** +```sh +$ kapow route --help +Usage: kapow route [OPTIONS] COMMAND [ARGS]... + +Options: + --help Show this message and exit. + +Commands: + add + remove +``` +```sh +$ kapow route add --help +Usage: kapow route add [OPTIONS] URL_PATTERN [COMMAND_FILE] + +Options: + -c, --command TEXT + -e, --entrypoint TEXT + -X, --method TEXT + --url TEXT + --help Show this message and exit. +``` +```sh +$ kapow route remove --help +Usage: kapow route remove [OPTIONS] ROUTE_ID + +Options: + --url TEXT + --help Show this message and exit. +``` #### Example - +```sh +kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /matches/ip) | response /body' +``` ### `request` +Exposes the requests' resources. + + +#### **Environment** +- `KAPOW_URL` +- `KAPOW_HANDLER_ID` + #### Example +```sh +# Access the body of the request +request /body +``` ### `response` +Exposes the response's resources. + + +#### **Environment** +- `KAPOW_URL` +- `KAPOW_HANDLER_ID` + #### Example +```sh +# Write to the body of the response +echo 'Hello, World!' | response /body +``` ## An End-to-End Example +```sh +$ cat nmap.kpow +kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /matches/ip) | response /body' +``` +```sh +$ kapow ./nmap.kapow +``` +```sh +$ curl $KAPOW_URL/list/127.0.0.1 +Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-30 14:45 CEST +Nmap scan report for localhost (127.0.0.1) +Host is up (0.00011s latency). +Not shown: 999 closed ports +PORT STATE SERVICE +22/tcp open ssh + +Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds +``` ## Test Suite Notes From d067b46d11daad1a7011ac3d2747f0ec166300e5 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Thu, 30 May 2019 15:04:21 +0200 Subject: [PATCH 16/16] spec: fix quoting style --- spec/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/README.md b/spec/README.md index 5d3f7de..11b67f8 100644 --- a/spec/README.md +++ b/spec/README.md @@ -68,10 +68,10 @@ incapable in others. * Custom code = More bugs * Security issues (command injection, etc) * Dependency on developers -* **"A programming language is low level when its programs require attention to - the irrelevant"** *Alan Perlis* -* **There is more Unix-nature in one line of shell script than there is in ten - thousand lines of C** *Master Foo* +* *"A programming language is low level when its programs require attention to + the irrelevant."
—Alan Perlis* +* *"There is more Unix-nature in one line of shell script than there is in ten + thousand lines of C."
—Master Foo* ### Why not CGI?