remove next query string from authentication logic.
This commit is contained in:
parent
c9aa05574e
commit
eb5f05f2a0
8 changed files with 45 additions and 86 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@
|
|||
required
|
||||
autofocus />
|
||||
|
||||
<input
|
||||
name = "next"
|
||||
type = "hidden"
|
||||
value = "{{ next }}" />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
{% for location in locations %}
|
||||
<li>
|
||||
<a href="{{ request.route_url('shop_location_switch', shop_id=shop.id, location_id=location.id, _query={'next': request.params.get('next', request.url)}) }}">{{ location.name }}</a>
|
||||
{% if location == request.shop_location %}(active){% endif %}
|
||||
{% if request.user in request.shop.owners %}
|
||||
<a href="{{ request.route_url('shop_location_edit', shop_id=shop.id, location_id=location.id) }}" class="button">⚙ edit</a>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -2,41 +2,25 @@
|
|||
{% block content -%}
|
||||
<section class="one-column">
|
||||
<section class="log-in-form well">
|
||||
<h2>Verification Code</h2>
|
||||
<b>Please enter code to log in.<b>
|
||||
<br>
|
||||
<br>
|
||||
<form method="post" action="/verification-challenge">
|
||||
<input
|
||||
name = "email"
|
||||
type = "hidden"
|
||||
id = "email_input"
|
||||
class = "common-text-input"
|
||||
value = "{{ email }}"
|
||||
placeholder = "Your Email Address" />
|
||||
|
||||
<h2>Verification Code</h2>
|
||||
<b>Please enter code to log in.</b>
|
||||
<br>
|
||||
<br>
|
||||
<form method="post" action="/verification-challenge">
|
||||
<input
|
||||
name = "raw-otp"
|
||||
type = "number"
|
||||
id = "raw-otp"
|
||||
class = "common-text-input"
|
||||
tabindex = "1"
|
||||
value = "{% if raw_otp %}{{ raw_otp }}{% endif %}"
|
||||
value = "{% if raw_otp %}{{ raw_otp }}{% endif %}"
|
||||
placeholder = "6 digit challenge verification code"
|
||||
required
|
||||
autofocus />
|
||||
|
||||
<input
|
||||
name = "next"
|
||||
type = "hidden"
|
||||
value = "{{ next }}" />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<input type="submit" name="submit" id="submit" value="verify code" required />
|
||||
|
||||
</form>
|
||||
<br/>
|
||||
<br/>
|
||||
<input type="submit" name="submit" id="submit" value="Verify Code" />
|
||||
</form>
|
||||
<br/>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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", ""),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue