mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-12-24 02:24:20 +00:00
Rework auth package
This commit is contained in:
parent
c90cd4d8a3
commit
3b798cb617
@ -10,7 +10,7 @@ import logging
|
||||
db = SQLAlchemy()
|
||||
logger = logging.getLogger(__name__)
|
||||
login_manager = LoginManager()
|
||||
login_manager.login_view = 'main.index'
|
||||
login_manager.login_view = 'auth.login'
|
||||
mail = Mail()
|
||||
socketio = SocketIO()
|
||||
|
||||
|
@ -12,25 +12,6 @@ class LoginForm(FlaskForm):
|
||||
submit = SubmitField('Log In')
|
||||
|
||||
|
||||
class PasswordResetForm(FlaskForm):
|
||||
password = PasswordField(
|
||||
'New Password',
|
||||
validators=[DataRequired(),
|
||||
EqualTo('password2', message='Passwords must match')]
|
||||
)
|
||||
password2 = PasswordField(
|
||||
'Confirm password',
|
||||
validators=[DataRequired(),
|
||||
EqualTo('password', message='Passwords must match.')]
|
||||
)
|
||||
submit = SubmitField('Reset Password')
|
||||
|
||||
|
||||
class PasswordResetRequestForm(FlaskForm):
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
submit = SubmitField('Reset Password')
|
||||
|
||||
|
||||
class RegistrationForm(FlaskForm):
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
username = StringField(
|
||||
@ -55,3 +36,22 @@ class RegistrationForm(FlaskForm):
|
||||
def validate_username(self, field):
|
||||
if User.query.filter_by(username=field.data).first():
|
||||
raise ValidationError('Username already in use.')
|
||||
|
||||
|
||||
class ResetPasswordForm(FlaskForm):
|
||||
password = PasswordField(
|
||||
'New Password',
|
||||
validators=[DataRequired(),
|
||||
EqualTo('password2', message='Passwords must match')]
|
||||
)
|
||||
password2 = PasswordField(
|
||||
'Confirm password',
|
||||
validators=[DataRequired(),
|
||||
EqualTo('password', message='Passwords must match.')]
|
||||
)
|
||||
submit = SubmitField('Reset Password')
|
||||
|
||||
|
||||
class ResetPasswordRequestForm(FlaskForm):
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
submit = SubmitField('Reset Password')
|
||||
|
@ -1,62 +1,14 @@
|
||||
from app import db
|
||||
from app import db, logger
|
||||
from app.email import send_email
|
||||
from app.models import User
|
||||
from flask import (current_app, flash, redirect, render_template, request,
|
||||
url_for)
|
||||
from flask_login import current_user, login_required, logout_user
|
||||
from flask_login import current_user, login_user, login_required, logout_user
|
||||
from . import auth
|
||||
from .forms import (PasswordResetForm, PasswordResetRequestForm,
|
||||
from .forms import (LoginForm, ResetPasswordForm, ResetPasswordRequestForm,
|
||||
RegistrationForm)
|
||||
import os
|
||||
|
||||
|
||||
@auth.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
flash('You have been logged out.')
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
|
||||
@auth.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
if not current_user.is_anonymous:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
registration_form = RegistrationForm(prefix='registration-form')
|
||||
if registration_form.validate_on_submit():
|
||||
user = User(email=registration_form.email.data.lower(),
|
||||
password=registration_form.password.data,
|
||||
username=registration_form.username.data)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
dir = os.path.join(current_app.config['NOPAQUE_STORAGE'], str(user.id))
|
||||
try:
|
||||
os.makedirs(dir)
|
||||
except OSError:
|
||||
flash('[ERROR]!')
|
||||
user.delete()
|
||||
else:
|
||||
token = user.generate_confirmation_token()
|
||||
send_email(user.email, 'Confirm Your Account',
|
||||
'auth/email/confirm', token=token, user=user)
|
||||
flash('A confirmation email has been sent to you by email.')
|
||||
return redirect(url_for('main.index'))
|
||||
return render_template('auth/register.html.j2',
|
||||
registration_form=registration_form,
|
||||
title='Register')
|
||||
|
||||
|
||||
@auth.route('/confirm/<token>')
|
||||
@login_required
|
||||
def confirm(token):
|
||||
if current_user.confirmed:
|
||||
return redirect(url_for('main.index'))
|
||||
if current_user.confirm(token):
|
||||
db.session.commit()
|
||||
flash('You have confirmed your account. Thanks!')
|
||||
else:
|
||||
flash('The confirmation link is invalid or has expired.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
import shutil
|
||||
|
||||
|
||||
@auth.before_app_request
|
||||
@ -72,10 +24,76 @@ def before_request():
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
|
||||
|
||||
@auth.route('/login')
|
||||
def login():
|
||||
login_form = LoginForm(prefix='login-form')
|
||||
if login_form.validate_on_submit():
|
||||
user = User.query.filter_by(username=login_form.user.data).first()
|
||||
if user is not None and user.verify_password(login_form.password.data):
|
||||
login_user(user, login_form.remember_me.data)
|
||||
next = request.args.get('next')
|
||||
if next is None or not next.startswith('/'):
|
||||
next = url_for('main.dashboard')
|
||||
return redirect(next)
|
||||
flash('Invalid username or password.')
|
||||
return render_template('auth/login.html.j2', login_form=login_form,
|
||||
title='nopaque')
|
||||
|
||||
|
||||
@auth.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
flash('You have been logged out.')
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
|
||||
@auth.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
registration_form = RegistrationForm(prefix='registration-form')
|
||||
if registration_form.validate_on_submit():
|
||||
user = User(email=registration_form.email.data.lower(),
|
||||
password=registration_form.password.data,
|
||||
username=registration_form.username.data)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
user_dir = os.path.join(current_app.config['NOPAQUE_STORAGE'],
|
||||
str(user.id))
|
||||
if os.path.exists(user_dir):
|
||||
shutil.rmtree(user_dir)
|
||||
os.mkdir(user_dir)
|
||||
token = user.generate_confirmation_token()
|
||||
send_email(user.email, 'Confirm Your Account',
|
||||
'auth/email/confirm', token=token, user=user)
|
||||
flash('A confirmation email has been sent to you by email.')
|
||||
return redirect(url_for('auth.login'))
|
||||
return render_template('auth/register.html.j2',
|
||||
registration_form=registration_form,
|
||||
title='Register')
|
||||
|
||||
|
||||
@auth.route('/confirm/<token>')
|
||||
@login_required
|
||||
def confirm(token):
|
||||
if current_user.confirmed:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
if current_user.confirm(token):
|
||||
db.session.commit()
|
||||
flash('You have confirmed your account. Thanks!')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
else:
|
||||
flash('The confirmation link is invalid or has expired.')
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
|
||||
|
||||
@auth.route('/unconfirmed')
|
||||
def unconfirmed():
|
||||
if current_user.is_anonymous or current_user.confirmed:
|
||||
if current_user.is_anonymous:
|
||||
return redirect(url_for('main.index'))
|
||||
elif current_user.confirmed:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return render_template('auth/unconfirmed.html.j2', title='Unconfirmed')
|
||||
|
||||
|
||||
@ -83,49 +101,46 @@ def unconfirmed():
|
||||
@login_required
|
||||
def resend_confirmation():
|
||||
token = current_user.generate_confirmation_token()
|
||||
send_email(current_user.email,
|
||||
'Confirm Your Account',
|
||||
'auth/email/confirm',
|
||||
token=token,
|
||||
user=current_user)
|
||||
send_email(current_user.email, 'Confirm Your Account',
|
||||
'auth/email/confirm', token=token, user=current_user)
|
||||
flash('A new confirmation email has benn sent to you by email.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
|
||||
|
||||
@auth.route('/reset', methods=['GET', 'POST'])
|
||||
def password_reset_request():
|
||||
if not current_user.is_anonymous:
|
||||
def reset_password_request():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
form = PasswordResetRequestForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(email=form.email.data.lower()).first()
|
||||
reset_password_request_form = ResetPasswordRequestForm()
|
||||
if reset_password_request_form.validate_on_submit():
|
||||
submitted_email = reset_password_request_form.email.data
|
||||
user = User.query.filter_by(email=submitted_email.lower()).first()
|
||||
if user:
|
||||
token = user.generate_reset_token()
|
||||
send_email(user.email,
|
||||
'Reset Your Password',
|
||||
'auth/email/reset_password',
|
||||
token=token,
|
||||
user=user)
|
||||
send_email(user.email, 'Reset Your Password',
|
||||
'auth/email/reset_password', token=token, user=user)
|
||||
flash('An email with instructions to reset your password has been '
|
||||
'sent to you.')
|
||||
return redirect(url_for('main.index'))
|
||||
return render_template('auth/reset_password_request.html.j2',
|
||||
form=form,
|
||||
title='Password Reset')
|
||||
return redirect(url_for('auth.login'))
|
||||
return render_template(
|
||||
'auth/reset_password_request.html.j2',
|
||||
reset_password_request_form=reset_password_request_form,
|
||||
title='Password Reset'
|
||||
)
|
||||
|
||||
|
||||
@auth.route('/reset/<token>', methods=['GET', 'POST'])
|
||||
def password_reset(token):
|
||||
if not current_user.is_anonymous:
|
||||
def reset_password(token):
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.dashboard'))
|
||||
form = PasswordResetForm()
|
||||
if form.validate_on_submit():
|
||||
if User.reset_password(token, form.password.data):
|
||||
reset_password_form = ResetPasswordForm()
|
||||
if reset_password_form.validate_on_submit():
|
||||
if User.reset_password(token, reset_password_form.password.data):
|
||||
db.session.commit()
|
||||
flash('Your password has been updated.')
|
||||
return redirect(url_for('main.index'))
|
||||
return redirect(url_for('auth.login'))
|
||||
else:
|
||||
return redirect(url_for('main.index'))
|
||||
return render_template('auth/reset_password.html.j2',
|
||||
form=form,
|
||||
reset_password_form=reset_password_form,
|
||||
title='Password Reset')
|
||||
|
@ -1,7 +1,7 @@
|
||||
<p>Dear {{ user.username }},</p>
|
||||
<p>To reset your password <a href="{{ url_for('auth.password_reset', token=token, _external=True) }}">click here</a>.</p>
|
||||
<p>To reset your password <a href="{{ url_for('auth.reset_password', token=token, _external=True) }}">click here</a>.</p>
|
||||
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
|
||||
<p>{{ url_for('auth.password_reset', token=token, _external=True) }}</p>
|
||||
<p>{{ url_for('auth.reset_password', token=token, _external=True) }}</p>
|
||||
<p>If you have not requested a password reset simply ignore this message.</p>
|
||||
<p>Sincerely,</p>
|
||||
<p>The nopaque Team</p>
|
||||
|
@ -2,7 +2,7 @@ Dear {{ user.username }},
|
||||
|
||||
To reset your password click on the following link:
|
||||
|
||||
{{ url_for('auth.password_reset', token=token, _external=True) }}
|
||||
{{ url_for('auth.reset_password', token=token, _external=True) }}
|
||||
|
||||
If you have not requested a password reset simply ignore this message.
|
||||
|
||||
|
52
app/templates/auth/login.html.j2
Normal file
52
app/templates/auth/login.html.j2
Normal file
@ -0,0 +1,52 @@
|
||||
{% extends "nopaque.html.j2" %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="col s12 m4">
|
||||
<h3>Cyber cyber</h3>
|
||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m8">
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Log in</span>
|
||||
{{ login_form.hidden_tag() }}
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">person</i>
|
||||
{{ login_form.user(class='validate') }}
|
||||
{{ login_form.user.label }}
|
||||
{% for error in login_form.user.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">vpn_key</i>
|
||||
{{ login_form.password(class='validate') }}
|
||||
{{ login_form.password.label }}
|
||||
{% for error in login_form.password.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 0;">
|
||||
<div class="col s6 left-align">
|
||||
<a href="{{ url_for('auth.reset_password_request') }}">Forgot your password?</a>
|
||||
</div>
|
||||
<div class="col s6 right-align">
|
||||
<div class="switch">
|
||||
<label>
|
||||
Remember me
|
||||
{{ login_form.remember_me() }}
|
||||
<span class="lever"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action right-align">
|
||||
{{ login_form.submit(class='btn') }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -7,27 +7,27 @@
|
||||
</div>
|
||||
|
||||
<div class="col s12 m8">
|
||||
<div class="card small">
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<div class="card-content">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ reset_password_form.hidden_tag() }}
|
||||
<div class="input-field">
|
||||
{{ form.password(class='validate', type='password') }}
|
||||
{{ form.password.label }}
|
||||
{% for error in form.password.errors %}
|
||||
{{ reset_password_form.password(type='password') }}
|
||||
{{ reset_password_form.password.label }}
|
||||
{% for error in reset_password_form.password.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="input-field">
|
||||
{{ form.password2(class='validate', type='password') }}
|
||||
{{ form.password2.label }}
|
||||
{% for error in form.password2.errors %}
|
||||
{{ reset_password_form.password2(type='password') }}
|
||||
{{ reset_password_form.password2.label }}
|
||||
{% for error in reset_password_form.password2.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action">
|
||||
{{ form.submit(class='btn right') }}
|
||||
<div class="card-action right-align">
|
||||
{{ form.submit(class='btn') }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -7,20 +7,20 @@
|
||||
</div>
|
||||
|
||||
<div class="col s12 m8">
|
||||
<div class="card small">
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<div class="card-content">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ reset_password_request_form.hidden_tag() }}
|
||||
<div class="input-field">
|
||||
{{ form.email(class='validate', type='email') }}
|
||||
{{ form.email.label }}
|
||||
{% for error in form.email.errors %}
|
||||
{{ reset_password_request_form.email(class='validate', type='email') }}
|
||||
{{ reset_password_request_form.email.label }}
|
||||
{% for error in reset_password_request_form.email.errors %}
|
||||
<span class="helper-text red-text">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action">
|
||||
{{ form.submit(class='btn right') }}
|
||||
<div class="card-action right-align">
|
||||
{{ reset_password_request_form.submit(class='btn') }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -116,7 +116,7 @@
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 0;">
|
||||
<div class="col s6 left-align">
|
||||
<a href="{{ url_for('auth.password_reset_request') }}">Forgot your password?</a>
|
||||
<a href="{{ url_for('auth.reset_password_request') }}">Forgot your password?</a>
|
||||
</div>
|
||||
<div class="col s6 right-align">
|
||||
<div class="switch">
|
||||
|
@ -51,7 +51,7 @@
|
||||
<li><a href="{{ url_for('profile.settings') }}"><i class="material-icons">settings</i>Settings</a></li>
|
||||
<li><a href="{{ url_for('auth.logout') }}"><i class="material-icons">power_settings_new</i>Log out</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('main.index', _anchor='registration-and-log-in') }}"><i class="material-icons">person</i>Log in</a></li>
|
||||
<li><a href="{{ url_for('auth.login') }}"><i class="material-icons">person</i>Log in</a></li>
|
||||
<li><a href="{{ url_for('auth.register') }}"><i class="material-icons">person_add</i>Register</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -77,7 +77,7 @@
|
||||
<li><a href="{{ url_for('profile.settings') }}"><i class="material-icons">settings</i>Settings</a></li>
|
||||
<li><a href="{{ url_for('auth.logout') }}"><i class="material-icons">power_settings_new</i>Log out</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('main.index') }}"><i class="material-icons">person</i>Log in</a></li>
|
||||
<li><a href="{{ url_for('auth.login') }}"><i class="material-icons">person</i>Log in</a></li>
|
||||
<li><a href="{{ url_for('auth.register') }}"><i class="material-icons">person_add</i>Register</a></li>
|
||||
{% endif %}
|
||||
{% if current_user.is_administrator() %}
|
||||
|
Loading…
Reference in New Issue
Block a user