From 9a87ef95621ae8d30c2883be8d05fcafceceb3f7 Mon Sep 17 00:00:00 2001 From: Florian Heinz Date: Mon, 13 Apr 2026 10:06:56 +0200 Subject: [PATCH] fix: disable public signup and restore local login flow --- README.md | 12 ++++++++++++ app/cli.py | 19 +++++++++++++++++-- app/forms.py | 15 ++++++++------- app/routes/auth.py | 10 ++++++++-- app/static/images/pwa-badge.png | Bin 364 -> 358 bytes app/static/images/pwa-icon-512.png | Bin 9418 -> 9421 bytes app/static/service-worker.js | 24 ++++++++++++++++++++---- app/templates/auth/login.html | 7 +++++-- 8 files changed, 70 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f2b3114..11274f9 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Putzliga ist eine moderne, leichte Haushaltsaufgaben-Web-App mit spielerischem C - Echte Web-Push-Architektur mit gespeicherten `PushSubscription`s - CLI-Kommandos für Archivierung und serverseitig triggerbare Benachrichtigungen - Cloudron-/Container-tauglicher Start mit `start.sh`, `Dockerfile` und `CloudronManifest.json` +- Keine freie Registrierung nach dem ersten Nutzer; weitere Nutzer lassen sich kontrolliert per CLI anlegen ## Projektstruktur @@ -108,6 +109,17 @@ Demo-Logins: - `anna@putzliga.local` / `putzliga123` - `ben@putzliga.local` / `putzliga123` +## Nutzer anlegen + +Freie Registrierung ist deaktiviert, sobald mindestens ein Nutzer existiert. + +- Wenn die Datenbank noch leer ist, darf genau der erste Nutzer über `/register` angelegt werden. +- Weitere Nutzer legst du kontrolliert per CLI an: + +```bash +flask --app app.py create-user +``` + ### 5. Entwicklungsserver starten ```bash diff --git a/app/cli.py b/app/cli.py index b6b4897..0c2bcea 100644 --- a/app/cli.py +++ b/app/cli.py @@ -3,7 +3,7 @@ from __future__ import annotations import click from .extensions import db -from .models import BadgeDefinition +from .models import BadgeDefinition, User from .services.monthly import archive_months_missing_up_to_previous from .services.notifications import send_due_notifications, send_monthly_winner_notifications @@ -54,6 +54,22 @@ def register_cli(app) -> None: seed_badges() click.echo("Datenbank und Standard-Badges sind bereit.") + @app.cli.command("create-user") + @click.option("--name", prompt=True, help="Anzeigename") + @click.option("--email", prompt=True, help="E-Mail") + @click.option("--password", prompt=True, hide_input=True, confirmation_prompt=True, help="Passwort") + def create_user_command(name: str, email: str, password: str): + existing = User.query.filter_by(email=email.lower().strip()).first() + if existing: + click.echo("Es existiert bereits ein Nutzer mit dieser E-Mail.") + raise SystemExit(1) + + user = User(name=name.strip(), email=email.lower().strip()) + user.set_password(password) + db.session.add(user) + db.session.commit() + click.echo(f"Nutzer {user.email} wurde angelegt.") + @app.cli.command("archive-months") def archive_months_command(): archive_months_missing_up_to_previous() @@ -68,4 +84,3 @@ def register_cli(app) -> None: def notify_monthly_winner_command(): result = send_monthly_winner_notifications() click.echo(f"Winner-Push: sent={result.sent} skipped={result.skipped} failed={result.failed}") - diff --git a/app/forms.py b/app/forms.py index 396bef1..5ee8cfc 100644 --- a/app/forms.py +++ b/app/forms.py @@ -5,21 +5,23 @@ from flask_wtf.file import FileAllowed, FileField from wtforms import ( BooleanField, DateField, - EmailField, IntegerField, PasswordField, - SelectField, StringField, + SelectField, SubmitField, TextAreaField, ) -from wtforms.validators import DataRequired, Email, EqualTo, Length, NumberRange, Optional, ValidationError +from wtforms.validators import DataRequired, EqualTo, Length, NumberRange, Optional, Regexp, ValidationError from .models import User +EMAIL_LIKE = Regexp(r"^[^@\s]+@[^@\s]+\.[^@\s]+$", message="Bitte gib eine gültige E-Mail-Adresse ein.") + + class LoginForm(FlaskForm): - email = EmailField("E-Mail", validators=[DataRequired(), Email(), Length(max=255)]) + email = StringField("E-Mail", validators=[DataRequired(), EMAIL_LIKE, Length(max=255)]) password = PasswordField("Passwort", validators=[DataRequired(), Length(min=6, max=128)]) remember_me = BooleanField("Angemeldet bleiben") submit = SubmitField("Einloggen") @@ -27,7 +29,7 @@ class LoginForm(FlaskForm): class RegisterForm(FlaskForm): name = StringField("Name", validators=[DataRequired(), Length(min=2, max=120)]) - email = EmailField("E-Mail", validators=[DataRequired(), Email(), Length(max=255)]) + email = StringField("E-Mail", validators=[DataRequired(), EMAIL_LIKE, Length(max=255)]) password = PasswordField("Passwort", validators=[DataRequired(), Length(min=6, max=128)]) password_confirm = PasswordField( "Passwort wiederholen", @@ -76,7 +78,7 @@ class TaskForm(FlaskForm): class SettingsProfileForm(FlaskForm): name = StringField("Name", validators=[DataRequired(), Length(min=2, max=120)]) - email = EmailField("E-Mail", validators=[DataRequired(), Email(), Length(max=255)]) + email = StringField("E-Mail", validators=[DataRequired(), EMAIL_LIKE, Length(max=255)]) password = PasswordField("Neues Passwort", validators=[Optional(), Length(min=6, max=128)]) avatar = FileField( "Avatar", @@ -96,4 +98,3 @@ class SettingsProfileForm(FlaskForm): return if User.query.filter_by(email=value).first(): raise ValidationError("Diese E-Mail-Adresse wird bereits verwendet.") - diff --git a/app/routes/auth.py b/app/routes/auth.py index d4786ed..808b01c 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -11,6 +11,10 @@ from ..models import User bp = Blueprint("auth", __name__) +def registration_open() -> bool: + return User.query.count() == 0 + + @bp.route("/login", methods=["GET", "POST"]) def login(): if current_user.is_authenticated: @@ -24,13 +28,16 @@ def login(): flash(f"Willkommen zurück, {user.name}.", "success") return redirect(url_for("tasks.my_tasks")) flash("Die Kombination aus E-Mail und Passwort passt leider nicht.", "error") - return render_template("auth/login.html", form=form) + return render_template("auth/login.html", form=form, registration_open=registration_open()) @bp.route("/register", methods=["GET", "POST"]) def register(): if current_user.is_authenticated: return redirect(url_for("tasks.my_tasks")) + if not registration_open(): + flash("Freie Registrierung ist deaktiviert.", "info") + return redirect(url_for("auth.login")) form = RegisterForm() if form.validate_on_submit(): @@ -50,4 +57,3 @@ def logout(): logout_user() flash("Du bist jetzt abgemeldet.", "info") return redirect(url_for("auth.login")) - diff --git a/app/static/images/pwa-badge.png b/app/static/images/pwa-badge.png index e2b7ae313dd0c400efc51b21388d5104d00733ca..17961a863b178d42877d30b3d83d7e0b2b940234 100644 GIT binary patch delta 331 zcmV-R0kr{5pt=(br&fia!dWWB3se6T-KJm>9ne!sPhn z5jMmxiLfbrIf%{i;|Ssh5kwCo2p$9wJBT215JB7^f~a8xL4Sh)Vulff3<8K4L=Z2G zARK_b0HTEv1PcO)6-E#Wz+M26!UzHZ0ANA@;)D@|0RX@N0AK*@0}v&QAP4{e27n)8 z<8LSc0|0;l0Kj-G>7l#<0Kj-X(aX68fR8kcPn3M9XMCm#z*tvcVTZA<#?mHZWtqi& z#_CGTTaER_mPB_OE9_n3AU*__`3MieWp3g_aH*%;R6z*uMr|0PcYrv~eGIiPgQ$4{ dM-}Ji^8u<Ae3bwI002ovPDHLkV1h1yhEo6l delta 337 zcmV-X0j~b$0_*~iB!4qWL_t(|+U?!B4MIT>M8Qpl$OxYxz{dk)dyZPE6L@8S^sjRq z$7y&T&)55Vs$7Wt@6@~;97w_FFp7m=2T?Kl8jMcyM)GB2tona3m{S$K_CDCECe7<7(o~S01N;C1F#Q3lrVxI000;OKg8y5 zC;$ThzyJU+mnB`4Hvj<4?TK#AH2@ycFpnsCP|rN33c$RszzaLf>uUA@KnTYNPyhfz zI6i~|@gWq54@#jxd;kRiAcW&XC=eflkNF7iJ7N&T--2*D9^pak4&N2wOh2N7*d0EN jq4s4EH80?(;{1F*s#LACes{R`00000NkvXXu0mjf?*@SB diff --git a/app/static/images/pwa-icon-512.png b/app/static/images/pwa-icon-512.png index dc832a8ad12d9d6e704826e96e40a9bf95ea6403..a5e29fdde0655c1fe4a565930f588084e97899ff 100644 GIT binary patch literal 9421 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 jqRMi7CCrs#R^S^#}VOVYd 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 diff --git a/app/static/service-worker.js b/app/static/service-worker.js index e084201..142e92c 100644 --- a/app/static/service-worker.js +++ b/app/static/service-worker.js @@ -1,6 +1,5 @@ -const CACHE_NAME = "putzliga-shell-v1"; +const CACHE_NAME = "putzliga-shell-v2"; const ASSETS = [ - "/my-tasks", "/static/css/style.css", "/static/js/app.js", "/static/images/logo.svg", @@ -24,6 +23,24 @@ self.addEventListener("activate", (event) => { self.addEventListener("fetch", (event) => { if (event.request.method !== "GET") return; + const url = new URL(event.request.url); + const isStaticAsset = + url.origin === self.location.origin && + ( + url.pathname.startsWith("/static/") || + url.pathname === "/manifest.json" || + url.pathname === "/service-worker.js" + ); + + if (event.request.mode === "navigate") { + event.respondWith(fetch(event.request)); + return; + } + + if (!isStaticAsset) { + return; + } + event.respondWith( caches.match(event.request).then((cached) => { if (cached) return cached; @@ -32,8 +49,7 @@ self.addEventListener("fetch", (event) => { const clone = response.clone(); caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone)); return response; - }) - .catch(() => caches.match("/my-tasks")); + }); }) ); }); diff --git a/app/templates/auth/login.html b/app/templates/auth/login.html index dda1ba3..c150d0d 100644 --- a/app/templates/auth/login.html +++ b/app/templates/auth/login.html @@ -41,8 +41,11 @@ {{ form.submit(class_="button button--wide") }}

Demo-Logins nach dem Seeden: `anna@putzliga.local` / `putzliga123` und `ben@putzliga.local` / `putzliga123`.

-

Noch kein Konto? Neu registrieren

+ {% if registration_open %} +

Es gibt noch keinen Nutzer. Ersten Account anlegen

+ {% else %} +

Freie Registrierung ist deaktiviert.

+ {% endif %} {% endblock %} -