115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
from pathlib import Path
|
|
from flask import Blueprint, request, session, redirect, flash
|
|
import json, os, secrets
|
|
from datetime import datetime, timezone, timedelta
|
|
import auth
|
|
import config_utils
|
|
|
|
_PAGE = Path(__file__).parent.name
|
|
|
|
bp = Blueprint(_PAGE, __name__)
|
|
|
|
|
|
|
|
def _load_accounts():
|
|
try:
|
|
with open(config_utils.ACCOUNTS_FILE) as f:
|
|
return json.load(f)
|
|
except Exception:
|
|
return {'accounts': []}
|
|
|
|
def _save_accounts(data):
|
|
with open(config_utils.ACCOUNTS_FILE, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
|
|
@bp.route('/action/accountverifyemail/email_verify', methods=['POST'])
|
|
@auth.require_level('nothing')
|
|
def email_verify():
|
|
# Abort if already logged in
|
|
if session.get('access_level', 'nothing') != 'nothing':
|
|
return redirect('/overview')
|
|
|
|
pending = session.get('pending_create_account')
|
|
|
|
if not pending:
|
|
flash('No pending account creation found. Please start over.', 'error')
|
|
return redirect('/accountcreate')
|
|
|
|
expires = datetime.fromisoformat(pending['expires'])
|
|
if datetime.now(tz=timezone.utc) > expires:
|
|
session.pop('pending_create_account', None)
|
|
flash('Verification code has expired. Please start over.', 'error')
|
|
return redirect('/accountcreate')
|
|
|
|
submitted = request.form.get('code', '').strip()
|
|
if submitted != pending['code']:
|
|
flash('Incorrect verification code.', 'error')
|
|
return redirect(f'/{_PAGE}')
|
|
|
|
data = _load_accounts()
|
|
accounts = data.get('accounts', [])
|
|
account = next(
|
|
(a for a in accounts if a.get('email_address', '').lower() == pending['email'].lower()),
|
|
None
|
|
)
|
|
|
|
if account is None:
|
|
session.pop('pending_create_account', None)
|
|
flash('Account no longer exists. Contact your manager.', 'error')
|
|
return redirect('/accountcreate')
|
|
|
|
if account.get('hashed_password'):
|
|
session.pop('pending_create_account', None)
|
|
flash('This account is already set up. Please log in.', 'error')
|
|
return redirect('/accountlogin')
|
|
|
|
now = datetime.now(tz=timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
account['hashed_password'] = pending['hashed_password']
|
|
account['timezone'] = pending['timezone']
|
|
if not account.get('account_created_utc'):
|
|
account['account_created_utc'] = now
|
|
if not account.get('account_created_by'):
|
|
account['account_created_by'] = 'self'
|
|
|
|
_save_accounts(data)
|
|
session.pop('pending_create_account', None)
|
|
|
|
session['email_address'] = account['email_address']
|
|
session['access_level'] = account.get('access_level', 'viewer')
|
|
session['timezone'] = pending['timezone']
|
|
session.permanent = True
|
|
|
|
return redirect('/overview')
|
|
|
|
|
|
@bp.route('/action/accountverifyemail/email_resend')
|
|
@auth.require_level('nothing')
|
|
def email_resend():
|
|
# Abort if already logged in
|
|
if session.get('access_level', 'nothing') != 'nothing':
|
|
return redirect('/overview')
|
|
|
|
from pages.accountcreate.action import _send_verification_email, CODE_TTL_MIN
|
|
|
|
pending = session.get('pending_create_account')
|
|
|
|
if not pending:
|
|
flash('No pending account creation found. Please start over.', 'error')
|
|
return redirect('/accountcreate')
|
|
|
|
code = f'{secrets.randbelow(1000000):06d}'
|
|
expires = (datetime.now(tz=timezone.utc) + timedelta(minutes=CODE_TTL_MIN)).isoformat()
|
|
|
|
try:
|
|
_send_verification_email(pending['email'], code)
|
|
except Exception as exc:
|
|
flash(f'Could not resend verification email: {exc}', 'error')
|
|
return redirect(f'/{_PAGE}')
|
|
|
|
pending['code'] = code
|
|
pending['expires'] = expires
|
|
session['pending_create_account'] = pending
|
|
|
|
flash('A new verification code has been sent.', 'success')
|
|
return redirect(f'/{_PAGE}')
|