From 31e72ea24b2bcd227fa5c42f1752a06ffcd58546 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 8 Sep 2025 08:23:04 -0700 Subject: [PATCH] fix org invites --- app/main/views/register.py | 3 ++ app/notify_client/org_invite_api_client.py | 44 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/app/main/views/register.py b/app/main/views/register.py index c1fd591d2..f41d23c70 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -164,7 +164,9 @@ def set_up_your_profile(): abort(403, "Login.gov state not detected #invites") state_key = f"login-state-{unquote(state)}" + current_app.logger.debug(hilite(f"Register tries to fetch state_key {state_key}")) stored_state = unquote(redis_client.get(state_key).decode("utf8")) + if state != stored_state: flash("Internal error: cannot recognize stored state") abort(403, "Internal error: cannot recognize stored state #invites") @@ -185,6 +187,7 @@ def set_up_your_profile(): f"#invites: Got the user_email and user_uuid {user_uuid} from login.gov" ) invite_data = redis_client.get(f"invitedata-{state}") + # TODO fails here. invite_data = json.loads(invite_data) invited_user_id = invite_data["invited_user_id"] invited_user_email_address = get_invited_user_email_address(invited_user_id) diff --git a/app/notify_client/org_invite_api_client.py b/app/notify_client/org_invite_api_client.py index 10b596f40..d8b9c185d 100644 --- a/app/notify_client/org_invite_api_client.py +++ b/app/notify_client/org_invite_api_client.py @@ -1,5 +1,14 @@ +import json +import secrets +from urllib.parse import unquote + +from flask import current_app, request + +from app import redis_client from app.enums import InvitedOrgUserStatus from app.notify_client import NotifyAdminAPIClient, _attach_current_user +from app.utils import hilite +from notifications_utils.url_safe_token import generate_token class OrgInviteApiClient(NotifyAdminAPIClient): @@ -15,7 +24,42 @@ class OrgInviteApiClient(NotifyAdminAPIClient): "invite_link_host": self.admin_url, } data = _attach_current_user(data) + + ttl = 24 * 60 * 60 + # make and store the state + state = generate_token( + str(request.remote_addr), + current_app.config["SECRET_KEY"], + current_app.config["DANGEROUS_SALT"], + ) + state_key = f"login-state-{unquote(state)}" + redis_client.set(state_key, state, ex=ttl) + current_app.logger.debug( + hilite(f"SET THE STATE KEY TO {state} with state_key {state_key}") + ) + + # make and store the nonce + nonce = secrets.token_urlsafe() + nonce_key = f"login-nonce-{unquote(nonce)}" + redis_client.set(nonce_key, nonce, ex=ttl) # save the nonce to redis. + current_app.logger.debug( + hilite(f"SET THE STATE KEY TO {state} with state_key {state_key}") + ) + + data["nonce"] = nonce # This is passed to api for the invite url. + data["state"] = state # This is passed to api for the invite url. + resp = self.post(url="/organization/{}/invite".format(org_id), data=data) + current_app.logger.debug(hilite(f"RESP is {resp}")) + + invite_data_key = f"invitedata-{unquote(state)}" + redis_invite_data = resp["invite"] + redis_invite_data = json.dumps(redis_invite_data) + redis_client.set(invite_data_key, redis_invite_data, ex=ttl) + current_app.logger.debug( + hilite(f"SET invite_data_key {invite_data_key} to {redis_invite_data}") + ) + return resp["data"] def get_invites_for_organization(self, org_id):