From a6dcb960d73a01806724bde5e6d2931afee632fa Mon Sep 17 00:00:00 2001 From: Firstyear Date: Sun, 10 Nov 2024 14:02:27 +1000 Subject: [PATCH] UI/Feature polish (#3191) Post release some small user issues arose * Optimise the autofocus for logins with passkeys to limit clicks * Sort login mechs by strength * Fix cookies to persist between browser restarts --- proto/src/v1/auth.rs | 2 +- server/core/src/https/views/cookies.rs | 4 ++++ server/core/src/https/views/login.rs | 16 +++++++++++++--- server/core/templates/login_mech_choose.html | 1 + server/core/templates/login_webauthn.html | 8 +++----- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/proto/src/v1/auth.rs b/proto/src/v1/auth.rs index a2e3a366d..7b80d8f38 100644 --- a/proto/src/v1/auth.rs +++ b/proto/src/v1/auth.rs @@ -85,10 +85,10 @@ impl fmt::Debug for AuthCredential { pub enum AuthMech { Anonymous, Password, + PasswordBackupCode, // Now represents TOTP. #[serde(rename = "passwordmfa")] PasswordTotp, - PasswordBackupCode, PasswordSecurityKey, Passkey, } diff --git a/server/core/src/https/views/cookies.rs b/server/core/src/https/views/cookies.rs index 309191fe7..be2f817c8 100644 --- a/server/core/src/https/views/cookies.rs +++ b/server/core/src/https/views/cookies.rs @@ -37,6 +37,8 @@ pub fn make_unsigned<'a>( // then webauthn won't work anyway! token_cookie.set_domain(state.domain.clone()); token_cookie.set_path(path); + // These last forever. + token_cookie.make_permanent(); token_cookie } @@ -69,6 +71,8 @@ pub fn make_signed<'a, T: Serialize>( token_cookie.set_http_only(true); token_cookie.set_path(path); token_cookie.set_domain(state.domain.clone()); + // These last forever, we have our own internal expiration handling. + token_cookie.make_permanent(); Some(token_cookie) } diff --git a/server/core/src/https/views/login.rs b/server/core/src/https/views/login.rs index 8e3651442..ce19a26f5 100644 --- a/server/core/src/https/views/login.rs +++ b/server/core/src/https/views/login.rs @@ -99,6 +99,7 @@ struct LoginView { pub struct Mech<'a> { name: AuthMech, value: &'a str, + autofocus: bool, } #[derive(Template)] @@ -754,7 +755,7 @@ async fn view_login_step( safety -= 1; match auth_state { - AuthState::Choose(allowed) => { + AuthState::Choose(mut allowed) => { debug!("🧩 -> AuthState::Choose"); jar = add_session_cookie(&state, jar, &session_context)?; @@ -793,13 +794,22 @@ async fn view_login_step( // Render the list of options. _ => { - let mechs = allowed + allowed.sort_unstable(); + // Put strongest first. + allowed.reverse(); + + let mechs: Vec<_> = allowed .into_iter() - .map(|m| Mech { + .enumerate() + .map(|(i, m)| Mech { value: m.to_value(), name: m, + // Auto focus the first item, it's the strongest + // mechanism and the one we should optimise for. + autofocus: i == 0, }) .collect(); + LoginMechView { display_ctx, mechs }.into_response() } }; diff --git a/server/core/templates/login_mech_choose.html b/server/core/templates/login_mech_choose.html index 7fcaa920e..c9cdbe0b2 100644 --- a/server/core/templates/login_mech_choose.html +++ b/server/core/templates/login_mech_choose.html @@ -11,6 +11,7 @@
diff --git a/server/core/templates/login_webauthn.html b/server/core/templates/login_webauthn.html index 6d886d992..d5917206c 100644 --- a/server/core/templates/login_webauthn.html +++ b/server/core/templates/login_webauthn.html @@ -16,16 +16,14 @@ (% if passkey %) - -
(% else %)
- - +
(% endif %)