2026-05-27 22:04:04 -04:00
|
|
|
from pathlib import Path
|
2026-05-17 03:26:01 -04:00
|
|
|
from flask import Blueprint, request, session, redirect, flash
|
2026-06-10 14:23:47 -04:00
|
|
|
import time, secrets
|
2026-06-07 00:21:08 -04:00
|
|
|
import auth
|
|
|
|
|
import config_utils
|
2026-06-10 14:23:47 -04:00
|
|
|
import settings
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-05-27 22:04:04 -04:00
|
|
|
_PAGE = Path(__file__).parent.name
|
|
|
|
|
|
|
|
|
|
bp = Blueprint(_PAGE, __name__)
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
|
2026-05-27 22:04:04 -04:00
|
|
|
@bp.route('/action/accountverifyemail/email_verify', methods=['POST'])
|
2026-06-07 00:21:08 -04:00
|
|
|
@auth.require_level('nothing')
|
2026-05-27 22:04:04 -04:00
|
|
|
def email_verify():
|
2026-05-17 03:26:01 -04:00
|
|
|
if session.get('access_level', 'nothing') != 'nothing':
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/overview')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
pending_email = session.get('pending_verify_email', '').lower()
|
|
|
|
|
if not pending_email:
|
|
|
|
|
flash('No pending account creation found. Please start over.', 'error')
|
|
|
|
|
return redirect('/accountcreate')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
try:
|
|
|
|
|
con = config_utils.open_accounts_db()
|
|
|
|
|
row = con.execute(
|
|
|
|
|
'SELECT * FROM pending_verifications WHERE email=?', (pending_email,)
|
|
|
|
|
).fetchone()
|
|
|
|
|
con.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
row = None
|
|
|
|
|
|
|
|
|
|
if not row:
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('No pending account creation found. Please start over.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/accountcreate')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
if int(time.time()) > row['expires_ts']:
|
|
|
|
|
try:
|
|
|
|
|
con = config_utils.open_accounts_db()
|
|
|
|
|
con.execute('DELETE FROM pending_verifications WHERE email=?', (pending_email,))
|
|
|
|
|
con.commit()
|
|
|
|
|
con.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
session.pop('pending_verify_email', None)
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('Verification code has expired. Please start over.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/accountcreate')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
submitted = request.form.get('code', '').strip()
|
2026-06-10 14:23:47 -04:00
|
|
|
if submitted != row['code']:
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('Incorrect verification code.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect(f'/{_PAGE}')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
account = config_utils.get_account_by_email(pending_email)
|
2026-05-17 03:26:01 -04:00
|
|
|
if account is None:
|
2026-06-10 14:23:47 -04:00
|
|
|
session.pop('pending_verify_email', None)
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('Account no longer exists. Contact your manager.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/accountcreate')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
if account.get('hashed_password'):
|
2026-06-10 14:23:47 -04:00
|
|
|
session.pop('pending_verify_email', None)
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('This account is already set up. Please log in.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/accountlogin')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
now = int(time.time())
|
|
|
|
|
try:
|
|
|
|
|
con = config_utils.open_accounts_db()
|
|
|
|
|
con.execute(
|
|
|
|
|
'UPDATE accounts SET hashed_password=?, created_ts=?, created_by=? WHERE account_id=?',
|
|
|
|
|
(row['hashed_password'], now, 'self', account['account_id'])
|
|
|
|
|
)
|
|
|
|
|
con.execute('DELETE FROM pending_verifications WHERE email=?', (pending_email,))
|
|
|
|
|
con.commit()
|
|
|
|
|
con.close()
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
flash(f'Could not complete account setup: {exc}', 'error')
|
|
|
|
|
return redirect(f'/{_PAGE}')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
session.pop('pending_verify_email', None)
|
|
|
|
|
session['account_id'] = account['account_id']
|
|
|
|
|
session['tz_offset_seconds'] = int(row['tz_offset_seconds'])
|
|
|
|
|
session['apply_changes_immediately'] = False
|
|
|
|
|
session.permanent = True
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/overview')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
|
2026-05-27 22:04:04 -04:00
|
|
|
@bp.route('/action/accountverifyemail/email_resend')
|
2026-06-07 00:21:08 -04:00
|
|
|
@auth.require_level('nothing')
|
2026-05-27 22:04:04 -04:00
|
|
|
def email_resend():
|
2026-05-17 03:26:01 -04:00
|
|
|
if session.get('access_level', 'nothing') != 'nothing':
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/overview')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
from pages.accountcreate.action import _send_verification_email, CODE_TTL_SECS
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
pending_email = session.get('pending_verify_email', '').lower()
|
|
|
|
|
if not pending_email:
|
2026-05-17 03:26:01 -04:00
|
|
|
flash('No pending account creation found. Please start over.', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect('/accountcreate')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
code = f'{secrets.randbelow(1000000):06d}'
|
|
|
|
|
expires_ts = int(time.time()) + CODE_TTL_SECS
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
try:
|
2026-06-10 14:23:47 -04:00
|
|
|
_send_verification_email(pending_email, code)
|
2026-05-17 03:26:01 -04:00
|
|
|
except Exception as exc:
|
|
|
|
|
flash(f'Could not resend verification email: {exc}', 'error')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect(f'/{_PAGE}')
|
2026-05-17 03:26:01 -04:00
|
|
|
|
2026-06-10 14:23:47 -04:00
|
|
|
try:
|
|
|
|
|
con = config_utils.open_accounts_db()
|
|
|
|
|
con.execute(
|
|
|
|
|
'UPDATE pending_verifications SET code=?, expires_ts=? WHERE email=?',
|
|
|
|
|
(code, expires_ts, pending_email)
|
|
|
|
|
)
|
|
|
|
|
con.commit()
|
|
|
|
|
con.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2026-05-17 03:26:01 -04:00
|
|
|
|
|
|
|
|
flash('A new verification code has been sent.', 'success')
|
2026-05-27 22:04:04 -04:00
|
|
|
return redirect(f'/{_PAGE}')
|