mirror of
https://github.com/simple-login/app.git
synced 2024-09-28 20:51:29 +02:00
Fix: Add CSRF validation to api key management page (#1523)
* Fix: Add CSRF validation to api key management page * Added csrf to subdomain creation * Added CSRF to totp cancel Co-authored-by: Adrià Casajús <adria.casajus@proton.ch>
This commit is contained in:
parent
0ab53ad49a
commit
d874acfe2c
@ -7,6 +7,7 @@ from app.dashboard.base import dashboard_bp
|
||||
from app.dashboard.views.enter_sudo import sudo_required
|
||||
from app.db import Session
|
||||
from app.models import ApiKey
|
||||
from app.utils import CSRFValidationForm
|
||||
|
||||
|
||||
class NewApiKeyForm(FlaskForm):
|
||||
@ -23,9 +24,13 @@ def api_key():
|
||||
.all()
|
||||
)
|
||||
|
||||
csrf_form = CSRFValidationForm()
|
||||
new_api_key_form = NewApiKeyForm()
|
||||
|
||||
if request.method == "POST":
|
||||
if not csrf_form.validate():
|
||||
flash("Invalid request", "warning")
|
||||
return redirect(request.url)
|
||||
if request.form.get("form-name") == "delete":
|
||||
api_key_id = request.form.get("api-key-id")
|
||||
|
||||
@ -62,5 +67,8 @@ def api_key():
|
||||
return redirect(url_for("dashboard.api_key"))
|
||||
|
||||
return render_template(
|
||||
"dashboard/api_key.html", api_keys=api_keys, new_api_key_form=new_api_key_form
|
||||
"dashboard/api_key.html",
|
||||
api_keys=api_keys,
|
||||
new_api_key_form=new_api_key_form,
|
||||
csrf_form=csrf_form,
|
||||
)
|
||||
|
@ -34,7 +34,7 @@ def batch_import_route():
|
||||
if request.method == "POST":
|
||||
if not csrf_form.validate():
|
||||
flash("Invalid request", "warning")
|
||||
redirect(request.url)
|
||||
return redirect(request.url)
|
||||
if len(batch_imports) > 10:
|
||||
flash(
|
||||
"You have too many imports already. Wait until some get cleaned up",
|
||||
|
@ -5,6 +5,7 @@ from app.dashboard.base import dashboard_bp
|
||||
from app.dashboard.views.enter_sudo import sudo_required
|
||||
from app.db import Session
|
||||
from app.models import RecoveryCode
|
||||
from app.utils import CSRFValidationForm
|
||||
|
||||
|
||||
@dashboard_bp.route("/mfa_cancel", methods=["GET", "POST"])
|
||||
@ -15,8 +16,13 @@ def mfa_cancel():
|
||||
flash("you don't have MFA enabled", "warning")
|
||||
return redirect(url_for("dashboard.index"))
|
||||
|
||||
csrf_form = CSRFValidationForm()
|
||||
|
||||
# user cancels TOTP
|
||||
if request.method == "POST":
|
||||
if not csrf_form.validate():
|
||||
flash("Invalid request", "warning")
|
||||
return redirect(request.url)
|
||||
current_user.enable_otp = False
|
||||
current_user.otp_secret = None
|
||||
Session.commit()
|
||||
@ -28,4 +34,4 @@ def mfa_cancel():
|
||||
flash("TOTP is now disabled", "warning")
|
||||
return redirect(url_for("dashboard.index"))
|
||||
|
||||
return render_template("dashboard/mfa_cancel.html")
|
||||
return render_template("dashboard/mfa_cancel.html", csrf_form=csrf_form)
|
||||
|
@ -2,6 +2,8 @@ import re
|
||||
|
||||
from flask import render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, validators
|
||||
|
||||
from app import parallel_limiter
|
||||
from app.config import MAX_NB_SUBDOMAIN
|
||||
@ -14,6 +16,15 @@ from app.models import CustomDomain, Mailbox, SLDomain
|
||||
_SUBDOMAIN_PATTERN = r"[0-9a-z-]{1,}"
|
||||
|
||||
|
||||
class NewSubdomainForm(FlaskForm):
|
||||
domain = StringField(
|
||||
"domain", validators=[validators.DataRequired(), validators.Length(max=64)]
|
||||
)
|
||||
subdomain = StringField(
|
||||
"subdomain", validators=[validators.DataRequired(), validators.Length(max=64)]
|
||||
)
|
||||
|
||||
|
||||
@dashboard_bp.route("/subdomain", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@parallel_limiter.lock(only_when=lambda: request.method == "POST")
|
||||
@ -28,9 +39,13 @@ def subdomain_route():
|
||||
).all()
|
||||
|
||||
errors = {}
|
||||
new_subdomain_form = NewSubdomainForm()
|
||||
|
||||
if request.method == "POST":
|
||||
if request.form.get("form-name") == "create":
|
||||
if not new_subdomain_form.validate():
|
||||
flash("Invalid new subdomain", "warning")
|
||||
return redirect(url_for("dashboard.subdomain_route"))
|
||||
if not current_user.is_premium():
|
||||
flash("Only premium plan can add subdomain", "warning")
|
||||
return redirect(request.url)
|
||||
@ -41,8 +56,8 @@ def subdomain_route():
|
||||
)
|
||||
return redirect(request.url)
|
||||
|
||||
subdomain = request.form.get("subdomain").lower().strip()
|
||||
domain = request.form.get("domain").lower().strip()
|
||||
subdomain = new_subdomain_form.subdomain.data.lower().strip()
|
||||
domain = new_subdomain_form.domain.data.lower().strip()
|
||||
|
||||
if len(subdomain) < 3:
|
||||
flash("Subdomain must have at least 3 characters", "error")
|
||||
@ -110,4 +125,5 @@ def subdomain_route():
|
||||
sl_domains=sl_domains,
|
||||
errors=errors,
|
||||
subdomains=subdomains,
|
||||
new_subdomain_form=new_subdomain_form,
|
||||
)
|
||||
|
@ -43,6 +43,7 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form method="post">
|
||||
{{ csrf_form.csrf_token }}
|
||||
<input type="hidden" name="form-name" value="delete">
|
||||
<input type="hidden" name="api-key-id" value="{{ api_key.id }}">
|
||||
<span class="card-link btn btn-link float-right text-danger delete-api-key">Delete</span>
|
||||
@ -57,6 +58,7 @@
|
||||
{% if api_keys|length > 0 %}
|
||||
|
||||
<form method="post">
|
||||
{{ csrf_form.csrf_token }}
|
||||
<input type="hidden" name="form-name" value="delete-all">
|
||||
<span class="delete btn btn-outline-danger delete-all-api-keys float-right">
|
||||
Delete All <i class="fe fe-trash"></i>
|
||||
@ -66,7 +68,7 @@
|
||||
{% endif %}
|
||||
<hr />
|
||||
<form method="post">
|
||||
{{ new_api_key_form.csrf_token }}
|
||||
{{ csrf_form.csrf_token }}
|
||||
<input type="hidden" name="form-name" value="create">
|
||||
<h2 class="h4">New API Key</h2>
|
||||
{{ new_api_key_form.name(class="form-control", placeholder="Chrome") }}
|
||||
|
@ -12,6 +12,7 @@
|
||||
or use WebAuthn (FIDO).
|
||||
</div>
|
||||
<form method="post">
|
||||
{{ csrf_form.csrf_token }}
|
||||
<button class="btn btn-danger mt-2">Disable TOTP</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -72,6 +72,7 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h4 mb-1">New Subdomain</h2>
|
||||
<form method="post" class="mt-2" data-parsley-validate>
|
||||
{{ new_subdomain_form.csrf_token }}
|
||||
<input type="hidden" name="form-name" value="create">
|
||||
<div class="form-group">
|
||||
<label>Subdomain</label>
|
||||
|
Loading…
Reference in New Issue
Block a user