Credential update tweaks (#2475)

* Make the Credential Update page more user-friendly
This commit is contained in:
illode 2024-02-06 03:36:22 +00:00 committed by GitHub
parent cd27879e7f
commit 8cd62d4d4a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 86 additions and 45 deletions

View file

@ -33,8 +33,10 @@
- philipcristiano
- Jianchen Zhao (bolu61)
- Allan Zhang (allan2)
- illode
- Jinna Kiisuo (jinnatar)
## Acknowledgements
- M. Gerstner

View file

@ -178,7 +178,7 @@ impl Component for CreateResetCode {
})
}
>
{ "Update your Authentication Settings on Another Device" }
{ "Add another device to your account" }
</button>
<div class="modal" tabindex="-1" role="dialog" id={ID_CRED_RESET_CODE}>
<div class="modal-dialog modal-lg" role="document">

View file

@ -227,7 +227,7 @@ impl ProfileApp {
})
}
>
{ "Password and Authentication Settings" }
{ "Authentication Settings" }
</button>
</p>
</div>

View file

@ -376,8 +376,8 @@ impl CredentialResetApp {
attested_passkeys_allowed_devices,
} = status;
let displayname = displayname.clone();
let spn = spn.clone();
let (username, domain) = spn.split_once('@').unwrap_or(("", &spn));
let names = format!("{} ({})", displayname, username);
let cb = self.cb.clone();
let ext_cred_portal_html = match ext_cred_portal {
@ -421,7 +421,7 @@ impl CredentialResetApp {
match warning {
CURegWarning::MfaRequired => html! {
<div class="alert alert-warning" role="alert">
<p>{ "MFA is required for your account. Add TOTP or remove your password in favour of Passkeys." }</p>
<p>{ "Multi-Factor Authentication is required for your account. Either add TOTP or remove your password in favour of passkeys to submit." }</p>
</div>
},
CURegWarning::PasskeyRequired => html! {
@ -464,8 +464,8 @@ impl CredentialResetApp {
<main class="w-100">
<div class="py-3 text-center">
<h3>{ "Updating Credentials" }</h3>
<p>{ displayname }</p>
<p>{ spn }</p>
<p>{ names }</p>
<p>{ domain }</p>
</div>
<div class="row g-3">
@ -524,7 +524,7 @@ impl CredentialResetApp {
let cb = self.cb.clone();
// match on primary, get type_.
let pw_html_inner = if matches!(primary_state, CUCredState::Modifiable) {
let alt_auth_method_inner = if matches!(primary_state, CUCredState::Modifiable) {
match primary {
Some(CredentialDetail {
uuid: _,
@ -532,21 +532,21 @@ impl CredentialResetApp {
}) => {
html! {
<>
<p>{ "Password Set" }</p>
<h6> <b>{ "Password" }</b> </h6>
<p>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticPassword">
{ "Change Password" }
</button>
</p>
<p>{ "❌ MFA Disabled" }</p>
<h6> <b>{ "Time-based One Time Password (TOTP)" }</b> </h6>
<p>{ "TOTPs are 6 digit codes generated on-demand as a second authentication factor."}</p>
<p>
<TotpModalApp token={ token.clone() } cb={ cb.clone() }/>
</p>
<br/>
<p>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#staticDeletePrimaryCred">
{ "Delete this Insecure Password" }
{ "Delete Alternative Credentials" }
</button>
</p>
</>
@ -566,15 +566,15 @@ impl CredentialResetApp {
}) => {
html! {
<>
<p>{ "Password Set" }</p>
<h6> <b>{ "Password" }</b> </h6>
<p>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticPassword">
{ "Change Password" }
</button>
</p>
<p>{ "✅ MFA Enabled" }</p>
<br/>
<h6> <b>{ "Time-based One Time Password (TOTP)" }</b></h6>
<p>{ "TOTPs are 6 digit codes generated on-demand as a second authentication factor."}</p>
<>
{ for totp_set.iter()
.map(|detail| html! { <TotpRemoveComp token={ token.clone() } label={ detail.clone() } cb={ cb.clone() } /> })
@ -584,10 +584,11 @@ impl CredentialResetApp {
<p>
<TotpModalApp token={ token.clone() } cb={ cb.clone() }/>
</p>
<br/>
<br/>
<p>
<button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#staticDeletePrimaryCred">
{ "Delete this Legacy MFA Credential" }
{ "Delete Alternative Credentials" }
</button>
</p>
@ -600,9 +601,10 @@ impl CredentialResetApp {
}) => {
html! {
<>
<p>{ "Generated Password" }</p>
<h6> <b>{ "Password" }</b> </h6>
<p>{ "In order to set up alternative authentication methods, you must delete the generated password." }</p>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#staticDeletePrimaryCred">
{ "Delete this Password" }
{ "Delete Generated Password" }
</button>
</>
}
@ -613,9 +615,9 @@ impl CredentialResetApp {
}) => {
html! {
<>
<p>{ "Webauthn Only - Will migrate to Passkeys in a future update" }</p>
<p>{ "Webauthn Only - Will migrate to passkeys in a future update" }</p>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#staticDeletePrimaryCred">
{ "Delete this Credential" }
{ "Delete Alternative Credentials" }
</button>
</>
}
@ -632,7 +634,7 @@ impl CredentialResetApp {
html! {
<p>
<button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#staticDeletePrimaryCred">
{ "Delete this Legacy Credential" }
{ "Delete Legacy Credentials" }
</button>
</p>
}
@ -640,38 +642,44 @@ impl CredentialResetApp {
html! {<></>}
};
let pw_warn = match primary_state {
let alt_auth_method_warning = match primary_state {
CUCredState::Modifiable => {
html! {
<>
<p>{ "Legacy password paired with other authentication factors." }</p>
<p>{ "It is recommended you avoid setting these if possible, as these can be phished or exploited." }</p>
<p>{ "If possible, passkeys should be used instead, as they are phishing and exploit resistant." }</p>
</>
}
}
CUCredState::DeleteOnly => {
html! {
<>
<p>{ "Legacy password paired with other authentication factors." }</p>
<p>{ "Account policy prevents you modifying this credential, but you may remove it." }</p>
<p>{ "If possible, passkeys should be used instead, as they are phishing and exploit resistant." }</p>
<p>{ "Account policy prevents you modifying these credentials, but you may remove them." }</p>
</>
}
}
CUCredState::AccessDeny => {
html! { <><p> { "You do not have access to modify the Password or TOTP tokens of this account" }</p></> }
html! {
<>
<p>{ "You do not have access to modify these credentials." }</p>
</>
}
}
CUCredState::PolicyDeny => {
html! { <><p> { "Account policy prevents you setting the Password or TOTP tokens of this account" }</p></> }
html! {
<>
<p>{ "Account policy prevents you from setting these credentials" }</p>
</>
}
}
};
html! {
<>
<hr class="my-4" />
<h4>{"Password / TOTP"}</h4>
{ pw_warn }
{ pw_html_inner }
<h4>{"Alternative Authentication Methods" }</h4>
{ alt_auth_method_warning }
{ alt_auth_method_inner }
<PwModalApp token={ token.clone() } cb={ cb } />
</>
@ -693,13 +701,17 @@ impl CredentialResetApp {
<hr class="my-4" />
<h4>{"Passkeys"}</h4>
<p>{ "Strong cryptographic authenticators with self contained multi-factor authentication." }</p>
{ if passkeys.is_empty() {
html! { <p>{ "No Passkeys Registered" }</p> }
} else {
html! { <></> }
} }
<p>{ "Easy to use digital credentials with self-contained multi-factor authentication designed to replace passwords." }</p>
<p>
<a target="_blank" href="https://support.microsoft.com/en-us/windows/passkeys-in-windows-301c8944-5ea2-452b-9886-97e4d2ef4422">{ "Windows" }</a>
{ ", " }
<a target="_blank" href="https://support.apple.com/guide/mac-help/create-a-passkey-mchl4af65d1a/mac">{ "MacOS" }</a>
{ ", " }
<a target="_blank" href="https://support.google.com/android/answer/14124480?hl=en">{ "Android" }</a>
{ ", and " }
<a target="_blank" href="https://support.apple.com/guide/iphone/use-passkeys-to-sign-in-to-apps-and-websites-iphf538ea8d0/ios">{ "iOS" }</a>
{ " have built-in support for passkeys."}
</p>
{ for passkeys.iter()
.map(|detail|
@ -744,8 +756,6 @@ impl CredentialResetApp {
<>
<hr class="my-4" />
<h4>{"Attested Passkeys"}</h4>
{ if attested_passkeys.is_empty() { html! { <p> { "No Passkeys Registered" } </p> } } else { html! {<></>} } }
{ for attested_passkeys.iter()
.map(|detail|
PasskeyRemoveModalApp::render_button(&detail.tag, detail.uuid)

View file

@ -357,6 +357,35 @@ impl Component for TotpModalApp {
</div>
</div>
<p> { "An authentication app is needed to generate TOTP codes"}
<ul>
<li>
<a target="_blank" href="https://support.apple.com/en-in/guide/iphone/ipha6173c19f/ios">{ "Built-in iOS TOTP generator" }</a>
</li>
<li>{ "Google Authenticator" }
{ " (" }
<a target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">{ "Android" }</a>
{ " / " }
<a target="_blank" href="https://apps.apple.com/app/google-authenticator/id388497605">{ "iOS" }</a>
{ ")" }
</li>
<li>{ "Microsoft Authenticator"}
{ " (" }
<a target="_blank" href="https://play.google.com/store/apps/details?id=com.azure.authenticator">{ "Android" }</a>
{ " / " }
<a target="_blank" href="https://apps.apple.com/us/app/microsoft-authenticator/id983156458">{ "iOS" }</a>
{ ")" }
</li>
<li>{ "FreeOTP"}
{ " (" }
<a target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">{ "Android" }</a>
{ " / " }
<a target="_blank" href="https://apps.apple.com/us/app/freeotp-authenticator/id872559395">{ "iOS" }</a>
{ ")" }
</li>
</ul>
</p>
{
match &self.secret {
TotpValue::Secret(secret) => {

View file

@ -225,7 +225,7 @@ impl ProfileApp {
})
}
>
{ "Password and Authentication Settings" }
{ "Authentication Settings" }
</button>
</p>
</div>