1616from ..products import products_web
1717from ..products .models import Product
1818from ..security .api import check_password , encrypt_password
19+ from ..users import api as users_service
1920from ..utils import HOUR
2021from ..utils_rate_limiting import global_rate_limit_route
2122from ._confirmation import is_confirmation_valid , make_confirmation_link
@@ -52,7 +53,7 @@ class ResetPasswordBody(InputSchema):
5253@routes .post (f"/{ API_VTAG } /auth/reset-password" , name = "initiate_reset_password" )
5354@global_rate_limit_route (number_of_requests = 10 , interval_seconds = HOUR )
5455async def initiate_reset_password (request : web .Request ):
55- """First of the "Two-Step Action Confirmation pattern"
56+ """First of the "Two-Step Action Confirmation pattern": initiate_reset_password + complete_reset_password(code)
5657
5758 1. confirm user exists
5859 2. check user status
@@ -76,7 +77,7 @@ async def initiate_reset_password(request: web.Request):
7677 # with a given email or username.
7778 response = flash_response (MSG_EMAIL_SENT .format (email = request_body .email ), "INFO" )
7879
79- # check user exists
80+ # CHECK user exists
8081 user = await db .get_user ({"email" : request_body .email })
8182 if not user :
8283 _logger .warning (
@@ -86,7 +87,7 @@ async def initiate_reset_password(request: web.Request):
8687 )
8788 return response
8889
89- # check user state
90+ # CHECK user state
9091 try :
9192 validate_user_status (user = dict (user ), support_email = product .support_email )
9293 except web .HTTPError as err :
@@ -99,9 +100,16 @@ async def initiate_reset_password(request: web.Request):
99100
100101 assert user ["status" ] == ACTIVE # nosec
101102 assert user ["email" ] == request_body .email # nosec
103+ assert isinstance (user ["id" ], int ) # nosec
102104
103- # check access to product
104- # TODO:
105+ # CHECK access to product
106+ if not await users_service .is_user_in_product (
107+ request .app , user_id = user ["id" ], product_name = product .name
108+ ):
109+ _logger .warning (
110+ "Password rest requested for a registered user but wihtout access to product"
111+ )
112+ return response
105113
106114 if await is_confirmation_valid (cfg , db , user , action = RESET_PASSWORD ):
107115 _logger .warning (
@@ -111,10 +119,11 @@ async def initiate_reset_password(request: web.Request):
111119 # delete previous and resend new?
112120 return response
113121
114- # TODO: create confirmation code,
115- confirmation = await db .create_confirmation (user ["id" ], action = RESET_PASSWORD )
116- link = make_confirmation_link (request , confirmation )
117122 try :
123+ # Produce a link so that the front-end can hit `complete_reset_password`
124+ confirmation = await db .create_confirmation (user ["id" ], action = RESET_PASSWORD )
125+ link = make_confirmation_link (request , confirmation )
126+
118127 # primary reset email with a URL and the normal instructions.
119128 await send_email_from_template (
120129 request ,
0 commit comments