def reset_password(self, action_token, signed_data): """Reset the user password. It was triggered by LOST-PASSWORD """ try: action = "reset-password" user = get_user_by_action_token(action, action_token) if not user or not user.signed_data_match(signed_data, action): raise mocha_exc.AppError("Verification Invalid!") if request.method == "POST": password = request.form.get("password", "").strip() password_confirm = request.form.get("password_confirm", "").strip() if not password or password != password_confirm: raise exceptions.AuthError( "Password is missing or passwords don't match") user.change_password(password) user.set_email_verified(True) session_set_require_password_change(False) flash_success("Password updated successfully!") return redirect(__options__.get("login_view") or self.login) return {"action_token": action_token, "signed_data": signed_data} except (mocha_exc.AppError, exceptions.AuthError) as ex: flash_error(str(ex)) except Exception as e: logging.exception(e) flash_error("Unable to reset password") return redirect(self.login)
def create(self): try: first_name = request.form.get("first_name", "").strip() last_name = request.form.get("last_name", "").strip() email = request.form.get("email", "").strip() password = request.form.get("password", "").strip() password_confirm = request.form.get("password_confirm", "").strip() user_role = request.form.get("user_role") role = models.AuthUserRole.get(user_role) if not role: raise exceptions.AuthError("Invalid ROLE selected") if not first_name: raise mocha_exc.AppError("First Name is required") elif not password or password != password_confirm: raise mocha_exc.AppError("Passwords don't match") user = create_user(username=email, password=password, first_name=first_name, last_name=last_name, login_method="email", role=role.name) if user: flash_success("New account created successfully!") return redirect(self.info, id=user.id) else: raise exceptions.AuthError("Account couldn't be created") except exceptions.AuthError as ae: flash_error(ae.message) return redirect(self.index)
def setup_login(self): return user_login = current_user.user_login("email") if user_login: return redirect(self.account_settings) if request.IS_POST: try: email = request.form.get("email") password = request.form.get("password") password2 = request.form.get("password2") if not password.strip() or password.strip() != password2.strip(): raise exceptions.AuthError("Passwords don't match") else: new_login = models.AuthUserLogin.new(login_method="email", user_id=current_user.id, email=email, password=password.strip()) if verify_email: send_registration_welcome_email(new_login.user) flash_success( "A welcome email containing a confirmation link has been sent to your email") return redirect(self.account_settings) except exceptions.AuthError as ex: flash_error(ex.message) return redirect(self.setup_login) except Exception as e: logging.exception(e) flash_error("Unable to setup login") return redirect(self)
def change_email(self): """Update the login email""" try: self._assert_current_password() email = request.form.get("email") current_user.change_email(email) flash_success(_("Email changed successfully!")) except exceptions.AuthError as ex: flash_error(str(ex)) except Exception as e: logging.exception(e) flash_error(_("Unable to change email")) redirect_url = request.form.get("redirect") or self.account_settings return redirect(redirect_url)
def post(self): recipients = request.form.get("recipients") success_message = request.form.get("success_message") if not recipients or not success_message: flash_error("Missing 'recipients' or 'success message'") else: data = { "recipients": recipients, "success_message": success_message } app_data.set(APP_DATA_KEY, data) flash_success("Contact Us Settings saved") return redirect(self.index)
def change_password(self): """Change password """ try: self._assert_current_password() password = request.form.get("password", "").strip() password_confirm = request.form.get("password_confirm", "").strip() if password != password_confirm: raise exceptions.AuthError("Passwords don't match") current_user.change_password(password) flash_success(_("Your password updated successfully!")) except exceptions.AuthError as ex: flash_error(str(ex)) except Exception as e: logging.exception(e) flash_error(_("Unable to update password")) redirect_url = request.form.get("redirect") or self.account_settings return redirect(redirect_url)
def lost_password(self): if not __options__.get("allow_login"): abort(403, "Login is not allowed. Contact admin if it's a mistake") page_attr("Lost Password") if request.method == "POST": username = request.form.get("username") user = models.AuthUser.get_by_username(username) if user: user = UserModel(user) user.send_password_reset(view_class=self) flash_success("A new password has been sent to '%s'" % user.email) return redirect(self.login) else: flash_error("Invalid login") return redirect(self.lost_password)
def verify_email(self, action_token, signed_data): """ Verify email account, in which a link was sent to """ try: action = "verify-email" user = get_user_by_action_token(action, action_token) if not user or not user.signed_data_match(signed_data, action): raise mocha_exc.AppError("Verification Invalid!") else: user.set_email_verified(True) flash_success("Account verified. You can now login") username = user.username if user.login_method == "email": username = user.email return redirect(self.login, username=username) except Exception as e: logging.exception(e) flash_error("Verification Failed!") return redirect(self.login)
def update_info(self): """Update basic account info""" try: first_name = request.form.get("first_name", "").strip() last_name = request.form.get("last_name", "").strip() delete_photo = request.form.get("delete_photo", "").strip() file = request.files.get("file") kwargs = { "first_name": first_name, "last_name": last_name } if file: prefix = __options__.get("profile_image_dir", "profile.imgs").replace("/", "") prefix += "/" profile_image = upload_file(None, file, name=utils.guid(), prefix=prefix, public=True, extensions=[ "jpg", "jpeg", "png", "gif"]) kwargs["profile_image"] = profile_image if delete_photo == "1": if current_user.profile_image is not None: delete_file(current_user.profile_image) kwargs["profile_image"] = None if kwargs: current_user.update_info(**kwargs) flash_success(_("Info updated successfully!")) except exceptions.AuthError as ex: flash_error(str(ex)) except Exception as e: logging.exception(e) flash_error(_("Unable to update info")) redirect_url = request.form.get("redirect") or self.account_settings return redirect(redirect_url)
def login(self): if not __options__.get("allow_login"): abort(403, "Login is not allowed. Contact admin if it's a mistake") if request.method == "POST": username = request.form.get("username", "").strip() password = request.form.get("password", "").strip() try: if not username or not password: raise mocha_exc.AppError("Email/Username or Password is empty") user = authenticate(username=username, password=password) if not user: raise mocha_exc.AppError("Email or Password is invalid") create_session(user) # if user.require_password_change is True: # flash_info("Password change is required") # session_set_require_password_change(True) # return redirect(views.auth.Account.account_settings, edit_password=1) return redirect(request.form.get("next") or __options__.get("login_view")) except exceptions.VerifyEmailError as ve: return redirect(self.login, username=username, v="1") except (mocha_exc.AppError, exceptions.AuthError) as ae: flash_error(str(ae)) except Exception as e: logging.exception(e) flash_error("Unable to login") return redirect(self.login, next=request.form.get("next")) page_attr("Login") return { "username": request.args.get("username"), "login_url_next": request.args.get("next", ""), "allow_registration": __options__.get("allow_registration"), "show_verification_message": True if request.args.get("v") == "1" else False }
def request_email_verification(self): """""" if not __options__.get("verify_email"): return redirect(self.login) if request.method == "POST": email = request.form.get("email") if email and utils.is_email_valid(email): user = models.AuthUser.get_by_email(email) if user: if not user.email_verified: send_email_verification_email(user, view_class=self) flash_success( "A verification email has been sent to %s" % email) else: flash_success("Your account is already verified") return redirect(self.login, email=email) flash_error("Invalid account") return redirect(self.request_email_verification, email=email) page_attr("Request Email Verification") return { "email": request.args.get("email"), }
def page(self): recipients = app_data.get(APP_DATA_KEY, "recipients") \ or __options__.get("recipients") \ or config("CONTACT_EMAIL") if not recipients: abort(500, "ContactPage missing email recipient") success_message = app_data.get(APP_DATA_KEY, "success_message", __options__.get("success_message")) return_to = __options__.get("return_to", None) if return_to: if "/" not in return_to: return_to = url_for(return_to) else: return_to = url_for(self) if request.method == "POST": email = request.form.get("email") subject = request.form.get("subject") message = request.form.get("message") name = request.form.get("name") try: if recaptcha.verify(): if not email or not subject or not message: raise exceptions.AppError("All fields are required") elif not utils.is_email_valid(email): raise exceptions.AppError("Invalid email address") else: try: send_mail(to=recipients, reply_to=email, mail_from=email, mail_subject=subject, mail_message=message, mail_name=name, template=__options__.get("template", "contact-us.txt") ) flash_data("ContactPage:EmailSent") except Exception as ex: logging.exception(ex) raise exceptions.AppError("Unable to send email") else: raise exceptions.AppError("Security code is invalid") except exceptions.AppError as e: flash_error(e.message) return redirect(self) title = __options__.get("title", _("Contact Us")) page_attr(title) fd = get_flash_data() return { "title": title, "email_sent": True if fd and "ContactPage:EmailSent" in fd else False, "success_message": success_message, "return_to": return_to }
def roles(self): """ Only admin and super admin can add/remove roles RESTRICTED ROLES CAN'T BE CHANGED """ roles_max_range = 11 if request.IS_POST: try: id = request.form.get("id") name = request.form.get("name") level = request.form.get("level") action = request.form.get("action") if name and level: level = int(level) name = name.upper() _levels = [r[0] for r in models.AuthUserRole.ROLES] _names = [r[1] for r in models.AuthUserRole.ROLES] if level in _levels or name in _names: raise exceptions.AuthError( "Can't modify PRIMARY Roles - name: %s, level: %s " % ( name, level)) else: if id: role = models.AuthUserRole.get(id) if role: if action == "delete": role.update(level=0) # Free the role role.delete() flash_success( "Role '%s' deleted successfully!" % role.name) elif action == "update": if role.level != level and models.AuthUserRole.get_by_level( level): raise exceptions.AuthError( "Role Level '%s' exists already" % level) elif role.name != models.AuthUserRole.slug_name( name) and models.AuthUserRole.get_by_name( name): raise exceptions.AuthError( "Role Name '%s' exists already" % name) else: role.update(name=name, level=level) flash_success( "Role '%s (%s)' updated successfully" % ( name, level)) else: raise exceptions.AuthError("Role doesn't exist") else: if models.AuthUserRole.get_by_level(level): raise exceptions.AuthError( "New Role Level '%s' exists already" % level) elif models.AuthUserRole.get_by_name(name): raise exceptions.AuthError( "New Role Name '%s' exists already" % name) else: models.AuthUserRole.new(name=name, level=level) flash_success( "New Role '%s (%s)' addedd successfully" % ( name, level)) except exceptions.AuthError as ex: flash_error("%s" % ex.message) return redirect(self.roles) page_attr("User Roles") roles = models.AuthUserRole.query().order_by( models.AuthUserRole.level.desc()) allocated_levels = [r.level for r in roles] # levels_options = [(l, l) for l in range(1, roles_max_range) if l not in allocated_levels] levels_options = [(l, l) for l in range(1, roles_max_range)] return { "roles": roles, "levels_options": levels_options }
def action(self): id = request.form.get("id") action = request.form.get("action") try: user = models.AuthUser.get(id, include_deleted=True) if not user: abort(404, "User doesn't exist or has been deleted!") if current_user.role.level < user.role.level: abort(403, "Not enough power level to update this user info") user = UserModel(user) if current_user.id != user.id: if action == "activate": user.change_status("active") flash_success("User has been ACTIVATED") elif action == "deactivate": user.change_status("suspended") flash_success("User is now SUSPENDED") elif action == "delete": user.change_status("deleted") user.delete() flash_success("User has been DELETED") elif action == "undelete": user.change_status("suspended") user.delete(False) flash_success("User is now RESTORED / Use is now SUSPENDED") if action == "info": first_name = request.form.get("first_name") last_name = request.form.get("last_name") data = {} if first_name: data["first_name"] = first_name if last_name: data["last_name"] = last_name if current_user.id != user.id: user_role = request.form.get("user_role") _role = models.AuthUserRole.get(user_role) if not _role: raise exceptions.AuthError("Invalid ROLE selected") data["role"] = _role if data: user.update_info(ACTIONS["UPDATE"], **data) flash_success("User info updated successfully!") elif action == "change-username": username = request.form.get("username") user.change_username(username) flash_success("Username changed successfully!") elif action == "change-email": email = request.form.get("email") user.change_email(email) flash_success("Email changed successfully!") elif action == "change-password": password = request.form.get("password", "").strip() password_confirm = request.form.get("password_confirm", "").strip() if password != password_confirm: raise exceptions.AuthError("Invalid passwords") user.change_password(password) flash_success("Password changed successfully!") elif action == "email-reset-password": user.send_password_reset() flash_success("Password reset was sent to email") elif action == "email-account-verification": user.send_verification_email() flash_success("Email verification was sent") elif action == "reset-secret-key": user.reset_secret_key() flash_success("The account's secret key has been changed") elif action == "delete-profile-image": if user.profile_image is not None: delete_file(user.profile_image) user.update_info(profile_image=None, _action=ACTIONS["PROFILE_IMAGE"]) flash_success("Profile Image deleted successfully!") except exceptions.AuthError as ae: flash_error(ae.message) return redirect(self.info, id=id)
def oauth_connect(self, provider, action): """ This endpoint doesn't check if user is logged in, because it has two functions 1. If the user is not logged in, it will try to signup the user - if the social info exist, it will login - not, it will create a new account and proceed 2. If user is logged in, it will try to create a social login entry with the current user **** This methods doesn't save the user token, it only retrieves the ID to login or ID, name, email if signing up :param provider: :param action: connect|authorized| - connect: to connect to the endpoint - authorized, when coming back """ valid_actions = ["connect", "authorized", "test"] _redirect = views.auth.Account.account_settings if is_authenticated() else self.login if action not in valid_actions \ or "oauth" not in __options__.get("registration_methods") \ or not __options__.get("allow_registration") \ or not hasattr(oauth, provider): return redirect(_redirect) client = getattr(oauth, provider) params = client.__params__ me_args = params.get("me") user_id = params.get("user_id") oauth_user_id = None oauth_name = None oauth_email = None if action == "test": session_data = { "provider": "ensure", "user_id": "1234", "name": "Mardix", "email": "*****@*****.**", } set_oauth_session(session_data) return redirect(url_for(self.register, oauth=1)) if action == "connect": _next = request.args.get('next') authorized_url = url_for(self, provider=provider, action="authorized", next=_next or request.referrer or None, _external=True) return client.authorize(callback=authorized_url) elif action == "authorized": resp = client.authorized_response() if resp is None: pass elif isinstance(resp, OAuthException): flash_error("Access Denied") else: if not me_args: oauth_user_id = resp.get(user_id) else: me = client.get(me_args) if action == "authorized" and oauth_user_id: if is_authenticated(): try: # Add federated login to current_user current_user.add_federated_login(provider=provider, federated_id=oauth_user_id) flash_success( "You can now login with your %s account" % provider.upper()) except Exception as e: logging.exception(e) return redirect(views.auth.Account.account_settings) # User not logged in else: # Existing user user = with_federation(provider, oauth_user_id) if user: create_session(user) return redirect(request.args.get("next") or __options__.get( "login_view")) # New User else: session_data = { "provider": provider, "user_id": oauth_user_id, "name": oauth_name, "email": oauth_email, } set_oauth_session(session_data) else: return redirect(_redirect) return { "action": action, "provider": provider, "authorized_url": "" } return redirect(_redirect)
def register(self): """ Registration """ if not __options__.get("allow_registration"): abort(403, "Registration is not allowed. Contact admin if it's a mistake") page_attr("Register") if request.method == "POST": try: if not recaptcha.verify(): raise mocha_exc.AppError("Invalid Security code") email = request.form.get("email", "").strip() username = request.form.get("username", "").strip() password = request.form.get("password", "").strip() password_confirm = request.form.get("password_confirm", "").strip() first_name = request.form.get("first_name", "").strip() last_name = request.form.get("last_name", "").strip() with_oauth = request.form.get("with_oauth") == "1" oauth_provider = request.form.get("oauth_provider") oauth_user_id = request.form.get("oauth_user_id") login_method = None # Require username and email if __options__.get("registration_username"): if "@" in username: raise exceptions.AuthError(_("Username can't be an email")) if not utils.is_email_valid(email): raise exceptions.AuthError(_("Invalid email address")) login_method = "username" # Require only email. Email will be used as username and email elif __options__.get("registration_email"): if not utils.is_email_valid(username): raise exceptions.AuthError(_("Invalid email address")) email = username login_method = "email" if not first_name: raise mocha_exc.AppError( _("First Name or Name is required")) elif not password or password != password_confirm: raise mocha_exc.AppError(_("Passwords don't match")) if not login_method: raise exceptions.AuthError(_("Registration is disabled")) user = create_user(username=username, password=password, email=email, first_name=first_name, last_name=last_name, login_method=login_method) # WITH OAUTH, we can straight up login user if with_oauth and oauth_provider and oauth_user_id: user.add_federation(oauth_provider, oauth_user_id) create_session(user) return redirect(request.form.get( "next") or views.auth.Account.account_settings) if __options__.get("require_email_verification"): user.send_welcome_email(view_class=self) flash_success(_("Please check your email. We've sent you a message")) return redirect( request.form.get("next") or __options__.get("login_view")) except (mocha_exc.AppError, exceptions.AuthError) as ex: flash_error(str(ex)) except Exception as e: logging.exception(e) flash_error("Unable to register") return redirect(self.register, next=request.form.get("next")) return { "reg_email": __options__.get("registration_email"), "reg_username": __options__.get("registration_username"), "reg_social": __options__.get("registration_social"), "reg_full_name": __options__.get("registration_full_name"), "login_url_next": request.args.get("next", ""), "with_oauth": has_oauth_request(), "oauth_provider": get_oauth_session().get("provider"), "oauth_user_id": get_oauth_session().get("user_id"), "email": get_oauth_session().get("email") or "", "name": get_oauth_session().get("name") or "", }