kalendasz/app.py

87 lines
2.3 KiB
Python

import argparse
import base64
import binascii
import json
import secrets
from urllib.parse import urlencode
import yaml
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from flask import Flask, redirect, render_template, request, session
parser = argparse.ArgumentParser()
parser.add_argument("config", help="Path to configuration file")
args = parser.parse_args()
with open(args.config) as f:
config = yaml.safe_load(f)
app = Flask(__name__)
app.secret_key = config["secret_key"]
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
).decode()
@app.route("/")
def index():
return render_template("index.html", application_name=config["application_name"])
@app.route("/authorize")
def authorize():
nonce = secrets.token_hex(16)
client_id = secrets.token_hex(48)
session["nonce"] = nonce
params = {
"auth_redirect": config["redirect_url"],
"application_name": config["application_name"],
"scopes": "read",
"client_id": client_id,
"nonce": nonce,
"public_key": public_key,
}
return redirect(f"{config['forum_url']}/user-api-key/new?{urlencode(params)}")
@app.route("/callback")
def callback():
payload_b64 = request.args.get("payload")
if not payload_b64:
return "Missing payload", 400
try:
payload = base64.b64decode(payload_b64)
except binascii.Error:
return "Failed to decode payload", 400
try:
data = private_key.decrypt(payload, padding.PKCS1v15())
response = json.loads(data)
except (ValueError, json.JSONDecodeError):
return "Failed to decrypt or decode payload", 400
if response.get("nonce") != session.get("nonce"):
return "Invalid nonce", 400
key = response["key"]
calendar_url = (
f"{config['forum_url']}/discourse-post-event/events.ics?"
+ urlencode({"order": "desc", "api_key": key})
)
return render_template(
"result.html",
application_name=config["application_name"],
calendar_url=calendar_url,
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)