diff --git a/app/assets/javascripts/discourse/app/components/user-preferences/user-passkeys.gjs b/app/assets/javascripts/discourse/app/components/user-preferences/user-passkeys.gjs
index 24beeac950e..4939a6d0ecf 100644
--- a/app/assets/javascripts/discourse/app/components/user-preferences/user-passkeys.gjs
+++ b/app/assets/javascripts/discourse/app/components/user-preferences/user-passkeys.gjs
@@ -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}}
- {{#if this.isCurrentUser}}
+ {{#if this.showActions}}
-
- {{#if this.isCurrentUser}}
+ {{#if this.showActions}}
+
- {{/if}}
-
+
+ {{/if}}
}
diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-security-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-security-test.js
index 436f28241ce..5adb555dbea 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-security-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-security-test.js
@@ -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");
+ });
});
diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
index 464b039152e..0a33b87519b 100644
--- a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
+++ b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
@@ -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": {
diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss
index 59f43e70c70..989282a71b8 100644
--- a/app/assets/stylesheets/common/base/modal.scss
+++ b/app/assets/stylesheets/common/base/modal.scss
@@ -806,3 +806,8 @@
max-width: 500px;
}
}
+
+.rename-passkey__message {
+ max-width: 500px;
+ margin-bottom: 2em;
+}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 1d58ccdb590..4b1b97fdf40 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -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: