linuxrouter/docker/routlin-dash/app/pages/accountverifyemail/action.py
2026-06-07 00:21:08 -04:00

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}')