Last active
January 22, 2021 09:54
-
-
Save spacelatte/b430b267f0063d77a43fc732b4f89aa0 to your computer and use it in GitHub Desktop.
#web #exception #api #flask #python #python3 #reporter #crud
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# start redis first: | |
# docker run --name=redis --rm -itdp 6379:6379 redis:latest | |
# install dependencies: | |
# python3 -m pip install -U flask redis | |
# run the app | |
# python3 reporter.py | |
# or | |
# python3 reporter.py redis://user:pass@redis-host:redis-port/db-number?retry_on_timeout=yes&decode_responses=yes | |
from flask import Flask, Response, request | |
from redis import Redis | |
import sys, time, json, hashlib, uuid, traceback | |
api = Flask(__name__) | |
mdb = Redis.from_url( | |
sys.argv[1] | |
if len(sys.argv) > 1 | |
else "redis://localhost:6379/0?retry_on_timeout=yes&decode_responses=yes" | |
) | |
key_prefix = "exception" | |
javascript = lambda url: """ | |
/* | |
window.addEventListener('error', function(event) { | |
console.log(event); | |
fetch('""" + url + """', { | |
method: "post", | |
cache: "no-cache", | |
redirect: "follow", | |
credentials: "same-origin", | |
headers: { | |
"content-type": "application/json", | |
}, | |
body: null, | |
}).then(function(res) { | |
return console.log("critical reported:", res); | |
}); | |
return; | |
}); | |
*/ | |
window.onerror = function(msg, src, line, col, err) { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("POST", '""" + url + """', true); | |
xhr.setRequestHeader("content-type", "application/json"); | |
xhr.withCredentials = true; | |
xhr.send(JSON.stringify({ | |
cookie: window.cookie, | |
loc: window.location, | |
msg: msg, | |
src: src, | |
line: line, | |
col: col, | |
err: err, | |
ua: navigator.userAgent, | |
}, null, 4)); | |
return; | |
} | |
""" | |
bypass_cors = lambda req: { | |
"access-control-allow-credentials": "true", | |
"access-control-allow-headers": "content-type", | |
"access-control-allow-origin": req.headers.get("origin") or "*", | |
} | |
def response_generic_err(error): | |
return Response( | |
f""" | |
something bad happened: {error} | |
--- | |
{traceback.format_exc()} | |
--- | |
{traceback.format_tb(None)} | |
""", | |
mimetype="text/plain", | |
status=500, | |
) | |
@api.after_request | |
def response_cors_headers(resp: Response): | |
resp.headers.update(bypass_cors(request)) | |
return resp | |
@api.before_request | |
def check_redis(): | |
try: | |
mdb.ping() | |
return None | |
except Exception as e: | |
return response_generic_err(e) | |
@api.route("/test", methods=[ "GET" ]) | |
def response_test_page(): | |
return Response( | |
""" | |
<p> hello world! </p> | |
<script type=text/javascript src=/js?url=/ ></script> | |
<script> | |
window.onload = function() { | |
non_existent_function(); | |
} | |
</script> | |
""", | |
mimetype="text/html", | |
status=200, | |
) | |
@api.route("/js", methods=[ "GET" ]) | |
def serve_index_js(cookie_key=key_prefix): | |
resp = Response( | |
javascript( | |
url=request.args.get( | |
key="url", | |
default=(request.url + "/.."), | |
type=str, | |
) | |
), | |
mimetype="application/javascript", | |
status=200, | |
) | |
if not request.cookies.get(key=cookie_key, default=None): | |
resp.set_cookie( | |
key=cookie_key, | |
value=hashlib.md5(uuid.uuid4().hex.encode()).hexdigest(), | |
httponly=False, | |
expires=None, | |
max_age=None, | |
secure=False, | |
domain=None, | |
path="/", | |
) | |
pass | |
return resp | |
@api.route("/", methods=[ "PUT", "POST" ]) | |
def save_incoming_data(cookie_key=key_prefix): | |
try: | |
u_session = request.cookies.get(key=cookie_key, default="unknown") | |
return Response( | |
json.dumps( | |
mdb.set( | |
name=f"{key_prefix}.{time.time()}.{request.remote_addr}.{u_session}", | |
value=json.dumps(request.get_json(force=True), indent="\t"), | |
ex=request.args.get(key="ttl", default=604800, type=int), | |
#keepttl=True, | |
), | |
indent="\t", | |
), | |
status=201, | |
mimetype="text/plain", | |
) | |
except Exception as e: | |
return response_generic_err(e) | |
@api.route("/", methods=[ "GET" ]) | |
def serve_keylist(): | |
try: | |
return Response( | |
json.dumps( | |
sorted( | |
mdb.scan_iter(match=f"{key_prefix}.*"), | |
reverse=True, | |
), | |
indent="\t", | |
), | |
mimetype="application/json", | |
status=200, | |
) | |
except Exception as e: | |
return response_generic_err(e) | |
@api.route("/<item>", methods=[ "GET" ]) | |
def serve_exception_data(item=None): | |
try: | |
return Response( | |
mdb.get(item), | |
mimetype="application/json", | |
status=200, | |
) | |
except Exception as e: | |
return response_generic_err(e) | |
@api.route("/<item>", methods=[ "DELETE" ]) | |
def delete_exception_data(item=None): | |
try: | |
return Response( | |
json.dumps(mdb.delete(item), indent="\t"), | |
mimetype="text/plain", | |
status=200, | |
) | |
except Exception as e: | |
return response_generic_err(e) | |
def main(): | |
api.run( | |
port=8000, | |
host="0.0.0.0", | |
#debug=, | |
) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment