feat(2fa): rezervni (jednokratni) kodovi za 2FA
Alternativa TOTP-u kada uređaj nije dostupan. Po CLAUDE.md specifikaciji: 10 kodova pri aktivaciji, čuvani kao bcrypt heš. Backend: - migracija 039 (tabela rezervni_kodovi, FK CASCADE) - auth.GenerisiRezervneKodove (Crockford base32, XXXX-XXXX) + NormalizujRezervniKod - RezervniKodoviRepository (Zameni/Iskoristi/BrojPreostalih/Obrisi) + SQLite impl - žičenje u Handler (+ reinicijalizuj) Prijava: - VerifikujTotp prvo proba TOTP, pa rezervni kod (isto polje); kod je jednokratni - totp_provera.html: input opušten (slova/crtica), napomena o rezervnom kodu Profil: - aktivacija generiše i prikazuje kodove JEDNOM; dugme Regeneriši; brojač preostalo X/10 - deaktivacija briše kodove Testovi: auth (generisanje/format/normalizacija), repo (jednokratnost/regeneracija), prijava rezervnim kodom end-to-end. Ukupno 36 test funkcija.
This commit is contained in:
@@ -77,6 +77,23 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Rezervni (jednokratni) kodovi -->
|
||||
<div style="margin-top: 18px; padding-top: 16px; border-top: 0.5px solid var(--ivica)">
|
||||
{{ if .RezervniKodovi }}
|
||||
<div class="poruka-uspeh" style="margin-bottom: 12px">Sačuvajte ove rezervne kodove na sigurno mesto — prikazuju se samo sada. Svaki se može upotrebiti jednom, umesto koda iz aplikacije.</div>
|
||||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 14px; max-width: 360px">
|
||||
{{ range .RezervniKodovi }}
|
||||
<code style="font-size: 14px; background: var(--pozadina); padding: 8px 10px; border-radius: 6px; text-align: center; letter-spacing: 1px; color: var(--tekst-glavni)">{{ . }}</code>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ else }}
|
||||
<div style="font-size: 13px; color: var(--tekst-sporedni); margin-bottom: 10px">Rezervni kodovi: preostalo <strong>{{ .BrojRezervnih }}</strong>. Koriste se za prijavu kada nemate pristup aplikaciji sa kodovima.</div>
|
||||
{{ end }}
|
||||
<form method="POST" action="/admin/profil/totp/kodovi" onsubmit="return confirm('Generisati nove rezervne kodove? Stari kodovi više neće važiti.');">
|
||||
<button type="submit" style="padding: 8px 16px; background: transparent; color: var(--sb-akcent); border: 1px solid var(--sb-akcent); border-radius: 8px; font-size: 13px; font-weight: 500; cursor: pointer">Regeneriši rezervne kodove</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{ else }}
|
||||
<!-- 2FA nije uključena -->
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px">
|
||||
|
||||
Reference in New Issue
Block a user