import datetime import smtplib from email.message import EmailMessage import email.utils from flask import Blueprint, render_template, request, url_for, redirect, flash, current_app from uffd.navbar import register_navbar from uffd.csrf import csrf_protect from uffd.user.models import User from uffd.session import get_current_user, login_required, is_valid_session from uffd.ldap import loginname_to_dn from uffd.selfservice.models import PasswordToken, MailToken from uffd.database import db bp = Blueprint("selfservice", __name__, template_folder='templates', url_prefix='/self/') @bp.route("/") @register_navbar('Selfservice', icon='portrait', blueprint=bp, visible=is_valid_session) @login_required() def index(): return render_template('self.html', user=get_current_user()) @bp.route("/update", methods=(['POST'])) @csrf_protect(blueprint=bp) @login_required() def update(): user = get_current_user() if request.values['displayname'] != user.displayname: if user.set_displayname(request.values['displayname']): flash('Display name changed.') else: flash('Display name is not valid.') if request.values['password1']: if not request.values['password1'] == request.values['password2']: flash('Passwords do not match') else: if user.set_password(request.values['password1']): flash('Password changed.') else: flash('Password could not be set.') if request.values['mail'] != user.mail: send_mail_verification(user.loginname, request.values['mail']) flash('We sent you an email, please verify your mail address.') user.to_ldap() return redirect(url_for('selfservice.index')) @bp.route("/passwordreset", methods=(['GET', 'POST'])) def forgot_password(): if request.method == 'GET': return render_template('forgot_password.html') loginname = request.values['loginname'] mail = request.values['mail'] flash("We sent a mail to this users mail address if you entered the correct mail and login name combination") user = User.from_ldap_dn(loginname_to_dn(loginname)) if user and user.mail == mail: send_passwordreset(loginname) return redirect(url_for('session.login')) @bp.route("/token/password/<token>", methods=(['POST', 'GET'])) def token_password(token): session = db.session dbtoken = PasswordToken.query.get(token) if not dbtoken or dbtoken.created < (datetime.datetime.now() - datetime.timedelta(days=2)): flash('Token expired, please try again.') if dbtoken: session.delete(dbtoken) session.commit() return redirect(url_for('session.login')) if request.method == 'GET': return render_template('set_password.html', token=token) if not request.values['password1']: flash('You need to set a password, please try again.') return render_template('set_password.html', token=token) if not request.values['password1'] == request.values['password2']: flash('Passwords do not match, please try again.') return render_template('set_password.html', token=token) user = User.from_ldap_dn(loginname_to_dn(dbtoken.loginname)) if not user.set_password(request.values['password1']): flash('Password ist not valid, please try again.') return render_template('set_password.html', token=token) user.to_ldap() flash('New password set') session.delete(dbtoken) session.commit() return redirect(url_for('session.login')) @bp.route("/token/mail_verification/<token>") @login_required() def token_mail(token): session = db.session dbtoken = MailToken.query.get(token) if not dbtoken or dbtoken.created < (datetime.datetime.now() - datetime.timedelta(days=2)): flash('Token expired, please try again.') if dbtoken: session.delete(dbtoken) session.commit() return redirect(url_for('selfservice.index')) user = User.from_ldap_dn(loginname_to_dn(dbtoken.loginname)) user.set_mail(dbtoken.newmail) user.to_ldap() flash('New mail set') session.delete(dbtoken) session.commit() return redirect(url_for('selfservice.index')) def send_mail_verification(loginname, newmail): session = db.session expired_tokens = MailToken.query.filter(MailToken.created < (datetime.datetime.now() - datetime.timedelta(days=2))).all() duplicate_tokens = MailToken.query.filter(MailToken.loginname == loginname).all() for i in expired_tokens + duplicate_tokens: session.delete(i) token = MailToken() token.loginname = loginname token.newmail = newmail session.add(token) session.commit() user = User.from_ldap_dn(loginname_to_dn(loginname)) msg = EmailMessage() msg.set_content(render_template('mailverification.mail.txt', user=user, token=token.token)) msg['Subject'] = 'Mail verification' send_mail(newmail, msg) def send_passwordreset(loginname): session = db.session expired_tokens = PasswordToken.query.filter(PasswordToken.created < (datetime.datetime.now() - datetime.timedelta(days=2))).all() duplicate_tokens = PasswordToken.query.filter(PasswordToken.loginname == loginname).all() for i in expired_tokens + duplicate_tokens: session.delete(i) token = PasswordToken() token.loginname = loginname session.add(token) session.commit() user = User.from_ldap_dn(loginname_to_dn(loginname)) msg = EmailMessage() msg.set_content(render_template('passwordreset.mail.txt', user=user, token=token.token)) msg['Subject'] = 'Password reset' send_mail(user.mail, msg) def send_mail(to_address, msg): server = smtplib.SMTP(host=current_app.config['MAIL_SERVER'], port=current_app.config['MAIL_PORT']) if current_app.config['MAIL_USE_STARTTLS']: server.starttls() server.login(current_app.config['MAIL_USERNAME'], current_app.config['MAIL_PASSWORD']) msg['From'] = current_app.config['MAIL_FROM_ADDRESS'] msg['To'] = to_address msg['Date'] = email.utils.formatdate(localtime=1) msg['Message-ID'] = email.utils.make_msgid() server.send_message(msg) server.quit()