From ea02a50536ddd47e31b711f8704ece376a3015a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Fri, 26 Apr 2019 07:45:33 +0200 Subject: [PATCH] Removing old-style kapow. --- Dockerfile | 10 - Pipfile | 19 -- Pipfile.lock | 538 ------------------------------- examples/eval.pow | 3 - examples/nmap/Dockerfile | 4 - examples/nmap/nmap.pow | 3 - examples/operator.pow | 37 --- examples/pandoc.pow | 31 -- examples/pdfeditor/index.html | 41 --- examples/pdfeditor/pdfeditor.pow | 19 -- examples/torrent.pow | 28 -- kapow.py | 504 ----------------------------- proposal.md | 130 -------- 13 files changed, 1367 deletions(-) delete mode 100644 Dockerfile delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100644 examples/eval.pow delete mode 100644 examples/nmap/Dockerfile delete mode 100644 examples/nmap/nmap.pow delete mode 100644 examples/operator.pow delete mode 100644 examples/pandoc.pow delete mode 100644 examples/pdfeditor/index.html delete mode 100644 examples/pdfeditor/pdfeditor.pow delete mode 100644 examples/torrent.pow delete mode 100644 kapow.py delete mode 100644 proposal.md diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 99464d6..0000000 --- a/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM python:3.7.3-alpine3.8 - -# Install Dependences -RUN pip install pipenv -COPY Pipfile Pipfile.lock ./ -RUN pipenv install --system --deploy && rm Pipfile Pipfile.lock - -# Install kapow! -COPY kapow.py /usr/sbin/kapow -RUN chmod a+x /usr/sbin/kapow diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 8ac1f0a..0000000 --- a/Pipfile +++ /dev/null @@ -1,19 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -sphinx = "*" -ipython = "*" -ipdb = "*" -pylint = "*" - -[packages] -pyparsing = "*" -aiohttp = "*" -click = "*" -aiofiles = "*" - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index cf99a95..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,538 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "fc23d2e0b455dc19dab220e38b1b8689a09c8aebd5b6657b06ec906462f5388a" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "aiofiles": { - "hashes": [ - "sha256:021ea0ba314a86027c166ecc4b4c07f2d40fc0f4b3a950d1868a0f2571c2bbee", - "sha256:1e644c2573f953664368de28d2aa4c89dfd64550429d0c27c4680ccd3aa4985d" - ], - "index": "pypi", - "version": "==0.4.0" - }, - "aiohttp": { - "hashes": [ - "sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55", - "sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed", - "sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10", - "sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5", - "sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1", - "sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939", - "sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390", - "sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa", - "sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc", - "sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5", - "sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d", - "sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf", - "sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6", - "sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72", - "sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12", - "sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366", - "sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4", - "sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300", - "sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d", - "sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303", - "sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6", - "sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889" - ], - "index": "pypi", - "version": "==3.5.4" - }, - "async-timeout": { - "hashes": [ - "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" - ], - "version": "==3.0.1" - }, - "attrs": { - "hashes": [ - "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", - "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" - ], - "version": "==19.1.0" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "index": "pypi", - "version": "==7.0" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "multidict": { - "hashes": [ - "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f", - "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3", - "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef", - "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b", - "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73", - "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc", - "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3", - "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd", - "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351", - "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941", - "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d", - "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1", - "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b", - "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a", - "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3", - "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7", - "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0", - "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0", - "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014", - "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5", - "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036", - "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d", - "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a", - "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce", - "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1", - "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", - "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", - "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", - "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" - ], - "version": "==4.5.2" - }, - "pyparsing": { - "hashes": [ - "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", - "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" - ], - "index": "pypi", - "version": "==2.4.0" - }, - "yarl": { - "hashes": [ - "sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9", - "sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f", - "sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb", - "sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320", - "sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842", - "sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0", - "sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829", - "sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310", - "sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4", - "sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8", - "sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1" - ], - "version": "==1.3.0" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "astroid": { - "hashes": [ - "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", - "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" - ], - "version": "==2.2.5" - }, - "babel": { - "hashes": [ - "sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", - "sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23" - ], - "version": "==2.6.0" - }, - "backcall": { - "hashes": [ - "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", - "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2" - ], - "version": "==0.1.0" - }, - "certifi": { - "hashes": [ - "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", - "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" - ], - "version": "==2019.3.9" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "decorator": { - "hashes": [ - "sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", - "sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6" - ], - "version": "==4.4.0" - }, - "docutils": { - "hashes": [ - "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", - "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", - "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" - ], - "version": "==0.14" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "imagesize": { - "hashes": [ - "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", - "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" - ], - "version": "==1.1.0" - }, - "ipdb": { - "hashes": [ - "sha256:dce2112557edfe759742ca2d0fee35c59c97b0cc7a05398b791079d78f1519ce" - ], - "index": "pypi", - "version": "==0.12" - }, - "ipython": { - "hashes": [ - "sha256:b038baa489c38f6d853a3cfc4c635b0cda66f2864d136fe8f40c1a6e334e2a6b", - "sha256:f5102c1cd67e399ec8ea66bcebe6e3968ea25a8977e53f012963e5affeb1fe38" - ], - "index": "pypi", - "version": "==7.4.0" - }, - "ipython-genutils": { - "hashes": [ - "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", - "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" - ], - "version": "==0.2.0" - }, - "isort": { - "hashes": [ - "sha256:01cb7e1ca5e6c5b3f235f0385057f70558b70d2f00320208825fa62887292f43", - "sha256:268067462aed7eb2a1e237fcb287852f22077de3fb07964e87e00f829eea2d1a" - ], - "version": "==4.3.17" - }, - "jedi": { - "hashes": [ - "sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b", - "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c" - ], - "version": "==0.13.3" - }, - "jinja2": { - "hashes": [ - "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", - "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" - ], - "version": "==2.10.1" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", - "sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", - "sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", - "sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", - "sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", - "sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", - "sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", - "sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", - "sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", - "sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", - "sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", - "sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", - "sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", - "sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", - "sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", - "sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", - "sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", - "sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", - "sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", - "sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", - "sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", - "sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", - "sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", - "sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", - "sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", - "sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", - "sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", - "sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", - "sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" - ], - "version": "==1.3.1" - }, - "markupsafe": { - "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "packaging": { - "hashes": [ - "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", - "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" - ], - "version": "==19.0" - }, - "parso": { - "hashes": [ - "sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33", - "sha256:2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376" - ], - "version": "==0.4.0" - }, - "pexpect": { - "hashes": [ - "sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1", - "sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb" - ], - "markers": "sys_platform != 'win32'", - "version": "==4.7.0" - }, - "pickleshare": { - "hashes": [ - "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", - "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56" - ], - "version": "==0.7.5" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780", - "sha256:2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1", - "sha256:977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55" - ], - "version": "==2.0.9" - }, - "ptyprocess": { - "hashes": [ - "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", - "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f" - ], - "version": "==0.6.0" - }, - "pygments": { - "hashes": [ - "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", - "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" - ], - "version": "==2.3.1" - }, - "pylint": { - "hashes": [ - "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", - "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" - ], - "index": "pypi", - "version": "==2.3.1" - }, - "pyparsing": { - "hashes": [ - "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", - "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03" - ], - "index": "pypi", - "version": "==2.4.0" - }, - "pytz": { - "hashes": [ - "sha256:303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", - "sha256:d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141" - ], - "version": "==2019.1" - }, - "requests": { - "hashes": [ - "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", - "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" - ], - "version": "==2.21.0" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", - "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" - ], - "version": "==1.2.1" - }, - "sphinx": { - "hashes": [ - "sha256:423280646fb37944dd3c85c58fb92a20d745793a9f6c511f59da82fa97cd404b", - "sha256:de930f42600a4fef993587633984cc5027dedba2464bcf00ddace26b40f8d9ce" - ], - "index": "pypi", - "version": "==2.0.1" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", - "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", - "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", - "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", - "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", - "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" - ], - "version": "==1.1.3" - }, - "traitlets": { - "hashes": [ - "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", - "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9" - ], - "version": "==4.3.2" - }, - "typed-ast": { - "hashes": [ - "sha256:04894d268ba6eab7e093d43107869ad49e7b5ef40d1a94243ea49b352061b200", - "sha256:16616ece19daddc586e499a3d2f560302c11f122b9c692bc216e821ae32aa0d0", - "sha256:252fdae740964b2d3cdfb3f84dcb4d6247a48a6abe2579e8029ab3be3cdc026c", - "sha256:2af80a373af123d0b9f44941a46df67ef0ff7a60f95872412a145f4500a7fc99", - "sha256:2c88d0a913229a06282b285f42a31e063c3bf9071ff65c5ea4c12acb6977c6a7", - "sha256:2ea99c029ebd4b5a308d915cc7fb95b8e1201d60b065450d5d26deb65d3f2bc1", - "sha256:3d2e3ab175fc097d2a51c7a0d3fda442f35ebcc93bb1d7bd9b95ad893e44c04d", - "sha256:4766dd695548a15ee766927bf883fb90c6ac8321be5a60c141f18628fb7f8da8", - "sha256:56b6978798502ef66625a2e0f80cf923da64e328da8bbe16c1ff928c70c873de", - "sha256:5cddb6f8bce14325b2863f9d5ac5c51e07b71b462361fd815d1d7706d3a9d682", - "sha256:644ee788222d81555af543b70a1098f2025db38eaa99226f3a75a6854924d4db", - "sha256:64cf762049fc4775efe6b27161467e76d0ba145862802a65eefc8879086fc6f8", - "sha256:68c362848d9fb71d3c3e5f43c09974a0ae319144634e7a47db62f0f2a54a7fa7", - "sha256:6c1f3c6f6635e611d58e467bf4371883568f0de9ccc4606f17048142dec14a1f", - "sha256:b213d4a02eec4ddf622f4d2fbc539f062af3788d1f332f028a2e19c42da53f15", - "sha256:bb27d4e7805a7de0e35bd0cb1411bc85f807968b2b0539597a49a23b00a622ae", - "sha256:c9d414512eaa417aadae7758bc118868cd2396b0e6138c1dd4fda96679c079d3", - "sha256:f0937165d1e25477b01081c4763d2d9cdc3b18af69cb259dd4f640c9b900fe5e", - "sha256:fb96a6e2c11059ecf84e6741a319f93f683e440e341d4489c9b161eca251cf2a", - "sha256:fc71d2d6ae56a091a8d94f33ec9d0f2001d1cb1db423d8b4355debfe9ce689b7" - ], - "markers": "implementation_name == 'cpython'", - "version": "==1.3.4" - }, - "urllib3": { - "hashes": [ - "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", - "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" - ], - "version": "==1.24.2" - }, - "wcwidth": { - "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" - ], - "version": "==0.1.7" - }, - "wrapt": { - "hashes": [ - "sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533" - ], - "version": "==1.11.1" - } - } -} diff --git a/examples/eval.pow b/examples/eval.pow deleted file mode 100644 index ba06e18..0000000 --- a/examples/eval.pow +++ /dev/null @@ -1,3 +0,0 @@ -POST /eval { - (@raw:request/body) > @fifo:response/stream/lines -} diff --git a/examples/nmap/Dockerfile b/examples/nmap/Dockerfile deleted file mode 100644 index 5c44761..0000000 --- a/examples/nmap/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM kapow -RUN apk add nmap -COPY nmap.pow . -CMD kapow nmap.pow diff --git a/examples/nmap/nmap.pow b/examples/nmap/nmap.pow deleted file mode 100644 index b0ae220..0000000 --- a/examples/nmap/nmap.pow +++ /dev/null @@ -1,3 +0,0 @@ -POST /list/{ip} { - nmap -sL @value:request/match/ip > @fifo:response/body -} diff --git a/examples/operator.pow b/examples/operator.pow deleted file mode 100644 index b2c0fa3..0000000 --- a/examples/operator.pow +++ /dev/null @@ -1,37 +0,0 @@ -GET /list/files { - ls -la @value:request/params/path > @fifo:response/body -} - -GET /list/processes { - ps -aux > @fifo:response/body -} - -GET /show/cpuinfo { - cat /proc/cpuinfo > @fifo:response/body -} - -GET /show/memory { - free -m > @fifo:response/body -} - -GET /show/disk { - df -h > @fifo:response/body -} - -GET /show/connections { - ss -pluton > @fifo:response/body -} - -GET /show/mounts { - mount > @fifo:response/body -} - -GET /tail/dmesg { - echo "text/plain" > @fifo:response/header/Content-Type - dmesg -w > @fifo:response/stream/lines -} - -GET /tail/journal { - echo "text/plain" > @fifo:response/header/Content-Type - journalctl -f > @fifo:response/stream/lines -} diff --git a/examples/pandoc.pow b/examples/pandoc.pow deleted file mode 100644 index dc458ba..0000000 --- a/examples/pandoc.pow +++ /dev/null @@ -1,31 +0,0 @@ -POST /convert/{from}/pdf { - tmpfile=$(mktemp --suffix=.pdf) - pandoc --from=@value:request/match/from \ - --to=pdf \ - --output=${tmpfile} \ - -t latex \ - @file:request/body - if [ $? -eq 0 ]; then - cat ${tmpfile} > @fifo:response/body - echo "application/pdf" > @fifo:response/header/Content-Type - echo 200 > @fifo:response/status - else - echo 500 > @fifo:response/status - fi - rm -f ${tmpfile} -} - -POST /convert/{from}/{to} { - pandoc --from=@value:request/match/from \ - --to=@value:request/match/to \ - --output=@fifo:response/body \ - @file:request/body -} - -GET /formats/input { - pandoc --list-input-formats > @fifo:response/body -} - -GET /formats/output { - pandoc --list-output-formats | grep -v pdf > @fifo:response/body -} diff --git a/examples/pdfeditor/index.html b/examples/pdfeditor/index.html deleted file mode 100644 index 378898b..0000000 --- a/examples/pdfeditor/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - PDF Editor - - - -
-
-
-
-
-
-
-
AWYSIWYG PDF Editor
-
-
InputFormat
- -
-
-
InputFormat
- -
-
-
Preview!
-
-
-
-
-
- -
-
-
-
-
- - - diff --git a/examples/pdfeditor/pdfeditor.pow b/examples/pdfeditor/pdfeditor.pow deleted file mode 100644 index c41b7bd..0000000 --- a/examples/pdfeditor/pdfeditor.pow +++ /dev/null @@ -1,19 +0,0 @@ -POST /editor/pdf { - tmpfile=$(mktemp --suffix=.pdf) - pandoc --from=@value:request/form/from \ - --to=pdf \ - --output=${tmpfile} \ - -t latex \ - @file:request/form/content - if [ $? -eq 0 ]; then - cat ${tmpfile} > @fifo:response/body - echo "application/pdf" > @fifo:response/header/Content-Type - echo 200 > @fifo:response/status - else - echo 500 > @fifo:response/status - fi - rm -f ${tmpfile} - -} - -GET / = index.html diff --git a/examples/torrent.pow b/examples/torrent.pow deleted file mode 100644 index 519f335..0000000 --- a/examples/torrent.pow +++ /dev/null @@ -1,28 +0,0 @@ -GET / { - echo "text/html" > @fifo:response/header/Content-Type - cat > @fifo:response/body <<-HTML - - - Add me to your bookmarks! - - -HTML -} - -GET /save/magnet { - set -x - link=@value:request/param/link - [ -z $link ] && echo 400 > @fifo:response/status && exit 0 - - watch_folder=/tmp - cd $watch_folder - [[ "$link" =~ xt=urn:btih:([^&/]+) ]] || exit; - echo "d10:magnet-uri${#link}:${link}e" > "meta-${BASH_REMATCH[1]}.torrent" - - echo 302 > @fifo:response/status - echo "/torrent/list" > @fifo:response/header/Location -} - -GET /torrent/list { - echo "..." > @fifo:response/body -} diff --git a/kapow.py b/kapow.py deleted file mode 100644 index c8bffe9..0000000 --- a/kapow.py +++ /dev/null @@ -1,504 +0,0 @@ -#!/usr/bin/env python -""" -A Kapow! interpreter written in Python. - -""" - -from dataclasses import dataclass -from shlex import quote as shell_quote -from string import Template -import asyncio -import contextlib -import io -import logging -import os -import sys -import tempfile -import threading -import traceback - -from aiohttp import web -from pyparsing import alphas, nums, White -from pyparsing import LineStart, LineEnd, SkipTo -from pyparsing import Literal, Combine, Word, Suppress -from pyparsing import OneOrMore, Optional, delimitedList -import aiofiles -import click - -log = logging.getLogger('kapow') - -######################################################################## -# Parser # -######################################################################## - -COMMENT = (Literal('#') + SkipTo(LineEnd()))(name="comment") - -# Method -METHOD = (Literal('GET') - | Literal('POST') - | Literal('PUT') - | Literal('DELETE') - | Literal('PATCH')) -MULTI_METHOD = delimitedList(METHOD, delim="|", combine=True) -METHOD_SPEC = Combine(Literal('*') | MULTI_METHOD) - -# Pattern -REGEX = Word(alphas + nums + '\\+*,.[]-_')(name="regex") -SYMBOL = Word(alphas)(name="symbol") -P_PATTERN = Combine('/{' + SYMBOL + Optional(':' + REGEX) + '}') -P_PATH = Word('/', alphas + nums + '$-_.+!*\'(),') -URLPATTERN = Combine(OneOrMore(P_PATTERN | P_PATH))(name="urlpattern") - -# Body -BODY = (Suppress('{') - + SkipTo(Combine(LineStart() + '}' + LineEnd()))(name="body")) - -# Endpoint head -ENDPOINT = (Optional(METHOD_SPEC + Suppress(White()), - default='*')(name="method") - + URLPATTERN - + Suppress(White())) - -# Endpoint bodies -CODE_EP = (ENDPOINT + BODY)(name="code_ep") -PATH_EP = (ENDPOINT + '=' + SkipTo(LineEnd())(name="path"))(name="path_ep") - -KAPOW_PROGRAM = CODE_EP | PATH_EP | COMMENT - - -######################################################################## -# Resources # -######################################################################## - -@dataclass -class ResourceManager: - """A resource exposed to the subshell.""" - #: Kapow resource representation - kapow_repr: str - #: Representation of the resource that can be understood by the shell - shell_repr: str - #: Coroutine capable of managing the resource internally - coro: object - #: Path to readed fifo. Needs to be written for coro to release. - #: XXX: Use proper fifo async instead - fifo_path: str = None - #: Fifo direction 'read'/'write' - fifo_direction: str = None - - - -async def get_value(context, path): - """Return the value of an http resource.""" - def nrd(n): - """Return the nrd element in a path.""" - return path.split('/')[n] - - try: - if path == 'request/method': - return context['request'].method.encode('utf-8') - elif path == 'request/path': - return context['request'].path.encode('utf-8') - elif path.startswith('request/match'): - return context['request'].match_info[nrd(2)].encode('utf-8') - elif path.startswith('request/param'): - return context['request'].rel_url.query[nrd(2)].encode('utf-8') - elif path.startswith('request/header'): - return context['request'].headers[nrd(2)].encode('utf-8') - elif path.startswith('request/cookie'): - return context['request'].cookies[nrd(2)].encode('utf-8') - elif path.startswith('request/form'): - return (await context['request'].post())[nrd(2)].encode('utf-8') - elif path.startswith('request/file'): - name = nrd(2) - content = nrd(3) # filename / content - field = (await context['request'].post())[name] - if content == 'filename': - try: - return field.filename.encode('utf-8') - except: - return b'' - elif content == 'content': - try: - return field.file.read() - except: - return b'' - else: - raise ValueError(f'Unknown content type {content!r}') - elif path == 'request/body': - return await context['request'].read() - else: - raise ValueError(f'Unknown path {path!r}') - except KeyError: - return b'' - - -async def set_value(context, path, value): - """ - Write to an http resource. - - File-like resources like `body` get write() calls so they have - append semantics. Non file-like resources are just set. - - """ - if not value: - return - - def nrd(n): - return path.split('/')[n] - - if path == 'response/status': - context['response_status'] = int(value.decode('utf-8')) - elif path == 'response/body': - context['response_body'].write(value) - elif path == 'response/body': - context['response_stream'].write(value) - elif path.startswith('response/header/'): - clean = value.rstrip(b'\n').decode('utf-8') - context['response_headers'][nrd(2)] = clean - elif path.startswith('response/cookie/'): - clean = value.rstrip(b'\n').decode('utf-8') - context['response_cookies'][nrd(2)] = clean - else: - raise ValueError(f'Unknown path {path!r}') - - -def is_readable(path): - return path.startswith('request/') - - -def is_writable(path): - return path.startswith('response/') - - -def get_manager(resource, context): - """ - Return an async context manager capable of manage the given - resource. - """ - try: - view, path = resource.split(':') - except: - log.error(f"Invalid resource %r", resource) - raise - - @contextlib.asynccontextmanager - async def manager(): - """ - Manage the given `resource` as an async context manager. - - This context manager has different behavior depending on the - `view` and/or `path` of the resource. - - As a context manager it has three sections: - - Before `yield`: Prepare, if needed, the physical resource on - disk. - - `yield`: Return a `ResourceManager` object containing the - shell representation of the object and the coroutine - consuming/generating the resource data. - - After `yield`: Cleanup any disk resource. - """ - if view == 'raw': - if not is_readable(path): - raise ValueError(f'Non-readable path "{path}".') - else: - value = await get_value(context, path) - yield ResourceManager( - kapow_repr=resource, - shell_repr=value.decode('utf-8'), - coro=asyncio.sleep(0)) - elif view == 'value': - if not is_readable(path): - raise ValueError(f'Non-readable path "{path}".') - else: - value = await get_value(context, path) - yield ResourceManager( - kapow_repr=resource, - shell_repr=shell_quote(value.decode('utf-8')), - coro=asyncio.sleep(0)) - elif view == 'fifo': - # No race condition here? Shut your ass!! - # https://stackoverflow.com/a/1430566 - filename = tempfile.mktemp() - os.mkfifo(filename) - if path.startswith('response/stream'): - async def manage_fifo(): - initialized = False - try: - async with aiofiles.open(filename, 'rb') as fifo: - while True: - if path.endswith('/lines'): - chunk = await fifo.readline() - else: - chunk = await fifo.read(1024*10) - if chunk: - if not initialized: - # Give a chance to other coroutines - # to write changes to response - # (headers, etc) - await asyncio.sleep(0) - response = web.StreamResponse( - status=200, - headers=context["response_headers"], - reason="OK") - for name, value in context["response_cookies"]: - response.set_cookie(name, value) - context["stream"] = response - await response.prepare(context["request"]) - initialized = True - await response.write(chunk) - else: - break - finally: - os.unlink(filename) - else: - async def manage_fifo(): - try: - if is_readable(path): - async with aiofiles.open(filename, 'wb') as fifo: - await fifo.write(await get_value(context, path)) - elif is_writable(path): - async with aiofiles.open(filename, 'rb') as fifo: - buf = io.BytesIO() - while True: - chunk = await fifo.read(128) - if not chunk: - break - buf.write(chunk) - await set_value(context, path, buf.getvalue()) - else: - raise RuntimeError('WTF!') - finally: - os.unlink(filename) - yield ResourceManager( - kapow_repr=resource, - shell_repr=shell_quote(filename), - coro=manage_fifo(), - fifo_path=filename, - fifo_direction='read' if is_readable(path) else 'write') - elif view == 'file': - with tempfile.NamedTemporaryFile(mode='w+b', buffering=0) as tmp: - if is_readable(path): - value = await get_value(context, path) - tmp.write(value) - tmp.flush() - - yield ResourceManager( - kapow_repr=resource, - shell_repr=shell_quote(tmp.name), - coro=asyncio.sleep(0)) - - if is_writable(path): - tmp.seek(0) - await set_value(context, path, tmp.read()) - else: - raise ValueError(f'Unknown view type {view}') - - return manager - - -class KapowTemplate(Template): - """Shell-code templating for @view:path variables substitution""" - - delimiter = '@' - idpattern = r'(?a:[_a-z][_a-z0-9]*:[_a-z][-_a-z0-9/]*)' - - async def run(self, context): - """Run this template allocating and deallocating resources.""" - async with contextlib.AsyncExitStack() as stack: - # Initialize all resources creating a mapping - resources = dict() # resource: (shell_repr, manager) - for match in self.pattern.findall(self.template): - delim, resource, *rest = match - if not resource: # When is braced - resource = rest[0] - if delim and not resource and rest == ['', '']: - # Escaped - continue - if resource not in resources: - try: - manager = get_manager(resource, context) - except: - log.error(f"Invalid match %r, %r, %r", delim, resource, rest) - raise - resources[resource] = await stack.enter_async_context(manager()) - - code = self.substitute(**{k: v.shell_repr - for k, v in resources.items()}) - - log.debug("Creating tasks") - manager_tasks = {asyncio.create_task(v.coro): v - for k, v in resources.items()} - - await asyncio.sleep(0) - log.debug("Creating subprocess") - shell_task = await asyncio.create_subprocess_shell( - code, - executable=os.environ.get('SHELL', '/bin/sh')) - - log.debug("Waiting for subprocess") - await shell_task.wait() # Run the subshell process - - done, pending = await asyncio.wait(manager_tasks.keys(), timeout=0.1) - - if pending: - for task in pending: - resource = manager_tasks[task] - if resource.fifo_path is not None: - log.debug(f"Trying to stop %s", resource.kapow_repr) - if resource.fifo_direction == 'write': - os.system(f"echo -n > {resource.fifo_path} &") - elif resource.fifo_direction == 'read': - os.system(f"cat {resource.fifo_path} > /dev/null &") - else: - raise ValueError("Unknown direction") - else: - log.debug(f"Non-fifo resource pending!! %s", resource.kapow_repr) - - log.debug("Waiting for pending resources...") - await asyncio.wait(pending) - - await asyncio.sleep(0) - - -def create_context(request): - """Create a request context with default values.""" - context = dict() - context["request"] = request - context["stream"] = None - context["response_body"] = io.BytesIO() - context["response_status"] = 200 - context["response_headers"] = dict() - context["response_cookies"] = dict() - return context - - -async def response_from_context(context): - """Return the appropia aiohttp response for a given context.""" - if context["stream"] is not None: - await context["stream"].write_eof() - return context["stream"] - else: - body = context["response_body"].getvalue() - status = context["response_status"] - headers = context["response_headers"] - cookies = context["response_cookies"] - - # Content-Type guessing (for demo only) - if "Content-Type" not in headers: - try: - body = body.decode("utf-8") - except UnicodeDecodeError: - pass - else: - headers["Content-Type"] = "text/plain" - - response = web.Response(body=body, status=status, headers=headers) - for name, value in cookies.items(): - response.set_cookie(name, value) - - return response - - -def generate_endpoint(code, path=None): - """Return an aiohttp-endpoint coroutine to run kapow `code`.""" - async def endpoint(request): - context = create_context(request) - log.debug("Running endpoint %r", path) - try: - await KapowTemplate(code).run(context) # Will change context - except: - log.exception("Template crashed!") - log.debug("Endpoint finished, creating response %r", path) - response = await response_from_context(context) - log.debug("Responding %r", path) - return response - return endpoint - - -def path_server(path): - """Return an aiohttp-endpoint coroutine to serve the file in `path`.""" - # At initialization check - if not os.path.isfile(path): - raise NotImplementedError("Only files can be served.") - - async def serve_path(request): - # Per request check - if os.path.isdir(path): - raise NotImplementedError("Cannot serve whole directories yet.") - return web.FileResponse(path) - return serve_path - - -######################################################################## -# Webserver # -######################################################################## - -def register_code_endpoint(app, methods, pattern, code): - """Register all needed endpoints for the defined endpoint code.""" - endpoint = generate_endpoint(code, pattern) - for method in methods: # May be '*' - app.add_routes([web.route(method, pattern, endpoint)]) - - -def register_path_endpoint(app, methods, pattern, path): - """Register all needed endpoints for the defined file.""" - for method in methods: - if method != 'GET': - raise ValueError("Invalid method for serving files.") - else: - app.add_routes([web.static(pattern, path)]) - - -async def debug_tasks(): - while True: - await asyncio.sleep(1) - log.debug("Tasks: %s | Threads: %s", - len(asyncio.Task.all_tasks()), - threading.active_count()) - - -async def start_background_tasks(app): - app["debug_tasks"] = app.loop.create_task(debug_tasks()) - - -@click.command() -@click.option('--expression', '-e') -@click.option('--verbose', '-v', count=True) -@click.argument('program', type=click.File(), required=False) -@click.pass_context -def main(ctx, program, verbose, expression): - """Run the kapow server with the given command-line parameters.""" - if program is None and expression is None: - program = sys.stdin - - app = web.Application(client_max_size=1024*1024*1024) - - if verbose == 0: - _print = lambda _: None - logging.basicConfig(stream=sys.stderr, level=logging.ERROR) - else: - _print = lambda s: print(s, file=sys.stderr) - if verbose == 1: - logging.basicConfig(stream=sys.stderr, level=logging.INFO) - else: - logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) - if verbose > 2: - app.on_startup.append(start_background_tasks) - - source = expression if program is None else program.read() - - for ep, _, _ in KAPOW_PROGRAM.scanString(source): - if 'comment' in ep: - continue - methods = ep.method.asList()[0].split('|') - pattern = ''.join(ep.urlpattern) - if ep.body: - log.info(f"Registering [code] methods=%r pattern=%r", methods, pattern) - register_code_endpoint(app, methods, pattern, ep.body) - else: - log.info(f"Registering [path] methods=%r pattern=%r", methods, pattern) - register_path_endpoint(app, methods, pattern, ep.path) - web.run_app(app, print=_print) - -if __name__ == '__main__': - main() diff --git a/proposal.md b/proposal.md deleted file mode 100644 index 3ab2885..0000000 --- a/proposal.md +++ /dev/null @@ -1,130 +0,0 @@ -10-SECOND PROPOSAL -=================== - -*kapow* is a specialized language for marrying the **web** and the **shell**. - - -DESCRIPTION -=========== - -The **web** and the **shell** are two different beasts, both packed with 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 | | - +--------------+------------------------+-------------------------+ -``` - -Any tool designed to give an HTTP interface to an existing shell command **must map concepts of boths**. For example: - -- "GET parameters" to "Command line parameters" -- "Headers" to "Environment variables" -- "Stdout" to "Response body" - -*kapow* is not opinionated about the different ways you can map both worlds. Instead it provides a concise language used to express the mapping and a set of common defaults. - - -Why not tool...? ----------------- - -All the alternatives we found are **rigid** about how 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. Settings through two command line arguments, path and shell command. -* [websocketd](https://github.com/joewalnes/websocketd): Turn any program that uses STDIN/STDOUT into a WebSocket server. Like inetd, but for WebSockets. -* [webhook](https://github.com/adnanh/webhook): webhook is a lightweight incoming webhook server to run shell commands. -* [gotty](https://github.com/yudai/gotty): GoTTY is a simple command line tool that turns your CLI tools into web applications. (For interactive commands only) - -Tools with a rigid matching **can't evade** *[impedance mismatch](https://haacked.com/archive/2004/06/15/impedance-mismatch.aspx/)*. Resulting is an easy-to-use software, convenient in some scenarios but incapable in others. - - -Why not my good-old programming language...? --------------------------------------------- - -* Boilerplate -* 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 - -*kapow* aims to be halfway from one of the mentioned tools and a general programming language. A limited scripting language. Think of *awk*, 20 years later, for HTTP. - - -Example -------- - -Imagine you want to improve your monitoring system to be able to check if a WiFi in a remote building is working. Suppose you already have a wireless capable linux server on that building. - -What about exposing a wifi scan as a service? - -``` -$ iwlist scan | grep 'ESSID:"BBVA"' -``` - -The above command will list the visible WiFI networks and filter for the one we are interested in (**BBVA**); exiting with code **0** when found and **1** otherwise. - -We want to signal the WiFI status with a meaningful HTTP status code: 200 for UP and 503 for DOWN. - -So the only thing our service has to do is translate from the **command's exit code** to a meaningful **HTTP status code**. - -Our *kapow* program (monitor.pow) should look **something like** this: - -``` -/monitor/wifi = - $(iwlist scan | grep 'ESSID:"BBVA') - | 0 = status 200 # OK - | 1 = status 503 # Service Unavailable -``` - -With this code, the user can run the service with: - -``` -$ kapow monitor.pow -``` -And then: - -1. *kapow* will open a port with an HTTP server serving the URI **/monitor/wifi**. -2. When requested `curl http:///monitor/wifi`. The command is executed resulting in a WiFI scan. -3. The command's **exit code** is translated to an HTTP **status code** and returned. - -USE CASES OR VALUE -================== - -* Reuse 40+ years of existing computer programs as microservices (nanoservices?). -* Expose command line only tools as services. Eliminating the need of interactive SSH sessions. -* Fine-grained access control to CLI based on options/parameters - - -REQUIRED SKILLS -=============== - -- Knowledge of HTTP and the command line. -- Programming. -- Low-level stuff... - - -ESTIMATION -========== - -- 2 weeks - - -OUTPUT -====== - -- A collection of **concrete** use cases, 5 to 10. -- A DSL design (over paper) to implement the use cases. -- A working **dirty** proof of concept.