UX: Minor fixes to passkey handling (#23947)
- don't try to guess the name of the manager (too many options) - improve error message when registration is not allowed - output error in console when registration fails - minor fix to rename dialog layout - hides action buttons in DiscourseHub (because adding passkeys there is not possible) - adds acceptance test to ensure action buttons are hidden for admins seeing another user's profile
This commit is contained in:
parent
585bb0df27
commit
a125c9e63e
|
@ -25,20 +25,11 @@ export default class UserPasskeys extends Component {
|
|||
lastUsedPrefix = I18n.t("user.passkeys.last_used_prefix");
|
||||
neverUsed = I18n.t("user.passkeys.never_used");
|
||||
|
||||
isCurrentUser() {
|
||||
return this.currentUser.id === this.args.model.id;
|
||||
}
|
||||
|
||||
passkeyDefaultName() {
|
||||
if (this.capabilities.isSafari) {
|
||||
return I18n.t("user.passkeys.name.icloud_keychain");
|
||||
}
|
||||
|
||||
if (this.capabilities.isAndroid || this.capabilities.isChrome) {
|
||||
return I18n.t("user.passkeys.name.google_password_manager");
|
||||
}
|
||||
|
||||
return I18n.t("user.passkeys.name.default");
|
||||
get showActions() {
|
||||
return (
|
||||
this.currentUser.id === this.args.model.id &&
|
||||
!this.capabilities.isAppWebview
|
||||
);
|
||||
}
|
||||
|
||||
async createPasskey() {
|
||||
|
@ -89,7 +80,7 @@ export default class UserPasskeys extends Component {
|
|||
type: credential.type,
|
||||
attestation: bufferToBase64(credential.response.attestationObject),
|
||||
clientData: bufferToBase64(credential.response.clientDataJSON),
|
||||
name: this.passkeyDefaultName(),
|
||||
name: I18n.t("user.passkeys.name.default"),
|
||||
};
|
||||
|
||||
const registrationResponse = await this.args.model.registerPasskey(
|
||||
|
@ -111,6 +102,8 @@ export default class UserPasskeys extends Component {
|
|||
bodyComponentModel: registrationResponse,
|
||||
});
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
this.errorMessage =
|
||||
error.name === "InvalidStateError"
|
||||
? I18n.t("user.passkeys.already_added_error")
|
||||
|
@ -221,7 +214,7 @@ export default class UserPasskeys extends Component {
|
|||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{#if this.isCurrentUser}}
|
||||
{{#if this.showActions}}
|
||||
<div class="passkey-right">
|
||||
<div class="actions">
|
||||
<PasskeyOptionsDropdown
|
||||
|
@ -239,15 +232,15 @@ export default class UserPasskeys extends Component {
|
|||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="controls pref-passkeys__add">
|
||||
{{#if this.isCurrentUser}}
|
||||
{{#if this.showActions}}
|
||||
<div class="controls pref-passkeys__add">
|
||||
<DButton
|
||||
@action={{this.addPasskey}}
|
||||
@icon="plus"
|
||||
@label="user.passkeys.add_passkey"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -177,4 +177,33 @@ acceptance("User Preferences - Security", function (needs) {
|
|||
"displays a dialog to confirm the user's identity before adding a passkey"
|
||||
);
|
||||
});
|
||||
|
||||
test("Viewing Passkeys - another user has a key", async function (assert) {
|
||||
this.siteSettings.experimental_passkeys = true;
|
||||
|
||||
// user charlie has passkeys in fixtures
|
||||
await visit("/u/charlie/preferences/security");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".pref-passkeys__rows .row-passkey__name").innerText.trim(),
|
||||
"iCloud Keychain",
|
||||
"displays the passkey name"
|
||||
);
|
||||
|
||||
assert
|
||||
.dom(".row-passkey__created-date")
|
||||
.exists("displays the created at date for the passkey");
|
||||
|
||||
assert
|
||||
.dom(".row-passkey__used-date")
|
||||
.exists("displays the last used at date for the passkey");
|
||||
|
||||
assert
|
||||
.dom(".pref-passkeys__add")
|
||||
.doesNotExist("does not show add passkey button");
|
||||
|
||||
assert
|
||||
.dom(".passkey-options-dropdown")
|
||||
.doesNotExist("does not show passkey options dropdown");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2724,6 +2724,14 @@ export default {
|
|||
text_size_seq: 0,
|
||||
timezone: "America/Los_Angeles",
|
||||
},
|
||||
user_passkeys: [
|
||||
{
|
||||
id: 2,
|
||||
name: "iCloud Keychain",
|
||||
last_used: "2023-10-10T20:03:20.986Z",
|
||||
created_at: "2023-10-09T20:01:37.578Z",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"/u/charlie/card.json": {
|
||||
|
|
|
@ -806,3 +806,8 @@
|
|||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.rename-passkey__message {
|
||||
max-width: 500px;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
|
|
@ -1518,15 +1518,13 @@ en:
|
|||
rename_passkey_instructions: "Pick a passkey name that will easily identify it for you, for example, use the name of your password manager."
|
||||
name:
|
||||
default: "Main Passkey"
|
||||
google_password_manager: "Google Password Manager"
|
||||
icloud_keychain: "iCloud Keychain"
|
||||
save: "Save"
|
||||
title: "Passkeys"
|
||||
short_description: "Passkeys are password replacements that validate your identity biometrically (e.g. touch, faceID) or via a device PIN/password."
|
||||
added_prefix: "Added"
|
||||
last_used_prefix: "Last Used"
|
||||
never_used: "Never Used"
|
||||
not_allowed_error: "The passkey registration process either timed out or was cancelled."
|
||||
not_allowed_error: "The passkey registration process either timed out, was cancelled or is not allowed."
|
||||
already_added_error: "You have already registered this passkey. You don’t have to register it again."
|
||||
|
||||
change_about:
|
||||
|
|
Loading…
Reference in New Issue