06/03 Optimize app
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Enable Two-Factor Auth{% endblock %}
|
||||
{% block page_title %}Enable Two-Factor Authentication{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-8 col-lg-6">
|
||||
|
||||
<div class="pcard mb-3">
|
||||
<div class="d-flex align-items-center gap-3 mb-4">
|
||||
<div style="width:44px;height:44px;border-radius:11px;background:#ede9fe;color:#5b21b6;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">
|
||||
<i class="bi bi-shield-lock-fill"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight:700;font-size:15px;">Authenticator App Setup</div>
|
||||
<div style="font-size:12px;color:var(--muted);">Scan the QR code with Google Authenticator, Authy, or any TOTP app.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="mb-4">
|
||||
<div style="font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:10px;">Step 1 — Scan QR code</div>
|
||||
<div class="text-center">
|
||||
<img src="{{ qr_data }}" alt="TOTP QR code" style="width:200px;height:200px;border:1px solid var(--border);border-radius:8px;padding:8px;background:#fff;">
|
||||
</div>
|
||||
<div class="mt-3 p-3" style="background:#f8fafc;border-radius:8px;font-size:12px;">
|
||||
<div style="color:var(--muted);margin-bottom:4px;">Can't scan? Enter this key manually:</div>
|
||||
<code class="mono" style="font-size:14px;font-weight:700;letter-spacing:.1em;word-break:break-all;">{{ secret }}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div>
|
||||
<div style="font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:10px;">Step 2 — Confirm with a code</div>
|
||||
<form method="POST" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="d-flex gap-2">
|
||||
<input type="text" name="code" inputmode="numeric" pattern="[0-9 ]*"
|
||||
maxlength="7" autofocus
|
||||
class="form-control mono text-center"
|
||||
style="font-size:22px;font-weight:700;letter-spacing:.15em;"
|
||||
placeholder="000000">
|
||||
<button type="submit" class="btn btn-primary" style="white-space:nowrap;">
|
||||
Enable 2FA
|
||||
</button>
|
||||
</div>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:6px;">
|
||||
Enter the current 6-digit code shown in your authenticator app to confirm setup.
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<a href="{{ url_for('settings.index') }}" class="btn btn-outline-secondary btn-sm">Cancel</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,41 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Two-Factor Verification{% endblock %}
|
||||
{% block page_title %}Two-Factor Verification{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-12 col-sm-8 col-md-5 col-lg-4">
|
||||
<div class="pcard">
|
||||
<div class="text-center mb-4">
|
||||
<div style="width:56px;height:56px;border-radius:14px;background:#ede9fe;color:#5b21b6;display:flex;align-items:center;justify-content:center;font-size:26px;margin:0 auto 12px;">
|
||||
<i class="bi bi-shield-lock-fill"></i>
|
||||
</div>
|
||||
<h5 style="font-weight:700;">Verify your identity</h5>
|
||||
<p class="text-muted" style="font-size:13px;">Enter the 6-digit code from your authenticator app.</p>
|
||||
</div>
|
||||
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" style="font-size:13px;">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="POST" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="mb-3">
|
||||
<input type="text" name="code" inputmode="numeric" pattern="[0-9 ]*"
|
||||
maxlength="7" autofocus
|
||||
class="form-control text-center mono"
|
||||
style="font-size:28px;font-weight:700;letter-spacing:.2em;"
|
||||
placeholder="000000">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Verify</button>
|
||||
</form>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ url_for('auth.login') }}" style="font-size:12px;color:var(--muted);">
|
||||
← Back to login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -18,6 +18,15 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if schwab_warning %}
|
||||
<div class="alert alert-warning d-flex align-items-center gap-2 mb-3" style="font-size:13px;">
|
||||
<i class="bi bi-exclamation-triangle-fill flex-shrink-0"></i>
|
||||
<div>
|
||||
{{ schwab_warning }}
|
||||
<a href="{{ url_for('schwab.connect') }}" class="alert-link ms-1">Reconnect now →</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="d-flex align-items-start align-items-sm-center justify-content-between flex-wrap gap-2 mb-4">
|
||||
<div>
|
||||
<h5 class="mb-0 fw-semibold">{{ period_label }}</h5>
|
||||
|
||||
@@ -61,6 +61,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Two-Factor Authentication -->
|
||||
<div class="row g-3 mt-1">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="pcard h-100">
|
||||
<div class="d-flex align-items-center gap-2 mb-3">
|
||||
<i class="bi bi-shield-lock-fill" style="font-size:1.3rem;color:#5b21b6;"></i>
|
||||
<span class="pcard-title mb-0">Two-Factor Authentication (2FA)</span>
|
||||
{% if current_user.totp_enabled %}
|
||||
<span class="badge ms-auto" style="background:#d1fae5;color:#065f46;font-size:11px;">Enabled</span>
|
||||
{% else %}
|
||||
<span class="badge ms-auto" style="background:#fee2e2;color:#991b1b;font-size:11px;">Disabled</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if current_user.totp_enabled %}
|
||||
<p style="font-size:13px;color:var(--muted);">
|
||||
2FA is active. Each login requires a 6-digit code from your authenticator app.
|
||||
</p>
|
||||
<form method="POST" action="{{ url_for('auth.totp_disable') }}"
|
||||
onsubmit="return confirm('Disable two-factor authentication?\nYou will only need a password to log in.')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="mb-2">
|
||||
<input type="password" name="password" class="form-control form-control-sm"
|
||||
placeholder="Confirm your password" required style="max-width:280px;">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">
|
||||
<i class="bi bi-shield-x me-1"></i>Disable 2FA
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p style="font-size:13px;color:var(--muted);">
|
||||
Protect your account with a time-based one-time password (TOTP).
|
||||
Use Google Authenticator, Authy, or any compatible app.
|
||||
</p>
|
||||
<a href="{{ url_for('auth.totp_setup') }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-shield-plus me-1"></i>Enable 2FA
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Maintenance + Email Alerts -->
|
||||
<div class="row g-3 mt-1">
|
||||
<div class="col-12 col-md-6">
|
||||
|
||||
Reference in New Issue
Block a user