kalendasz/app.py

81 lines
2.2 KiB
Python

import argparse
import base64
import json
import secrets
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, url_for
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)
@app.route("/")
def index():
return render_template("index.html", application_name=config["application_name"])
@app.route("/authorize")
def authorize():
public_key = private_key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
).decode()
nonce = secrets.token_hex(16)
client_id = secrets.token_hex(48)
session["nonce"] = nonce
session["client_id"] = client_id
params = {
"auth_redirect": config["redirect_url"],
"application_name": config["application_name"],
"scopes": "read",
"client_id": client_id,
"nonce": nonce,
"public_key": public_key,
}
query = "&".join(f"{k}={v}" for k, v in params.items())
return redirect(f"{config['forum_url']}/user-api-key/new?{query}")
@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)
data = private_key.decrypt(payload, padding.PKCS1v15())
response = json.loads(data)
except Exception:
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?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)