From eb5f05f2a05bfaf5ad7bb2c06cf78ec8af587492 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Sat, 14 Dec 2024 21:57:08 +0000 Subject: [PATCH] remove next query string from authentication logic. --- development.ini | 2 +- make_post_sell/lib/mail.py | 2 +- make_post_sell/templates/join-or-log-in.j2 | 5 -- make_post_sell/templates/shop_locations.j2 | 1 + .../templates/verification-challenge.j2 | 36 +++------- make_post_sell/tests/test_functional.py | 10 ++- make_post_sell/views/__init__.py | 7 +- make_post_sell/views/authentication.py | 68 ++++++------------- 8 files changed, 45 insertions(+), 86 deletions(-) diff --git a/development.ini b/development.ini index 631696b..fb31431 100644 --- a/development.ini +++ b/development.ini @@ -41,7 +41,7 @@ app.root_domain = blanka.foxhop.net app.root_domain_owner_email = russell.ballestrini@gmail.com app.root_url = http://blanka.foxhop.net:6501 -#app.email.relay = localhost:8025 +app.email.relay = localhost:8025 # TODO: these values should be moved to environment variables & we should create an # example app.env environment file. diff --git a/make_post_sell/lib/mail.py b/make_post_sell/lib/mail.py index 45fe2d6..676ab02 100644 --- a/make_post_sell/lib/mail.py +++ b/make_post_sell/lib/mail.py @@ -249,7 +249,7 @@ def send_invite_email(request, to_email, user, shop): subject = f"You have been invited to {shop.name}" join_link = request.route_url( "join-or-log-in", - _query={"email": to_email, "next": request.route_url("actions_new")}, + _query={"email": to_email}, ) message_text = INVITE_1_TEXT.format(user.email, shop.name, join_link) message_html = INVITE_1_HTML.format(subject, user.email, shop.name, join_link) diff --git a/make_post_sell/templates/join-or-log-in.j2 b/make_post_sell/templates/join-or-log-in.j2 index 1c49749..92aed0f 100644 --- a/make_post_sell/templates/join-or-log-in.j2 +++ b/make_post_sell/templates/join-or-log-in.j2 @@ -27,11 +27,6 @@ required autofocus /> - -

