PIVOT 1.1.0
This commit is contained in:
commit
8a53234eb6
161 files changed
+31109
No files matched your search
@@ -0,0 +1,177 @@
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, session
|
||||
from tenancy import huidige_school, per_school
|
||||
from blueprints.auth import login_required
|
||||
from rechten import recht_vereist
|
||||
from config import Config
|
||||
from services.tweestaps_service import TweestapsService, TweestapsError
|
||||
|
||||
tweestaps_bp = Blueprint('tweestaps', __name__)
|
||||
LOG_PER_PAGINA = 25 # standaard; te kiezen: 10 / 25 / 50 / 100 / alles (0)
|
||||
LOG_KEUZES = (10, 25, 50, 100, 0)
|
||||
service = per_school(TweestapsService)
|
||||
|
||||
_tables_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn
|
||||
|
||||
|
||||
def _ensure_tables():
|
||||
if huidige_school().code not in _tables_ready:
|
||||
try:
|
||||
service.ensure_tables()
|
||||
_tables_ready.add(huidige_school().code)
|
||||
except Exception as e:
|
||||
flash(f"Kon de 2FA-tabellen niet aanmaken: {e}", "error")
|
||||
|
||||
|
||||
def _render(email=None, codes=None, code_actie=None, fout=None):
|
||||
"""Bouwt de pagina op; codes worden enkel in deze response getoond, nooit bewaard of gelogd."""
|
||||
tab = request.args.get('tab', 'hulp')
|
||||
zoek = (request.args.get('zoek') or '').strip()
|
||||
email = email or (request.args.get('email') or '').strip()
|
||||
gebruiker, uitzondering, zoekresultaten, reset_wacht = None, None, [], None
|
||||
|
||||
if zoek and '@' not in zoek:
|
||||
zoekresultaten = service.search_users(zoek)
|
||||
if not zoekresultaten:
|
||||
fout = fout or f"Geen gebruikers gevonden voor '{zoek}'."
|
||||
elif zoek:
|
||||
email = zoek
|
||||
|
||||
if email:
|
||||
try:
|
||||
gebruiker = service.get_user(email)
|
||||
uitzondering = service.active_for(gebruiker['email'])
|
||||
reset_wacht = service.reset_bezig(gebruiker['email'])
|
||||
except TweestapsError as e:
|
||||
fout = fout or str(e)
|
||||
|
||||
try:
|
||||
actief = service.active_exceptions()
|
||||
# Aantal per pagina: uit ?logper=..., anders de vorige keuze (sessie), anders 25
|
||||
per = request.args.get('logper', type=int)
|
||||
if per in LOG_KEUZES:
|
||||
session['tweestaps_logper'] = per
|
||||
per = session.get('tweestaps_logper', LOG_PER_PAGINA)
|
||||
grootte = per or 100000 # 0 = alles
|
||||
log_pagina = max(1, request.args.get('logpagina', 1, type=int) or 1)
|
||||
logboek, log_totaal = service.recent_log(log_pagina, grootte)
|
||||
log_paginas = max(1, -(-log_totaal // grootte))
|
||||
if log_pagina > log_paginas:
|
||||
log_pagina = log_paginas
|
||||
logboek, log_totaal = service.recent_log(log_pagina, grootte)
|
||||
except Exception:
|
||||
actief, logboek, log_totaal, log_pagina, log_paginas, per = [], [], 0, 1, 1, LOG_PER_PAGINA
|
||||
|
||||
lijst, lijst_fout = None, None
|
||||
if tab == 'lijst':
|
||||
try:
|
||||
lijst = service.niet_ingesteld(force=request.args.get('vernieuw') == '1')
|
||||
lijst_fout = service.ou_melding() # sommige OU's bestaan niet: lijst tonen + waarschuwing
|
||||
except TweestapsError as e:
|
||||
lijst_fout = str(e)
|
||||
except Exception as e:
|
||||
lijst_fout = TweestapsService._friendly(e)
|
||||
|
||||
return render_template('tweestaps.html', tab=tab, zoek=zoek, zoekresultaten=zoekresultaten,
|
||||
gebruiker=gebruiker, uitzondering=uitzondering, reset_wacht=reset_wacht, codes=codes, code_actie=code_actie,
|
||||
fout=fout, actief=actief, logboek=logboek, log_totaal=log_totaal, log_pagina=log_pagina, log_per=per, log_keuzes=LOG_KEUZES,
|
||||
log_paginas=log_paginas, lijst=lijst, lijst_fout=lijst_fout,
|
||||
einde=service.einde_vandaag(), groep=service.exception_group,
|
||||
ous=Config.TWEESTAPS_OUS, nu=datetime.now())
|
||||
|
||||
|
||||
@tweestaps_bp.route('/', methods=['GET'])
|
||||
@login_required
|
||||
@recht_vereist('tweestaps_codes', 'tweestaps_uitzetten')
|
||||
def overzicht():
|
||||
_ensure_tables()
|
||||
return _render()
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
# Back-upcodes
|
||||
#---------------------------------------------
|
||||
@tweestaps_bp.route('/codes', methods=['POST'])
|
||||
@login_required
|
||||
@recht_vereist('tweestaps_codes')
|
||||
def codes():
|
||||
_ensure_tables()
|
||||
email = request.form.get('email', '')
|
||||
actie = request.form.get('actie', 'tonen')
|
||||
door = session.get('user')
|
||||
try:
|
||||
user = service.get_user(email)
|
||||
if actie == 'ongeldig':
|
||||
service.invalidate_codes(user['email'])
|
||||
service.log(door, 'codes ongeldig gemaakt', user['email'])
|
||||
flash(f"Alle back-upcodes van {user['email']} zijn ongeldig gemaakt.", "success")
|
||||
return redirect(url_for('tweestaps.overzicht', email=user['email']))
|
||||
|
||||
bestaand = [] if actie == 'nieuw' else service.list_codes(user['email'])
|
||||
if bestaand:
|
||||
lijst = bestaand
|
||||
service.log(door, 'code getoond', user['email'])
|
||||
else:
|
||||
lijst = service.generate_codes(user['email'])
|
||||
service.log(door, 'nieuwe codes', user['email'], f"{len(lijst)} codes")
|
||||
return _render(email=user['email'], codes=lijst, code_actie='nieuw' if not bestaand else 'bestaand')
|
||||
except TweestapsError as e:
|
||||
return _render(email=email, fout=str(e))
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
# Tijdelijke uitzondering
|
||||
#---------------------------------------------
|
||||
@tweestaps_bp.route('/uitzondering', methods=['POST'])
|
||||
@login_required
|
||||
@recht_vereist('tweestaps_uitzetten')
|
||||
def uitzondering():
|
||||
_ensure_tables()
|
||||
email = request.form.get('email', '')
|
||||
reden = (request.form.get('reden') or '').strip()
|
||||
eindtijd = service.einde_vandaag()
|
||||
try:
|
||||
user = service.grant_exception(email, eindtijd, session.get('user'), reden)
|
||||
flash(f"{user['email']} kan tot {eindtijd:%H:%M} zonder 2FA inloggen. Daarna zet PIVOT 2FA automatisch "
|
||||
"terug aan. Let op: het kan enkele minuten duren voor Google de uitzondering toepast.", "success")
|
||||
except TweestapsError as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for('tweestaps.overzicht', email=email.strip()))
|
||||
|
||||
|
||||
@tweestaps_bp.route('/reset', methods=['POST'])
|
||||
@login_required
|
||||
@recht_vereist('tweestaps_uitzetten')
|
||||
def reset():
|
||||
"""2FA resetten voor iemand met een nieuwe of verloren telefoon."""
|
||||
_ensure_tables()
|
||||
email = request.form.get('email', '')
|
||||
eindtijd = service.einde_vandaag()
|
||||
try:
|
||||
user = service.reset_2fa(email, eindtijd, session.get('user'), (request.form.get('reden') or '').strip())
|
||||
if user.get('wacht'):
|
||||
flash(f"{user['email']} staat nu in de uitzonderingsgroep, maar Google past dat pas na enkele minuten toe. "
|
||||
"PIVOT probeert de 2FA-reset elke minuut opnieuw (tot de uitzondering afloopt om "
|
||||
f"{eindtijd:%H:%M}). Je hoeft niets meer te doen; vernieuw deze pagina om de status te zien.", "info")
|
||||
return redirect(url_for('tweestaps.overzicht', email=email.strip()))
|
||||
tekst = f"2FA is uitgezet voor {user['email']}. Hij kan nu inloggen en 2FA opnieuw instellen met zijn nieuwe telefoon"
|
||||
if user.get('uitzondering'):
|
||||
tekst += f" (vóór {eindtijd:%H:%M}; daarna is 2FA weer verplicht)"
|
||||
flash(tekst + ". Het kan enkele minuten duren voor Google dit toepast.", "success")
|
||||
except TweestapsError as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for('tweestaps.overzicht', email=email.strip()))
|
||||
|
||||
|
||||
@tweestaps_bp.route('/uitzondering/<int:uitz_id>/stop', methods=['POST'])
|
||||
@login_required
|
||||
@recht_vereist('tweestaps_uitzetten')
|
||||
def stop_uitzondering(uitz_id):
|
||||
_ensure_tables()
|
||||
try:
|
||||
email = service.end_exception(uitz_id, session.get('user'))
|
||||
flash(f"2FA is opnieuw verplicht voor {email}.", "success")
|
||||
except TweestapsError as e:
|
||||
flash(str(e), "error")
|
||||
terug = request.form.get('terug')
|
||||
return redirect(url_for('tweestaps.overzicht', email=terug) if terug else url_for('tweestaps.overzicht'))
|
||||
Reference in new issue
Block a user