def login(): title = 'Login' if current_user.is_authenticated: return redirect(url_for('main.index')) form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data.lower()).first() if user and bcrypt.check_password_hash(user.password.encode(), form.password.data): if user.activated != 0: session['email'] = user.email session['master_key'] = decrypt(get_key(form.password.data), user.master_key) if user.otp_secret is None: login_user(user, remember=form.remember.data) session['encryption_key'] = get_key(session['master_key']) next_page = request.args.get('next') return redirect(next_page) if next_page else redirect(url_for('main.index')) else: return redirect(url_for('account.login_2fa')) else: flash(Markup(f'Your email address is not confirmed. Check your email for the verification link or ' f'<a href="{url_for("account.resend_activation_link", email=user.email)}">' f'send again.</a>'), 'warning') else: flash('Invalid email or password!', 'danger') return render_template('account/login.html', title=title, form=form)
def account_settings(): title = 'Account Settings' # Check if 2fa is enabled for current user if current_user.otp_secret is None: tfa = False else: tfa = True form = UpdateAccountForm() if form.validate_on_submit(): if bcrypt.check_password_hash(current_user.password.encode(), form.current_password.data): if form.email.data != current_user.email: current_user.email = form.email.data current_user.activated = False send_activation_email(current_user) flash('Email address has been changed. Please check your email for the verification link.', 'success') if form.new_password.data: current_user.password = bcrypt.generate_password_hash(form.new_password.data) current_user.master_key = encrypt(get_key(form.new_password.data), session['master_key']) flash('Password has been updated.', 'success') db.session.commit() return redirect(url_for('account.account_settings')) elif request.method == 'GET': form.email.data = current_user.email return render_template('account/account_settings.html', title=title, form=form, tfa=tfa)
def register(): title = 'Create an account' if current_user.is_authenticated: return redirect(url_for('main.index')) form = RegistrationForm() if form.validate_on_submit(): email = form.email.data.lower() hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8') master_key = generate_pswrd(length=32, special=False) encrypted_master_key = encrypt(get_key(form.password.data), master_key) user = User(email=email, password=hashed_password, master_key=encrypted_master_key) try: send_activation_email(user) flash('Account created! Verification link has been sent to your email.', 'success') except SMTPRecipientsRefused: flash('Entered email address is invalid!', 'danger') return redirect(url_for('account.register')) except: user.activated = True flash('Account created! You can now log in.', 'success') db.session.add(user) db.session.commit() return redirect(url_for('account.login')) return render_template('account/register.html', title=title, form=form)
def import_encrypted_user_data(data, master_key): data = json.loads(data) encryption_key = get_key(master_key) passwords = [] for entry_id in data['passwords']: entry = data['passwords'][entry_id] entry['name'] = entry['name'] entry['site'] = entry['site'] entry['username'] = entry['username'] entry['password'] = entry['password'] passwords.append( Password(name=entry['name'], site=entry['site'], username=entry['username'], password=entry['password'])) secure_notes = [] for entry_id in data['secure_notes']: entry = data['secure_notes'][entry_id] entry['name'] = entry['name'] entry['content'] = entry['content'] secure_notes.append( SecureNote(name=entry['name'], content=entry['content'])) credit_cards = [] for entry_id in data['credit_cards']: entry = data['credit_cards'][entry_id] entry['name'] = entry['name'] entry['number'] = entry['number'] entry['expiration_date'] = entry['expiration_date'] entry['cvv'] = entry['cvv'] entry['cardholder_name'] = entry['cardholder_name'] credit_cards.append( CreditCard(name=entry['name'], number=entry['number'], expiration_date=entry['expiration_date'], cvv=entry['cvv'], cardholder_name=entry['cardholder_name'])) decrypted_passwords = [] for entry in passwords: entry = decrypt_password(encryption_key, entry) decrypted_passwords.append(entry) decrypted_secure_notes = [] for entry in secure_notes: entry = decrypt_secure_note(encryption_key, entry) decrypted_secure_notes.append(entry) decrypted_credit_cards = [] for entry in credit_cards: entry = decrypt_credit_card(encryption_key, entry) decrypted_credit_cards.append(entry) return decrypted_passwords, decrypted_secure_notes, decrypted_credit_cards
def reset_token(token): title = 'Reset Password' if current_user.is_authenticated: return redirect(url_for('main.index')) user = User.verify_reset_token(token) if not user: flash('Invalid or expired token.', 'danger') return redirect(url_for('account.reset_request')) form = ResetPasswordForm() if form.validate_on_submit(): if bcrypt.check_password_hash(user.password.encode(), form.password.data): flash('The password you entered is already set.', 'danger') return redirect(url_for('account.reset_token', token=token)) file_contents = '' if form.master_key_file.data: file_contents = form.master_key_file.data.stream.readline().decode('utf-8') if not form.master_key.data and not file_contents and form.lost_master_key.data: wipe_user_data(user) master_key = generate_pswrd(length=32, special=False) user.master_key = encrypt(get_key(form.password.data), master_key) flash('User data has been permanently erased! Master key has been reset.', 'warning') elif not check_master_key(form.master_key.data, user) and not check_master_key(file_contents, user): flash('Master key invalid or not provided!', 'danger') return redirect(url_for('account.reset_token', token=token)) else: user.master_key = encrypt(get_key(form.password.data), form.master_key.data) user.password = bcrypt.generate_password_hash(form.password.data) db.session.commit() flash('Password has been updated.', 'success') return redirect(url_for('account.login')) return render_template('account/password_reset_token.html', title=title, form=form)
def change_master_key(): title = 'Get a New Master Key' form = ChangeMasterKeyForm() if form.validate_on_submit(): if bcrypt.check_password_hash(current_user.password.encode(), form.password.data): current_user.master_key = encrypt(get_key(form.password.data), form.master_key.data) old_encryption_key = session['encryption_key'] new_encryption_key = get_key(form.master_key.data) reencrypt_user_data(current_user, old_encryption_key, new_encryption_key) db.session.commit() session['master_key'] = form.master_key.data session['encryption_key'] = new_encryption_key flash('Master key has been changed. Don\'t forget to save it in a secure place!', 'success') return redirect(url_for('account.account_settings')) else: flash('The password you entered is incorrect.', 'danger') return redirect(url_for('account.change_master_key')) elif request.method == 'GET': form.master_key.data = generate_pswrd(length=32, special=False) return render_template('account/change_master_key.html', title=title, form=form)
def login_2fa(): title = 'Login' user = User.query.filter_by(email=session['email']).first() form = TFAForm() if form.validate_on_submit(): if user.verify_totp(form.security_code.data): login_user(user, remember=form.remember.data) session['encryption_key'] = get_key(session['master_key']) return redirect(url_for('main.index')) else: session['email'] = None session['master_key'] = None flash('Invalid security code!', 'danger') return redirect(url_for('account.login')) return render_template('account/login_2fa.html', title=title, form=form)
def check_master_key(master_key, user): """Checks if provided master key is valid by trying to decrypt user data with it.""" encryption_key = get_key(master_key) try: get_user_passwords(user, encryption_key) except: return False try: get_user_secure_notes(user, encryption_key) except: return False try: get_user_credit_cards(user, encryption_key) except: return False return True