keep fernet key in memory and rotate it safely

This commit is contained in:
Micha Albert 2024-08-31 00:44:04 +00:00
parent 3241ab8ccb
commit a2f34fbf0b

View file

@ -4,8 +4,7 @@ import json
import os import os
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from datetime import datetime from datetime import datetime
from random import choice from secrets import choice, token_hex
from secrets import token_hex
from typing import Dict, List from typing import Dict, List
import cv2 import cv2
@ -30,7 +29,23 @@ active_streams: List[Dict[str, str | bool]] = []
scheduler = AsyncIOScheduler() scheduler = AsyncIOScheduler()
FERNET = Fernet(os.environ["FERNET_KEY"]) FERNET_KEY = Fernet.generate_key()
FERNET_KEY_USERS = []
if FERNET_KEY == "":
raise TypeError("No Fernet key found, exiting...")
FERNET = Fernet(FERNET_KEY)
async def rotate_fernet_key():
global FERNET_KEY
global FERNET
if FERNET_KEY_USERS == []:
FERNET_KEY = Fernet.generate_key()
FERNET = Fernet(FERNET_KEY)
else:
print("not rotating key since we have a pending verification")
def get_recording_duration(timestamp, stream_key): def get_recording_duration(timestamp, stream_key):
@ -140,8 +155,10 @@ async def check_for_new():
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
await update_active() await update_active()
scheduler.start() scheduler.start()
scheduler.add_job(update_active, IntervalTrigger(seconds=5 * 60)) scheduler.add_job(update_active, IntervalTrigger(minutes=5))
scheduler.add_job(check_for_new, IntervalTrigger(seconds=3)) scheduler.add_job(check_for_new, IntervalTrigger(seconds=3))
scheduler.add_job(rotate_fernet_key, IntervalTrigger(minutes=30))
await rotate_fernet_key()
await db.connect() await db.connect()
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
for stream in await db.stream.find_many(): for stream in await db.stream.find_many():
@ -196,6 +213,8 @@ async def github_callback(request: Request):
code: str = request.query_params["code"] code: str = request.query_params["code"]
state: str = request.query_params["state"] state: str = request.query_params["state"]
user_id, pr_id = FERNET.decrypt(bytes.fromhex(state)).decode().split("+") user_id, pr_id = FERNET.decrypt(bytes.fromhex(state)).decode().split("+")
if user_id in FERNET_KEY_USERS:
FERNET_KEY_USERS.remove(user_id)
db_user = await db.user.find_first_or_raise(where={"slack_id": user_id}) db_user = await db.user.find_first_or_raise(where={"slack_id": user_id})
user_stream_key = ( user_stream_key = (
await db.stream.find_first_or_raise(where={"user_id": db_user.id}) await db.stream.find_first_or_raise(where={"user_id": db_user.id})
@ -299,8 +318,8 @@ async def github_callback(request: Request):
"<h1>Success! Your PR has been linked to your Slack account. Check your Slack DMs for the next steps!</h1>" "<h1>Success! Your PR has been linked to your Slack account. Check your Slack DMs for the next steps!</h1>"
) )
return HTMLResponse( return HTMLResponse(
f"<h1>Looks like something went wrong! DM @mra on slack.</h1><p>This info might be of use to them: {FERNET.encrypt(bytes(str(db_pr.gh_user_id) + " " + str(gh_user) + " " + user_id + " " + pr_id + " " + state, encoding='utf-8'))}</p>", "<h1>Looks like something went wrong! DM @mra on slack.</h1>",
status_code=403, status_code=500,
) )
@ -546,6 +565,8 @@ async def submit(ack: AsyncAck, command):
text="There doesn't seem to be a PR open with that ID! If this seems like a mistake, please message <@U05C64XMMHV> about it!", text="There doesn't seem to be a PR open with that ID! If this seems like a mistake, please message <@U05C64XMMHV> about it!",
) )
return return
if user_id not in FERNET_KEY_USERS:
FERNET_KEY_USERS.append(user_id)
await bolt.client.chat_postEphemeral( await bolt.client.chat_postEphemeral(
channel=channel_id, channel=channel_id,
user=user_id, user=user_id,