mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 19:13:26 +08:00
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");
|
lastUsedPrefix = I18n.t("user.passkeys.last_used_prefix");
|
||||||
neverUsed = I18n.t("user.passkeys.never_used");
|
neverUsed = I18n.t("user.passkeys.never_used");
|
||||||
|
|
||||||
isCurrentUser() {
|
get showActions() {
|
||||||
return this.currentUser.id === this.args.model.id;
|
return (
|
||||||
}
|
this.currentUser.id === this.args.model.id &&
|
||||||
|
!this.capabilities.isAppWebview
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async createPasskey() {
|
async createPasskey() {
|
||||||
@ -89,7 +80,7 @@ export default class UserPasskeys extends Component {
|
|||||||
type: credential.type,
|
type: credential.type,
|
||||||
attestation: bufferToBase64(credential.response.attestationObject),
|
attestation: bufferToBase64(credential.response.attestationObject),
|
||||||
clientData: bufferToBase64(credential.response.clientDataJSON),
|
clientData: bufferToBase64(credential.response.clientDataJSON),
|
||||||
name: this.passkeyDefaultName(),
|
name: I18n.t("user.passkeys.name.default"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const registrationResponse = await this.args.model.registerPasskey(
|
const registrationResponse = await this.args.model.registerPasskey(
|
||||||
@ -111,6 +102,8 @@ export default class UserPasskeys extends Component {
|
|||||||
bodyComponentModel: registrationResponse,
|
bodyComponentModel: registrationResponse,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
this.errorMessage =
|
this.errorMessage =
|
||||||
error.name === "InvalidStateError"
|
error.name === "InvalidStateError"
|
||||||
? I18n.t("user.passkeys.already_added_error")
|
? I18n.t("user.passkeys.already_added_error")
|
||||||
@ -221,7 +214,7 @@ export default class UserPasskeys extends Component {
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if this.isCurrentUser}}
|
{{#if this.showActions}}
|
||||||
<div class="passkey-right">
|
<div class="passkey-right">
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<PasskeyOptionsDropdown
|
<PasskeyOptionsDropdown
|
||||||
@ -239,15 +232,15 @@ export default class UserPasskeys extends Component {
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if this.showActions}}
|
||||||
<div class="controls pref-passkeys__add">
|
<div class="controls pref-passkeys__add">
|
||||||
{{#if this.isCurrentUser}}
|
|
||||||
<DButton
|
<DButton
|
||||||
@action={{this.addPasskey}}
|
@action={{this.addPasskey}}
|
||||||
@icon="plus"
|
@icon="plus"
|
||||||
@label="user.passkeys.add_passkey"
|
@label="user.passkeys.add_passkey"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
@ -177,4 +177,33 @@ acceptance("User Preferences - Security", function (needs) {
|
|||||||
"displays a dialog to confirm the user's identity before adding a passkey"
|
"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,
|
text_size_seq: 0,
|
||||||
timezone: "America/Los_Angeles",
|
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": {
|
"/u/charlie/card.json": {
|
||||||
|
@ -806,3 +806,8 @@
|
|||||||
max-width: 500px;
|
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."
|
rename_passkey_instructions: "Pick a passkey name that will easily identify it for you, for example, use the name of your password manager."
|
||||||
name:
|
name:
|
||||||
default: "Main Passkey"
|
default: "Main Passkey"
|
||||||
google_password_manager: "Google Password Manager"
|
|
||||||
icloud_keychain: "iCloud Keychain"
|
|
||||||
save: "Save"
|
save: "Save"
|
||||||
title: "Passkeys"
|
title: "Passkeys"
|
||||||
short_description: "Passkeys are password replacements that validate your identity biometrically (e.g. touch, faceID) or via a device PIN/password."
|
short_description: "Passkeys are password replacements that validate your identity biometrically (e.g. touch, faceID) or via a device PIN/password."
|
||||||
added_prefix: "Added"
|
added_prefix: "Added"
|
||||||
last_used_prefix: "Last Used"
|
last_used_prefix: "Last Used"
|
||||||
never_used: "Never 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."
|
already_added_error: "You have already registered this passkey. You don’t have to register it again."
|
||||||
|
|
||||||
change_about:
|
change_about:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user