def flaskbb_load_blueprints(app): auth = Blueprint("auth", __name__) def login_rate_limit(): """Dynamically load the rate limiting config from the database.""" # [count] [per|/] [n (optional)] [second|minute|hour|day|month|year] return "{count}/{timeout}minutes".format( count=flaskbb_config["AUTH_REQUESTS"], timeout=flaskbb_config["AUTH_TIMEOUT"]) def login_rate_limit_message(): """Display the amount of time left until the user can access the requested resource again.""" current_limit = getattr(g, 'view_rate_limit', None) if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) reset_time = datetime.utcfromtimestamp(window_stats[0]) timeout = reset_time - datetime.utcnow() return "{timeout}".format(timeout=format_timedelta(timeout)) @auth.before_request def check_rate_limiting(): """Check the the rate limits for each request for this blueprint.""" if not flaskbb_config["AUTH_RATELIMIT_ENABLED"]: return None return limiter.check() @auth.errorhandler(429) def login_rate_limit_error(error): """Register a custom error handler for a 'Too Many Requests' (HTTP CODE 429) error.""" return render_template("errors/too_many_logins.html", timeout=error.description) # Activate rate limiting on the whole blueprint limiter.limit(login_rate_limit, error_message=login_rate_limit_message)(auth) register_view(auth, routes=['/discord'], view_func=DiscordAuthorize.as_view('discord')) register_view( auth, routes=['/discord-callback'], view_func=DiscordAuthorizeCallback.as_view( 'discord-callback', authentication_manager_factory=authentication_manager_factory, registration_service_factory=registration_service_factory)) register_view(auth, routes=['/logout'], view_func=Logout.as_view('logout')) app.register_blueprint(auth, url_prefix=app.config['AUTH_URL_PREFIX'])
) def login_rate_limit_message(): """Display the amount of time left until the user can access the requested resource again.""" current_limit = getattr(g, 'view_rate_limit', None) if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) reset_time = datetime.utcfromtimestamp(window_stats[0]) timeout = reset_time - datetime.utcnow() return "{timeout}".format(timeout=format_timedelta(timeout)) # Activate rate limiting on the whole blueprint limiter.limit(login_rate_limit, error_message=login_rate_limit_message)(auth) class Logout(MethodView): decorators = [limiter.exempt, login_required] def get(self): logout_user() flash(_("Logged out"), "success") return redirect(url_for("forum.index")) class Login(MethodView): decorators = [anonymous_required] def form(self):
def flaskbb_load_blueprints(app): auth = Blueprint("auth", __name__) def login_rate_limit(): """Dynamically load the rate limiting config from the database.""" # [count] [per|/] [n (optional)] [second|minute|hour|day|month|year] return "{count}/{timeout}minutes".format( count=flaskbb_config["AUTH_REQUESTS"], timeout=flaskbb_config["AUTH_TIMEOUT"]) def login_rate_limit_message(): """Display the amount of time left until the user can access the requested resource again.""" current_limit = getattr(g, 'view_rate_limit', None) if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) reset_time = datetime.utcfromtimestamp(window_stats[0]) timeout = reset_time - datetime.utcnow() return "{timeout}".format(timeout=format_timedelta(timeout)) @auth.before_request def check_rate_limiting(): """Check the the rate limits for each request for this blueprint.""" if not flaskbb_config["AUTH_RATELIMIT_ENABLED"]: return None return limiter.check() @auth.errorhandler(429) def login_rate_limit_error(error): """Register a custom error handler for a 'Too Many Requests' (HTTP CODE 429) error.""" return render_template("errors/too_many_logins.html", timeout=error.description) def registration_service_factory(): with app.app_context(): blacklist = [ w.strip() for w in flaskbb_config["AUTH_USERNAME_BLACKLIST"].split(",") ] requirements = registration.UsernameRequirements( min=flaskbb_config["AUTH_USERNAME_MIN_LENGTH"], max=flaskbb_config["AUTH_USERNAME_MAX_LENGTH"], blacklist=blacklist) validators = [ registration.EmailUniquenessValidator(User), registration.UsernameUniquenessValidator(User), registration.UsernameValidator(requirements) ] return RegistrationService(validators, UserRepository(db)) # Activate rate limiting on the whole blueprint limiter.limit(login_rate_limit, error_message=login_rate_limit_message)(auth) register_view(auth, routes=['/logout'], view_func=Logout.as_view('logout')) register_view(auth, routes=['/login'], view_func=Login.as_view('login')) register_view(auth, routes=['/reauth'], view_func=Reauth.as_view('reauth')) register_view( auth, routes=['/register'], view_func=Register.as_view( 'register', registration_service_factory=registration_service_factory)) register_view(auth, routes=['/reset-password'], view_func=ForgotPassword.as_view('forgot_password')) def reset_service_factory(): token_serializer = FlaskBBTokenSerializer(app.config['SECRET_KEY'], expiry=timedelta(hours=1)) verifiers = [EmailMatchesUserToken(User)] return ResetPasswordService(token_serializer, User, token_verifiers=verifiers) register_view(auth, routes=['/reset-password/<token>'], view_func=ResetPassword.as_view( 'reset_password', password_reset_service_factory=reset_service_factory)) register_view( auth, routes=['/activate'], view_func=RequestActivationToken.as_view('request_activation_token')) register_view(auth, routes=['/activate/confirm', '/activate/confirm/<token>'], view_func=ActivateAccount.as_view('activate_account')) app.register_blueprint(auth, url_prefix=app.config['AUTH_URL_PREFIX'])
) def login_rate_limit_message(): """Display the amount of time left until the user can access the requested resource again.""" current_limit = getattr(g, 'view_rate_limit', None) if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) reset_time = datetime.utcfromtimestamp(window_stats[0]) timeout = reset_time - datetime.utcnow() return "{timeout}".format(timeout=format_timedelta(timeout)) # Activate rate limiting on the whole blueprint limiter.limit(login_rate_limit, error_message=login_rate_limit_message)(auth) @auth.route("/login", methods=["GET", "POST"]) def login(): """Logs the user in.""" if current_user is not None and current_user.is_authenticated: return redirect_or_next(url_for("forum.index")) current_limit = getattr(g, 'view_rate_limit', None) login_recaptcha = False if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) stats_diff = flaskbb_config["AUTH_REQUESTS"] - window_stats[1] login_recaptcha = stats_diff >= flaskbb_config["LOGIN_RECAPTCHA"]
def flaskbb_load_blueprints(app): auth = Blueprint("auth", __name__) def login_rate_limit(): """Dynamically load the rate limiting config from the database.""" # [count] [per|/] [n (optional)] [second|minute|hour|day|month|year] return "{count}/{timeout}minutes".format( count=flaskbb_config["AUTH_REQUESTS"], timeout=flaskbb_config["AUTH_TIMEOUT"] ) def login_rate_limit_message(): """Display the amount of time left until the user can access the requested resource again.""" current_limit = getattr(g, 'view_rate_limit', None) if current_limit is not None: window_stats = limiter.limiter.get_window_stats(*current_limit) reset_time = datetime.utcfromtimestamp(window_stats[0]) timeout = reset_time - datetime.utcnow() return "{timeout}".format(timeout=format_timedelta(timeout)) @auth.before_request def check_rate_limiting(): """Check the the rate limits for each request for this blueprint.""" if not flaskbb_config["AUTH_RATELIMIT_ENABLED"]: return None return limiter.check() @auth.errorhandler(429) def login_rate_limit_error(error): """Register a custom error handler for a 'Too Many Requests' (HTTP CODE 429) error.""" return render_template( "errors/too_many_logins.html", timeout=error.description ) # Activate rate limiting on the whole blueprint limiter.limit( login_rate_limit, error_message=login_rate_limit_message )(auth) register_view(auth, routes=['/logout'], view_func=Logout.as_view('logout')) register_view( auth, routes=['/login'], view_func=Login.as_view( 'login', authentication_manager_factory=authentication_manager_factory ) ) register_view( auth, routes=['/reauth'], view_func=Reauth.as_view( 'reauth', reauthentication_factory=reauthentication_manager_factory ) ) register_view( auth, routes=['/register'], view_func=Register.as_view( 'register', registration_service_factory=registration_service_factory ) ) register_view( auth, routes=['/reset-password'], view_func=ForgotPassword.as_view( 'forgot_password', password_reset_service_factory=reset_service_factory ) ) register_view( auth, routes=['/reset-password/<token>'], view_func=ResetPassword.as_view( 'reset_password', password_reset_service_factory=reset_service_factory ) ) register_view( auth, routes=['/activate'], view_func=RequestActivationToken.as_view( 'request_activation_token', account_activator_factory=account_activator_factory ) ) register_view( auth, routes=['/activate/confirm'], view_func=ActivateAccount.as_view( 'activate_account', account_activator_factory=account_activator_factory ) ) register_view( auth, routes=['/activate/confirm/<token>'], view_func=AutoActivateAccount.as_view( 'autoactivate_account', account_activator_factory=account_activator_factory ) ) app.register_blueprint(auth, url_prefix=app.config['AUTH_URL_PREFIX'])