def github_callback(): # user clicks on cancel if "error" in request.args: flash("Please use another sign in method then", "warning") return redirect("/") github = OAuth2Session( GITHUB_CLIENT_ID, state=session["oauth_state"], scope=["user:email"], redirect_uri=_redirect_uri, ) token = github.fetch_token( _token_url, client_secret=GITHUB_CLIENT_SECRET, authorization_response=request.url, ) # a dict with "name", "login" github_user_data = github.get("https://api.github.com/user").json() LOG.d("user login with github %s", github_user_data) # return list of emails # { # 'email': '*****@*****.**', # 'primary': False, # 'verified': True, # 'visibility': None # } emails = github.get("https://api.github.com/user/emails").json() # only take the primary email email = None for e in emails: if e.get("verified") and e.get("primary"): email = e.get("email") break if not email: raise Exception("cannot get email for github user") user = User.get_by(email=email) # create user if not user: LOG.d("create github user") user = User.create( email=email, name=github_user_data.get("name") or "", activated=True ) db.session.commit() login_user(user) email_utils.send_welcome_email(user.email, user.name) flash(f"Welcome to SimpleLogin {user.name}!", "success") # The activation link contains the original page, for ex authorize page next_url = request.args.get("next") if request.args else None return after_login(user, next_url)
def login(): if current_user.is_authenticated: LOG.d("user is already authenticated, redirect to dashboard") return redirect(url_for("dashboard.index")) form = LoginForm(request.form) next_url = request.args.get("next") show_resend_activation = False if form.validate_on_submit(): user = User.filter_by(email=form.email.data).first() if not user: flash("Email or password incorrect", "error") elif not user.check_password(form.password.data): flash("Email or password incorrect", "error") elif not user.activated: show_resend_activation = True flash( "Please check your inbox for the activation email. You can also have this email re-sent", "error", ) else: return after_login(user, next_url) return render_template( "auth/login.html", form=form, next_url=next_url, show_resend_activation=show_resend_activation, )
def reset_password(): form = ResetPasswordForm(request.form) reset_password_code_str = request.args.get("code") reset_password_code: ResetPasswordCode = ResetPasswordCode.get_by( code=reset_password_code_str) if not reset_password_code: # Trigger rate limiter g.deduct_limit = True error = ("The reset password link can be used only once. " "Please request a new link to reset password.") return render_template("auth/reset_password.html", form=form, error=error) if reset_password_code.is_expired(): error = "The link has been already expired. Please make a new request of the reset password link" return render_template("auth/reset_password.html", form=form, error=error) if form.validate_on_submit(): user = reset_password_code.user new_password = form.password.data # avoid user reusing the old password if user.check_password(new_password): error = "You cannot reuse the same password" return render_template("auth/reset_password.html", form=form, error=error) user.set_password(new_password) flash("Your new password has been set", "success") # this can be served to activate user too user.activated = True # remove the reset password code ResetPasswordCode.delete(reset_password_code.id) # change the alternative_id to log user out on other browsers user.alternative_id = str(uuid.uuid4()) Session.commit() # do not use login_user(user) here # to make sure user needs to go through MFA if enabled return after_login(user, url_for("dashboard.index")) return render_template("auth/reset_password.html", form=form)
def login(): next_url = request.args.get("next") if current_user.is_authenticated: if next_url: LOG.debug("user is already authenticated, redirect to %s", next_url) return redirect(next_url) else: LOG.d("user is already authenticated, redirect to dashboard") return redirect(url_for("dashboard.index")) form = LoginForm(request.form) show_resend_activation = False if form.validate_on_submit(): user = User.filter_by(email=sanitize_email(form.email.data)).first() if not user or not user.check_password(form.password.data): # Trigger rate limiter g.deduct_limit = True form.password.data = None flash("Email or password incorrect", "error") elif user.disabled: flash( "Your account is disabled. Please contact SimpleLogin team to re-enable your account.", "error", ) elif not user.activated: show_resend_activation = True flash( "Please check your inbox for the activation email. You can also have this email re-sent", "error", ) else: return after_login(user, next_url) return render_template( "auth/login.html", form=form, next_url=next_url, show_resend_activation=show_resend_activation, )
def github_callback(): # user clicks on cancel if "error" in request.args: flash("Please use another sign in method then", "warning") return redirect("/") github = OAuth2Session( GITHUB_CLIENT_ID, state=session["oauth_state"], scope=["user:email"], redirect_uri=_redirect_uri, ) github.fetch_token( _token_url, client_secret=GITHUB_CLIENT_SECRET, authorization_response=request.url, ) # a dict with "name", "login" github_user_data = github.get("https://api.github.com/user").json() # return list of emails # { # 'email': '*****@*****.**', # 'primary': False, # 'verified': True, # 'visibility': None # } emails = github.get("https://api.github.com/user/emails").json() # only take the primary email email = None for e in emails: if e.get("verified") and e.get("primary"): email = e.get("email") break if not email: LOG.e(f"cannot get email for github user {github_user_data} {emails}") flash( "Cannot get a valid email from Github, please another way to login/sign up", "error", ) return redirect(url_for("auth.login")) email = sanitize_email(email) user = User.get_by(email=email) if not user: flash( "Sorry you cannot sign up via Github, please use email/password sign-up instead", "error", ) return redirect(url_for("auth.register")) if not SocialAuth.get_by(user_id=user.id, social="github"): SocialAuth.create(user_id=user.id, social="github") Session.commit() # The activation link contains the original page, for ex authorize page next_url = request.args.get("next") if request.args else None return after_login(user, next_url)
def github_callback(): # user clicks on cancel if "error" in request.args: flash("Please use another sign in method then", "warning") return redirect("/") github = OAuth2Session( GITHUB_CLIENT_ID, state=session["oauth_state"], scope=["user:email"], redirect_uri=_redirect_uri, ) token = github.fetch_token( _token_url, client_secret=GITHUB_CLIENT_SECRET, authorization_response=request.url, ) # a dict with "name", "login" github_user_data = github.get("https://api.github.com/user").json() # return list of emails # { # 'email': '*****@*****.**', # 'primary': False, # 'verified': True, # 'visibility': None # } emails = github.get("https://api.github.com/user/emails").json() # only take the primary email email = None for e in emails: if e.get("verified") and e.get("primary"): email = e.get("email") break if not email: LOG.error( f"cannot get email for github user {github_user_data} {emails}") flash( "Cannot get a valid email from Github, please another way to login/sign up", "error", ) return redirect(url_for("auth.login")) email = email.lower() user = User.get_by(email=email) # create user if not user: if DISABLE_REGISTRATION: flash("Registration is closed", "error") return redirect(url_for("auth.login")) if not can_be_used_as_personal_email(email) or email_already_used( email): flash(f"You cannot use {email} as your personal inbox.", "error") return redirect(url_for("auth.login")) LOG.d("create github user") user = User.create(email=email.lower(), name=github_user_data.get("name") or "", activated=True) db.session.commit() login_user(user) email_utils.send_welcome_email(user) flash(f"Welcome to SimpleLogin {user.name}!", "success") if not SocialAuth.get_by(user_id=user.id, social="github"): SocialAuth.create(user_id=user.id, social="github") db.session.commit() # The activation link contains the original page, for ex authorize page next_url = request.args.get("next") if request.args else None return after_login(user, next_url)