Skip to content

Instantly share code, notes, and snippets.

@spacelatte
Last active January 22, 2021 09:54
Show Gist options
  • Save spacelatte/b430b267f0063d77a43fc732b4f89aa0 to your computer and use it in GitHub Desktop.
Save spacelatte/b430b267f0063d77a43fc732b4f89aa0 to your computer and use it in GitHub Desktop.
#web #exception #api #flask #python #python3 #reporter #crud
#!/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