diff --git a/make_post_sell/templates/shop_locations.j2 b/make_post_sell/templates/shop_locations.j2 index c34673a..3ecb1df 100644 --- a/make_post_sell/templates/shop_locations.j2 +++ b/make_post_sell/templates/shop_locations.j2 @@ -12,6 +12,7 @@ {% for location in locations %}
  • {{ location.name }} + {% if location == request.shop_location %}(active){% endif %} {% if request.user in request.shop.owners %} ⚙ edit {% endif %} diff --git a/make_post_sell/templates/verification-challenge.j2 b/make_post_sell/templates/verification-challenge.j2 index e8894a5..99f6980 100644 --- a/make_post_sell/templates/verification-challenge.j2 +++ b/make_post_sell/templates/verification-challenge.j2 @@ -2,41 +2,25 @@ {% block content -%}
    diff --git a/make_post_sell/tests/test_functional.py b/make_post_sell/tests/test_functional.py index 75a8391..014a1f1 100644 --- a/make_post_sell/tests/test_functional.py +++ b/make_post_sell/tests/test_functional.py @@ -198,11 +198,15 @@ class AuthenticatedFunctionalTests(FunctionalTests): super(AuthenticatedFunctionalTests, self).tearDown() def log_in_user(self, user_creds): - # log in user. + # Set the email in the session before posting to the verification challenge + self.testapp.post("/join-or-log-in", {"email": user_creds[0]}) + + # Simulate entering the OTP res_login = self.testapp.post( - "/verification-challenge?email={}&raw-otp={}&submit".format(*user_creds) + "/verification-challenge", {"raw-otp": user_creds[1], "submit": True} ) - # attach csrf to class. + + # Attach csrf to class if needed res_csrf = self.testapp.get("/") # self.csrf = res_csrf.form.fields["csrf_token"][0].value return res_login diff --git a/make_post_sell/views/__init__.py b/make_post_sell/views/__init__.py index 94c555e..5126097 100644 --- a/make_post_sell/views/__init__.py +++ b/make_post_sell/views/__init__.py @@ -18,12 +18,11 @@ def user_required( def inner(request): if request.user and request.user.authenticated: return fn(request) + # Flash message request.session.flash((flash_msg, flash_level)) - next_url = request.url + # Redirect to the login route if redirect_to_route_name: - return HTTPFound( - request.route_url(redirect_to_route_name, _query={"next": next_url}) - ) + return HTTPFound(request.route_url(redirect_to_route_name)) return HTTPFound(get_referer_or_home(request)) return inner diff --git a/make_post_sell/views/authentication.py b/make_post_sell/views/authentication.py index 742309c..6b0ff00 100644 --- a/make_post_sell/views/authentication.py +++ b/make_post_sell/views/authentication.py @@ -34,15 +34,10 @@ def join_or_log_in(request): address & to authenticate the device displaying the challenge input field. """ _email_regex = re.compile("^[^@]+@[^@]+\.[^.@]+$") - - # get the raw OTP (one-time-password) from posted parameters. raw_otp = request.params.get("raw-otp", "") - - # get the email from posted parameters. email = request.params.get("email", "") if email and _email_regex.match(email) is None: - # posted email does not pass regex, set it to None. email = "" request.session.flash(("That email address is invalid.", "error")) @@ -50,10 +45,10 @@ def join_or_log_in(request): return request.spam if request.user and request.user.authenticated: + request.session.flash(("You are already authenticated!", "info")) return HTTPFound(get_referer_or_home(request)) elif email: - # get or create a User object from the posted email. user = get_or_create_user_by_email(request.dbsession, email) if user.throttle_password(): @@ -61,16 +56,11 @@ def join_or_log_in(request): f"Check email for a 6 digit verification code to log in. {user.email}", "info", ) - else: - # generate a new one-time-password and save to database raw_otp = user.new_password() request.dbsession.add(user) request.dbsession.flush() - - # email user the one-time-password and flash message. send_verification_digits_to_email(request, user.email, raw_otp) - msg = ( f"Check email for a 6 digit verification code to log in. {user.email}", "info", @@ -78,62 +68,50 @@ def join_or_log_in(request): request.session.flash(msg) - email_encoded = urlencode( - {"email": email, "next": request.params.get("next", "")} - ) - return HTTPFound(f"/verification-challenge?{email_encoded}") + # Store 'unauthed_email' in session instead of passing via query param + request.session["unauthed_email"] = email + + # Redirect to verification challenge without 'unauthed_email' in query + return HTTPFound("/verification-challenge") return { - "title": "join or log in", - "next": request.params.get("next", request.route_url("home")), + "title": "Join or Log In", } @view_config(route_name="verification-challenge", renderer="verification-challenge.j2") def verification_challenge(request): - # get the raw OTP (one-time-password) from posted parameters. - raw_otp = request.params.get("raw-otp", "") + # Retrieve 'unauthed_email' from the session + unauthed_email = request.session.get("unauthed_email", "") - # get the email from posted parameters. - email = request.params.get("email", "") + if not unauthed_email: + # If 'unauthed_email' is not in session, redirect to login/join + request.session.flash(("Email is required for verification.", "error")) + return HTTPFound("/join-or-log-in") - user = None - if email: - # get or create a User object from the posted email. - user = get_or_create_user_by_email(request.dbsession, email) + user = get_or_create_user_by_email(request.dbsession, unauthed_email) if "submit" in request.params: + raw_otp = request.params.get("raw-otp", "") if raw_otp and user.check_password(raw_otp): - # success: the user was verified. user.verified = True - name = "" - if user.full_name: - name = user.name + name = user.full_name or "" msg = (f"Welcome {name}", "success") + _ = request.session.pop("unauthed_email", None) request.session["authenticated_user_id"] = str(user.id) request.session.flash(msg) - # merge any products in the session cart - # into request user's active cart for this shop. + # Merge carts request.active_cart.merge_in_cart(request.session_cart) - - # delete old session only cart. request.dbsession.delete(request.session_cart) - - # make session cart match user's active cart. request.session["active_cart_id"] = str(request.active_cart.id) - - # save user and user's active cart. request.dbsession.add(user) request.dbsession.add(request.active_cart) request.dbsession.flush() - if request.active_cart.count > 0: - next_url = "/cart" - else: - next_url = request.params.get("next", request.route_url("home")) - - return HTTPFound(next_url) + return HTTPFound( + "/cart" if request.active_cart.count > 0 else request.route_url("home") + ) else: msg = ("Invalid Verification Code", "error") @@ -141,7 +119,5 @@ def verification_challenge(request): return { "title": "Please Enter Verification Code", - "email": email, - "raw_otp": raw_otp, - "next": request.params.get("next", request.route_url("home")), + "raw_otp": request.params.get("raw-otp", ""), }