Skip to content

Commit

Permalink
Add multi-factor authentication (MFA) support; update localization an…
Browse files Browse the repository at this point in the history
…d error handling
  • Loading branch information
seanmorley15 committed Dec 14, 2024
1 parent 1b54f8e commit 9bf0849
Show file tree
Hide file tree
Showing 15 changed files with 369 additions and 68 deletions.
1 change: 1 addition & 0 deletions backend/server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ django-resized
django-geojson
setuptools
gunicorn==23.0.0
qrcode==8.0
# slippers==0.6.2
# django-allauth-ui==1.5.1
# django-widget-tweaks==1.5.0
31 changes: 12 additions & 19 deletions frontend/src/lib/components/TOTPModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,10 @@
}
async function sendTotp() {
console.log('sending totp');
let sessionid = document.cookie
.split('; ')
.find((row) => row.startsWith('sessionid'))
?.split('=')[1];
const res = await fetch('/_allauth/browser/v1/account/authenticators/totp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Cookie: `sessionid=${sessionid}`
'Content-Type': 'application/json'
},
body: JSON.stringify({
code: first_code
Expand All @@ -73,7 +65,7 @@
});
console.log(res);
if (res.ok) {
addToast('success', '2FA enabled');
addToast('success', $t('settings.mfa_enabled'));
is_enabled = true;
getRecoveryCodes();
} else {
Expand Down Expand Up @@ -125,10 +117,10 @@
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">Enable 2FA</h3>
<h3 class="font-bold text-lg">{$t('settings.enable_mfa')}</h3>

{#if qrCodeDataUrl}
<div class="mb-4 flex items-center justify-center">
<div class="mb-4 flex items-center justify-center mt-2">
<img src={qrCodeDataUrl} alt="QR Code" class="w-64 h-64" />
</div>
{/if}
Expand All @@ -141,28 +133,29 @@
class="input input-bordered w-full max-w-xs"
readonly
/>
<button class="btn btn-primary ml-2" on:click={() => copyToClipboard(secret)}>Copy</button
<button class="btn btn-primary ml-2" on:click={() => copyToClipboard(secret)}
>{$t('settings.copy')}</button
>
</div>
{/if}
</div>

<input
type="text"
placeholder="Authenticator Code"
placeholder={$t('settings.authenticator_code')}
class="input input-bordered w-full max-w-xs"
bind:value={first_code}
/>

<div class="recovery-codes-container">
{#if recovery_codes.length > 0}
<h3 class="mt-4 text-center font-bold text-lg">Recovery Codes</h3>
<h3 class="mt-4 text-center font-bold text-lg">{$t('settings.recovery_codes')}</h3>
<p class="text-center text-lg mb-2">
These are your recovery codes. Keep them safe. You will not be able to see them again.
{$t('settings.recovery_codes_desc')}
</p>
<button
class="btn btn-primary ml-2"
on:click={() => copyToClipboard(recovery_codes.join(', '))}>Copy</button
on:click={() => copyToClipboard(recovery_codes.join(', '))}>{$t('settings.copy')}</button
>
{/if}
<div class="recovery-codes-grid flex flex-wrap">
Expand All @@ -178,12 +171,12 @@

{#if reauthError}
<div class="alert alert-error mt-4">
Please logout and back in to refresh your session and try again.
{$t('settings.reset_session_error')}
</div>
{/if}

{#if !is_enabled}
<button class="btn btn-primary mt-4" on:click={sendTotp}>Enable 2FA</button>
<button class="btn btn-primary mt-4" on:click={sendTotp}>{$t('settings.enable_mfa')}</button>
{/if}

<button class="btn btn-primary mt-4" on:click={close}>{$t('about.close')}</button>
Expand Down
46 changes: 42 additions & 4 deletions frontend/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@
"add_a_tag": "Fügen Sie ein Tag hinzu",
"tags": "Schlagworte",
"set_to_pin": "Auf „Anpinnen“ setzen",
"category_fetch_error": "Fehler beim Abrufen der Kategorien"
"category_fetch_error": "Fehler beim Abrufen der Kategorien",
"copied_to_clipboard": "In die Zwischenablage kopiert!",
"copy_failed": "Das Kopieren ist fehlgeschlagen"
},
"home": {
"desc_1": "Entdecken, planen und erkunden Sie mit Leichtigkeit",
Expand Down Expand Up @@ -234,7 +236,8 @@
"my_tags": "Meine Tags",
"tag": "Etikett",
"language_selection": "Sprache",
"support": "Unterstützung"
"support": "Unterstützung",
"calendar": "Kalender"
},
"auth": {
"confirm_password": "Passwort bestätigen",
Expand All @@ -250,7 +253,8 @@
"username": "Benutzername",
"profile_picture": "Profilbild",
"public_profile": "Öffentliches Profil",
"public_tooltip": "Mit einem öffentlichen Profil können Benutzer Sammlungen mit Ihnen teilen und Ihr Profil auf der Benutzerseite anzeigen."
"public_tooltip": "Mit einem öffentlichen Profil können Benutzer Sammlungen mit Ihnen teilen und Ihr Profil auf der Benutzerseite anzeigen.",
"email_required": "E-Mail ist erforderlich"
},
"users": {
"no_users_found": "Keine Benutzer mit öffentlichen Profilen gefunden."
Expand Down Expand Up @@ -295,7 +299,41 @@
"photo_by": "Foto von",
"change_password_error": "Passwort kann nicht geändert werden. \nUngültiges aktuelles Passwort oder ungültiges neues Passwort.",
"current_password": "Aktuelles Passwort",
"password_change_lopout_warning": "Nach der Passwortänderung werden Sie abgemeldet."
"password_change_lopout_warning": "Nach der Passwortänderung werden Sie abgemeldet.",
"authenticator_code": "Authentifikatorcode",
"copy": "Kopie",
"disable_mfa": "Deaktivieren Sie MFA",
"email_added": "E-Mail erfolgreich hinzugefügt!",
"email_added_error": "Fehler beim Hinzufügen der E-Mail",
"email_removed": "E-Mail erfolgreich entfernt!",
"email_removed_error": "Fehler beim Entfernen der E-Mail",
"email_set_primary": "E-Mail erfolgreich als primäre E-Mail-Adresse festgelegt!",
"email_set_primary_error": "Fehler beim Festlegen der E-Mail-Adresse als primär",
"email_verified": "E-Mail erfolgreich bestätigt!",
"email_verified_erorr_desc": "Ihre E-Mail-Adresse konnte nicht bestätigt werden. \nBitte versuchen Sie es erneut.",
"email_verified_error": "Fehler bei der E-Mail-Bestätigung",
"email_verified_success": "Ihre E-Mail-Adresse wurde bestätigt. \nSie können sich jetzt anmelden.",
"enable_mfa": "Aktivieren Sie MFA",
"error_change_password": "Fehler beim Ändern des Passworts. \nBitte überprüfen Sie Ihr aktuelles Passwort und versuchen Sie es erneut.",
"generic_error": "Bei der Bearbeitung Ihrer Anfrage ist ein Fehler aufgetreten.",
"invalid_code": "Ungültiger MFA-Code",
"invalid_credentials": "Ungültiger Benutzername oder Passwort",
"make_primary": "Machen Sie primär",
"mfa_disabled": "Multi-Faktor-Authentifizierung erfolgreich deaktiviert!",
"mfa_enabled": "Multi-Faktor-Authentifizierung erfolgreich aktiviert!",
"mfa_not_enabled": "MFA ist nicht aktiviert",
"mfa_page_title": "Multi-Faktor-Authentifizierung",
"mfa_required": "Eine Multi-Faktor-Authentifizierung ist erforderlich",
"no_emai_set": "Keine E-Mail-Adresse festgelegt",
"not_verified": "Nicht verifiziert",
"primary": "Primär",
"recovery_codes": "Wiederherstellungscodes",
"recovery_codes_desc": "Dies sind Ihre Wiederherstellungscodes. \nBewahren Sie sie sicher auf. \nSie werden sie nicht mehr sehen können.",
"reset_session_error": "Bitte melden Sie sich ab und wieder an, um Ihre Sitzung zu aktualisieren, und versuchen Sie es erneut.",
"verified": "Verifiziert",
"verify": "Verifizieren",
"verify_email_error": "Fehler bei der E-Mail-Bestätigung. \nVersuchen Sie es in ein paar Minuten noch einmal.",
"verify_email_success": "E-Mail-Bestätigung erfolgreich gesendet!"
},
"checklist": {
"add_item": "Artikel hinzufügen",
Expand Down
20 changes: 19 additions & 1 deletion frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,25 @@
"make_primary": "Make Primary",
"verify": "Verify",
"no_emai_set": "No email set",
"error_change_password": "Error changing password. Please check your current password and try again."
"error_change_password": "Error changing password. Please check your current password and try again.",
"mfa_disabled": "Multi-factor authentication disabled successfully!",
"mfa_page_title": "Multi-factor Authentication",
"enable_mfa": "Enable MFA",
"disable_mfa": "Disable MFA",
"mfa_not_enabled": "MFA is not enabled",
"mfa_enabled": "Multi-factor authentication enabled successfully!",
"copy": "Copy",
"recovery_codes": "Recovery Codes",
"recovery_codes_desc": "These are your recovery codes. Keep them safe. You will not be able to see them again.",
"reset_session_error": "Please logout and back in to refresh your session and try again.",
"authenticator_code": "Authenticator Code",
"email_verified": "Email verified successfully!",
"email_verified_success": "Your email has been verified. You can now log in.",
"email_verified_error": "Error verifying email",
"email_verified_erorr_desc": "Your email could not be verified. Please try again.",
"invalid_code": "Invalid MFA code",
"invalid_credentials": "Invalid username or password",
"mfa_required": "Multi-factor authentication is required"
},
"collection": {
"collection_created": "Collection created successfully!",
Expand Down
24 changes: 22 additions & 2 deletions frontend/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,9 @@
"add_a_tag": "Agregar una etiqueta",
"tags": "Etiquetas",
"set_to_pin": "Establecer en Fijar",
"category_fetch_error": "Error al buscar categorías"
"category_fetch_error": "Error al buscar categorías",
"copied_to_clipboard": "¡Copiado al portapapeles!",
"copy_failed": "Copia fallida"
},
"worldtravel": {
"all": "Todo",
Expand Down Expand Up @@ -313,7 +315,25 @@
"verify": "Verificar",
"verify_email_error": "Error al verificar el correo electrónico. \nInténtalo de nuevo en unos minutos.",
"verify_email_success": "¡La verificación por correo electrónico se envió correctamente!",
"error_change_password": "Error al cambiar la contraseña. \nPor favor verifique su contraseña actual e inténtelo nuevamente."
"error_change_password": "Error al cambiar la contraseña. \nPor favor verifique su contraseña actual e inténtelo nuevamente.",
"disable_mfa": "Deshabilitar MFA",
"enable_mfa": "Habilitar MFA",
"mfa_disabled": "¡La autenticación multifactor se deshabilitó correctamente!",
"mfa_not_enabled": "MFA no está habilitado",
"mfa_page_title": "Autenticación multifactor",
"copy": "Copiar",
"mfa_enabled": "¡La autenticación multifactor se habilitó correctamente!",
"recovery_codes": "Códigos de recuperación",
"recovery_codes_desc": "Estos son tus códigos de recuperación. \nMantenlos a salvo. \nNo podrás volver a verlos.",
"reset_session_error": "Por favor cierre sesión y vuelva a iniciarla para actualizar su sesión e inténtelo nuevamente.",
"authenticator_code": "Código de autenticación",
"email_verified": "¡Correo electrónico verificado exitosamente!",
"email_verified_erorr_desc": "Su correo electrónico no pudo ser verificado. \nPor favor inténtalo de nuevo.",
"email_verified_error": "Error al verificar el correo electrónico",
"email_verified_success": "Su correo electrónico ha sido verificado. \nAhora puedes iniciar sesión.",
"invalid_code": "Código MFA no válido",
"invalid_credentials": "Nombre de usuario o contraseña no válidos",
"mfa_required": "Se requiere autenticación multifactor"
},
"checklist": {
"add_item": "Agregar artículo",
Expand Down
46 changes: 42 additions & 4 deletions frontend/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@
"add_a_tag": "Ajouter une balise",
"tags": "Balises",
"set_to_pin": "Définir sur Épingler",
"category_fetch_error": "Erreur lors de la récupération des catégories"
"category_fetch_error": "Erreur lors de la récupération des catégories",
"copied_to_clipboard": "Copié dans le presse-papier !",
"copy_failed": "Échec de la copie"
},
"home": {
"desc_1": "Découvrez, planifiez et explorez en toute simplicité",
Expand Down Expand Up @@ -234,7 +236,8 @@
"my_tags": "Mes balises",
"tag": "Étiqueter",
"language_selection": "Langue",
"support": "Soutien"
"support": "Soutien",
"calendar": "Calendrier"
},
"auth": {
"confirm_password": "Confirmez le mot de passe",
Expand All @@ -250,7 +253,8 @@
"username": "Nom d'utilisateur",
"profile_picture": "Photo de profil",
"public_profile": "Profil public",
"public_tooltip": "Avec un profil public, les utilisateurs peuvent partager des collections avec vous et afficher votre profil sur la page des utilisateurs."
"public_tooltip": "Avec un profil public, les utilisateurs peuvent partager des collections avec vous et afficher votre profil sur la page des utilisateurs.",
"email_required": "L'e-mail est requis"
},
"users": {
"no_users_found": "Aucun utilisateur trouvé avec des profils publics."
Expand Down Expand Up @@ -295,7 +299,41 @@
"photo_by": "Photo par",
"change_password_error": "Impossible de changer le mot de passe. \nMot de passe actuel invalide ou nouveau mot de passe invalide.",
"current_password": "Mot de passe actuel",
"password_change_lopout_warning": "Vous serez déconnecté après avoir modifié votre mot de passe."
"password_change_lopout_warning": "Vous serez déconnecté après avoir modifié votre mot de passe.",
"authenticator_code": "Code d'authentification",
"copy": "Copie",
"disable_mfa": "Désactiver MFA",
"email_added": "E-mail ajouté avec succès !",
"email_added_error": "Erreur lors de l'ajout de l'e-mail",
"email_removed": "E-mail supprimé avec succès !",
"email_removed_error": "Erreur lors de la suppression de l'e-mail",
"email_set_primary": "E-mail défini comme principal avec succès !",
"email_set_primary_error": "Erreur lors de la définition de l'adresse e-mail comme adresse principale",
"email_verified": "E-mail vérifié avec succès !",
"email_verified_erorr_desc": "Votre email n'a pas pu être vérifié. \nVeuillez réessayer.",
"email_verified_error": "Erreur lors de la vérification de l'e-mail",
"email_verified_success": "Votre email a été vérifié. \nVous pouvez maintenant vous connecter.",
"enable_mfa": "Activer l'authentification multifacteur",
"error_change_password": "Erreur lors du changement de mot de passe. \nVeuillez vérifier votre mot de passe actuel et réessayer.",
"generic_error": "Une erreur s'est produite lors du traitement de votre demande.",
"invalid_code": "Code MFA invalide",
"invalid_credentials": "Nom d'utilisateur ou mot de passe invalide",
"make_primary": "Rendre primaire",
"mfa_disabled": "Authentification multifacteur désactivée avec succès !",
"mfa_enabled": "Authentification multifacteur activée avec succès !",
"mfa_not_enabled": "MFA n'est pas activé",
"mfa_page_title": "Authentification multifacteur",
"mfa_required": "Une authentification multifacteur est requise",
"no_emai_set": "Aucune adresse e-mail définie",
"not_verified": "Non vérifié",
"primary": "Primaire",
"recovery_codes": "Codes de récupération",
"recovery_codes_desc": "Ce sont vos codes de récupération. \nGardez-les en sécurité. \nVous ne pourrez plus les revoir.",
"reset_session_error": "Veuillez vous déconnecter, puis vous reconnecter pour actualiser votre session et réessayer.",
"verified": "Vérifié",
"verify": "Vérifier",
"verify_email_error": "Erreur lors de la vérification de l'e-mail. \nRéessayez dans quelques minutes.",
"verify_email_success": "Vérification par e-mail envoyée avec succès !"
},
"checklist": {
"add_item": "Ajouter un article",
Expand Down
46 changes: 42 additions & 4 deletions frontend/src/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@
"add_a_tag": "Aggiungi un'etichetta",
"tags": "Tag",
"set_to_pin": "Imposta su Blocca",
"category_fetch_error": "Errore durante il recupero delle categorie"
"category_fetch_error": "Errore durante il recupero delle categorie",
"copied_to_clipboard": "Copiato negli appunti!",
"copy_failed": "Copia non riuscita"
},
"home": {
"desc_1": "Scopri, pianifica ed esplora con facilità",
Expand Down Expand Up @@ -234,7 +236,8 @@
"my_tags": "I miei tag",
"tag": "Etichetta",
"language_selection": "Lingua",
"support": "Supporto"
"support": "Supporto",
"calendar": "Calendario"
},
"auth": {
"confirm_password": "Conferma password",
Expand All @@ -250,7 +253,8 @@
"username": "Nome utente",
"profile_picture": "Immagine del profilo",
"public_profile": "Profilo pubblico",
"public_tooltip": "Con un profilo pubblico, gli utenti possono condividere raccolte con te e visualizzare il tuo profilo nella pagina degli utenti."
"public_tooltip": "Con un profilo pubblico, gli utenti possono condividere raccolte con te e visualizzare il tuo profilo nella pagina degli utenti.",
"email_required": "L'e-mail è obbligatoria"
},
"users": {
"no_users_found": "Nessun utente trovato con profili pubblici."
Expand Down Expand Up @@ -295,7 +299,41 @@
"photo_by": "Foto di",
"change_password_error": "Impossibile modificare la password. \nPassword attuale non valida o nuova password non valida.",
"current_password": "password attuale",
"password_change_lopout_warning": "Verrai disconnesso dopo aver modificato la password."
"password_change_lopout_warning": "Verrai disconnesso dopo aver modificato la password.",
"authenticator_code": "Codice Autenticatore",
"copy": "Copia",
"disable_mfa": "Disabilita MFA",
"email_added": "Email aggiunta con successo!",
"email_added_error": "Errore durante l'aggiunta dell'e-mail",
"email_removed": "Email rimossa con successo!",
"email_removed_error": "Errore durante la rimozione dell'e-mail",
"email_set_primary": "Email impostata come primaria con successo!",
"email_set_primary_error": "Errore durante l'impostazione dell'e-mail come principale",
"email_verified": "Email verificata con successo!",
"email_verified_erorr_desc": "Non è stato possibile verificare la tua email. \nPer favore riprova.",
"email_verified_error": "Errore durante la verifica dell'e-mail",
"email_verified_success": "La tua email è stata verificata. \nOra puoi accedere.",
"enable_mfa": "Abilita MFA",
"error_change_password": "Errore durante la modifica della password. \nControlla la tua password attuale e riprova.",
"generic_error": "Si è verificato un errore durante l'elaborazione della tua richiesta.",
"invalid_code": "Codice MFA non valido",
"invalid_credentials": "Nome utente o password non validi",
"make_primary": "Rendi primario",
"mfa_disabled": "Autenticazione a più fattori disabilitata correttamente!",
"mfa_enabled": "Autenticazione a più fattori abilitata correttamente!",
"mfa_not_enabled": "L'MFA non è abilitata",
"mfa_page_title": "Autenticazione a più fattori",
"mfa_required": "È richiesta l'autenticazione a più fattori",
"no_emai_set": "Nessuna e-mail impostata",
"not_verified": "Non verificato",
"primary": "Primario",
"recovery_codes": "Codici di ripristino",
"recovery_codes_desc": "Questi sono i tuoi codici di ripristino. \nTeneteli al sicuro. \nNon potrai vederli più.",
"reset_session_error": "Esci, effettua nuovamente l'accesso per aggiornare la sessione e riprova.",
"verified": "Verificato",
"verify_email_success": "Verifica email inviata con successo!",
"verify": "Verificare",
"verify_email_error": "Errore durante la verifica dell'e-mail. \nRiprova tra qualche minuto."
},
"checklist": {
"add_item": "Aggiungi articolo",
Expand Down
Loading

0 comments on commit 9bf0849

Please sign in to comment.