minimost.auth
minimost.auth
Authentication routes, password utilities, and access-control decorator.
This module handles everything related to user identity:
Registration (
/signup) — validates and stores new user credentials, creates the user’s SQLite database, and seeds it with public channel history so a new user is not greeted by an empty chat.Login (
/login) — verifies credentials and establishes a Flask session.Logout (
/logout) — marks the user as offline and clears the session.:func:`login_required` — a decorator applied to every route that requires an authenticated session.
Module-level attributes
- AUTH_DBstr
Absolute path to the shared
auth.dbSQLite file that holds all user credentials.- auth_bpflask.Blueprint
The Flask Blueprint for all authentication routes. Registered in
minimost.create_app().- _USERNAME_REre.Pattern
Compiled regular expression that a username must fully match:
[A-Za-z0-9_\-]{1,32}.
- minimost.auth._lockout_settings() tuple[source]
Return
(max_attempts, lockout_seconds)for account lockout.Reads
max_login_attemptsandlockout_duration_minutesfromsettings.jsonon each call, so changes take effect without a restart. Amax_login_attemptsof0(or any non-positive value) disables lockout entirely. Missing, malformed, or invalid values fall back to the built-in defaults (5attempts,15minutes).
- minimost.auth._lockout_message(minutes) str[source]
Return the user-facing error shown while an account is locked out.
- Parameters:
minutes – Whole minutes remaining in the lockout (rounded up; a minimum of
1is always shown).- Returns:
A human-readable lockout message.
- Return type:
- minimost.auth.hash_password(password: str) str[source]
Hash a plaintext password using PBKDF2.
Delegates to
werkzeug.security.generate_password_hash(), which applies a random salt and uses PBKDF2-HMAC-SHA256 by default. The returned string is suitable for storage inauth.dband can be verified withwerkzeug.security.check_password_hash().- Parameters:
password (str) – The plaintext password to hash.
- Returns:
A Werkzeug-format hash string that encodes the algorithm, iterations, salt, and digest.
- Return type:
Example:
hashed = hash_password("S3cr3t!") assert check_password_hash(hashed, "S3cr3t!")
- minimost.auth._seed_channel_history(new_user: str) None[source]
Copy all public channel message history into a newly created user’s DB.
When a new account is created, this function seeds the new user’s
messagestable with every public-channel message from an existing user’s database. This ensures new users can see the full conversation history from the moment they join, rather than starting with a blank slate.Algorithm:
Pick any existing user from
auth.db(other than new_user).Open that user’s
.dbfile as the source.Select all rows from
messageswherechannel NOT LIKE 'dm:%'(i.e. public channels only — DMs are never copied).Insert those rows verbatim into the new user’s database with
read = 1so they generate no unread-message notifications.
Edge cases:
If no other users exist (first registration), the function returns immediately — there is no history to copy.
If the existing user’s
.dbfile is missing on disk, the function also returns without error.
- Parameters:
new_user (str) – The username of the account being registered.
- Returns:
None
- minimost.auth.login_required(fn)[source]
Decorator that enforces an authenticated Flask session.
Wraps a Flask view function so that unauthenticated requests are redirected to
/logininstead of executing the view. The session key"user"is set by thelogin()route upon successful authentication.This decorator preserves the wrapped function’s name and docstring via
functools.wraps(), which is required for Flask’s endpoint registration to work correctly when multiple routes use the decorator.- Parameters:
fn (callable) – The Flask view function to protect.
- Returns:
A wrapped view function that checks for
session["user"]before calling fn.- Return type:
callable
Example:
@chat_bp.route("/messages/<channel>") @login_required def messages(channel): ...
- minimost.auth.login()[source]
Render the login page.
Routes:
GET /login,GET /login.html- Returns:
A rendered
login.htmltemplate.- Return type:
- minimost.auth.login_post()[source]
Authenticate a user from the login form.
Reads
usernameandpasswordfrom the form, looks up the stored hash inauth.db, and verifies it withwerkzeug.security.check_password_hash().On success:
Sets
session["user"]to the authenticated username.Calls
minimost.common.init_user_db()to ensure the user’s database exists (relevant after a manualusers/directory wipe).Redirects to
/(the main chat interface).
On failure:
Waits 3 seconds before responding to slow down brute-force attempts.
Re-renders
login.htmlwith a generic"Invalid credentials"error (username and password failures are intentionally indistinguishable).
Account lockout: consecutive failed attempts against an existing account are counted in
users.failed_attempts. Once they reachmax_login_attempts(fromsettings.json) the account is locked forlockout_duration_minutesby settingusers.lockout_until; further logins are rejected — without checking the password — until that time passes. A successful login clears the counter. Settingmax_login_attemptsto0disables the feature. See_lockout_settings().Routes:
POST /login,POST /login.html- Returns:
A rendered
login.htmltemplate on failure, or a redirect to/on success.- Return type:
- minimost.auth.logout()[source]
Log the current user out and redirect to the login page.
Sets the user’s presence state to
"offline"inpresence.dbviaminimost.presence.update_presence(), then clears the Flask session and redirects to/login.Route:
GET /logout- Returns:
A redirect response to
/login.- Return type:
- minimost.auth._validate_password(password: str)[source]
Return an error string if password fails the strength rules, else
None.Shared by signup and password reset so the rules stay in one place.
- Parameters:
password – The submitted password.
- Returns:
A human-readable error message, or
Noneif all rules pass.- Return type:
str or None
- minimost.auth._validate_signup(username: str, password: str, confirm: str)[source]
Validate signup form fields and return an error string, or
Noneon success.- Parameters:
username – The submitted username.
password – The submitted password.
confirm – The password confirmation field.
- Returns:
A human-readable error message, or
Noneif all rules pass.- Return type:
str or None
- minimost.auth.forgot_password()[source]
Render the forgot-password information page.
Route:
GET /forgot-password- Returns:
A rendered
forgot_password.htmltemplate.- Return type:
- minimost.auth.signup()[source]
Render the registration page.
Route:
GET /signup- Returns:
A rendered
signup.htmltemplate.- Return type:
- minimost.auth.signup_post()[source]
Create a new user account from the registration form.
Validates the submitted
username,password, andconfirm_passwordfields, creates the account, and logs the user in.Validation rules (enforced server-side):
usernamemust fully match[A-Za-z0-9_\-]{1,32}.passwordmust be at least 8 characters long.passwordmust contain at least one digit (\d).passwordmust contain at least one uppercase ASCII letter.passwordmust contain at least one special character from the set!@#$%^&*()_+-=[]{};\':|,./<>?`~.passwordandconfirm_passwordmust match.
On success:
Inserts
(username, hashed_password)intoauth.db.Calls
minimost.common.init_user_db()to create the user’s DB.Calls
_seed_channel_history()to populate public channel history.Calls
minimost.chat.post_welcome_message()to greet the new user in the first public channel under the MiniMost identity.Sets
session["user"]and redirects to/.
On failure:
Returns
signup.htmlwith a descriptiveerrorvariable.If the username is already taken (
IntegrityError), the error message says so.
Route:
POST /signup- Returns:
A rendered
signup.htmltemplate on validation failure, or a redirect to/on successful registration.- Return type:
- minimost.auth._validate_password_reset(password: str, confirm: str)[source]
Return an error string if the new password fails validation, else None.
- minimost.auth.reset_password_form(token)[source]
Render the password reset form if the token is valid and unexpired.
Route:
GET /reset-password/<token>- Returns:
Rendered
reset_password.htmlwith the form or an error.- Return type:
- minimost.auth.reset_password_post(token)[source]
Process a password reset form submission.
Validates the token is still active, applies password rules, updates the stored hash in
auth.db, and marks the token as used.Route:
POST /reset-password/<token>- Returns:
Rendered
reset_password.html(success or error).- Return type:
Route Summary
Method |
Path |
Handler |
|---|---|---|
GET, POST |
|
|
GET |
|
|
GET, POST |
|