diff --git a/.github/scripts/parse-webauthn-metadata.py b/.github/scripts/parse-webauthn-metadata.py new file mode 100644 index 00000000000..4509ec46f7c --- /dev/null +++ b/.github/scripts/parse-webauthn-metadata.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python +# +# Parses the passkey authenticator AAGUID registry (combined_aaguid.json) and produces: +# 1. keycloak-webauthn-metadata.json — metadata consumed by the Keycloak server at runtime +# 2. Passkey icon image files — decoded from base64 data-URIs in the source +# +# The icon files are written to two directories so both the login theme and the +# account console can reference them: +# - js/apps/account-ui/public/passkeys/ +# - themes/src/main/resources/theme/base/login/resources/img/passkeys/ +# +# See services/src/main/resources/README.md for full usage instructions. + +import base64 +import json +import os +import re +import sys +import unicodedata + +REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + +ICON_DEST_DIRS = [ + os.path.join(REPO_ROOT, "js", "apps", "account-ui", "public", "passkeys"), + os.path.join(REPO_ROOT, "themes", "src", "main", "resources", "theme", "base", "login", "resources", "img", "passkeys"), +] + +METADATA_DEST = os.path.join(REPO_ROOT, "services", "src", "main", "resources", "keycloak-webauthn-metadata.json") + + +def normalize(input_str): + """Strip diacritics so authenticator names become safe ASCII filenames.""" + nfkd_form = unicodedata.normalize('NFKD', input_str) + return u"".join([c for c in nfkd_form if not unicodedata.combining(c)]) + + + +def write_file(name, data): + """Write binary data to every icon destination directory.""" + if os.sep in name or name in ('.', '..') or '/' in name or not name: + print(f"Rejecting unsafe filename: '{name}'", file=sys.stderr) + return + for dest_dir in ICON_DEST_DIRS: + os.makedirs(dest_dir, exist_ok=True) + with open(os.path.join(dest_dir, name), "wb") as f: + f.write(data) + + +def decode_base64(base64_str): + """Decode a base64 string with padding correction.""" + base64_str += "=" * ((4 - len(base64_str) % 4) % 4) + return base64.b64decode(base64_str) + + +def process_icon(icon_data_uri, short_name, flavor): + """Extract an image from a data-URI, write it to disk, and return the filename.""" + if icon_data_uri is None: + return None + + if icon_data_uri.startswith('data:image/svg+xml;base64,'): + base64_str = icon_data_uri[len('data:image/svg+xml;base64,'):] + name = short_name + "-" + flavor + ".svg" + write_file(name, decode_base64(base64_str)) + return name + elif icon_data_uri.startswith('data:image/png;base64,'): + base64_str = icon_data_uri[len('data:image/png;base64,'):] + name = short_name + "-" + flavor + ".png" + write_file(name, decode_base64(base64_str)) + return name + else: + print("Unknown data image format: " + icon_data_uri[:40], file=sys.stderr) + return None + + +def parse_aaguids(input_file): + """ + Read the given combined_aaguid.json file and produce + keycloak-webauthn-metadata.json plus decoded icon files. + """ + names = set() + files = {} + output = {} + + with open(input_file, 'r', encoding='utf-8') as f: + contents = json.load(f) + + for aaguid, info in contents.items(): + name = info.get('name') + if name is None: + continue + + # Derive a short filesystem-safe name from the authenticator name + short_name = normalize(name) + short_name = re.split(r'[^0-9a-zA-Z_\-]', short_name)[0].lower() + if not short_name: + print(f"Skipping entry with no usable name: '{name}' (AAGUID: {aaguid})", file=sys.stderr) + continue + + prefix = short_name + i = 0 + while short_name in names: + i += 1 + short_name = prefix + str(i) + names.add(short_name) + + icon_light = info.get('icon_light') + icon_dark = info.get('icon_dark') + + # Deduplicate identical icons across authenticators + if icon_light is not None and icon_light in files: + file_light = files[icon_light] + else: + file_light = process_icon(icon_light, short_name, 'light') + if icon_light is not None: + files[icon_light] = file_light + + if icon_dark is not None and icon_dark in files: + file_dark = files[icon_dark] + else: + file_dark = process_icon(icon_dark, short_name, 'dark') + if icon_dark is not None: + files[icon_dark] = file_dark + + entry = {"name": name} + if file_light is not None: + entry["icon_light"] = file_light + if file_dark is not None: + entry["icon_dark"] = file_dark + + output[aaguid] = entry + + with open(METADATA_DEST, 'w') as f: + json.dump(output, f, indent=2) + f.write('\n') + + print(f"Wrote {len(output)} entries to {METADATA_DEST}") + print(f"Icons written to: {', '.join(ICON_DEST_DIRS)}") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(1) + parse_aaguids(sys.argv[1]) diff --git a/core/src/main/java/org/keycloak/representations/account/CredentialMetadataRepresentation.java b/core/src/main/java/org/keycloak/representations/account/CredentialMetadataRepresentation.java index 3e81a3f7552..277eba2bdea 100644 --- a/core/src/main/java/org/keycloak/representations/account/CredentialMetadataRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/account/CredentialMetadataRepresentation.java @@ -12,6 +12,8 @@ public class CredentialMetadataRepresentation { LocalizedMessage warningMessageDescription; private CredentialRepresentation credential; + private String iconLight; + private String iconDark; public CredentialRepresentation getCredential() { @@ -53,4 +55,20 @@ public class CredentialMetadataRepresentation { public void setWarningMessageDescription(LocalizedMessage warningMessageDescription) { this.warningMessageDescription = warningMessageDescription; } + + public String getIconLight() { + return iconLight; + } + + public void setIconLight(String iconLight) { + this.iconLight = iconLight; + } + + public String getIconDark() { + return iconDark; + } + + public void setIconDark(String iconDark) { + this.iconDark = iconDark; + } } diff --git a/docs/documentation/release_notes/topics/26_7_0.adoc b/docs/documentation/release_notes/topics/26_7_0.adoc index e7e949407ee..823fb75c054 100644 --- a/docs/documentation/release_notes/topics/26_7_0.adoc +++ b/docs/documentation/release_notes/topics/26_7_0.adoc @@ -19,6 +19,14 @@ The `manage-realm` role continues to implicitly grant full organization manageme For per-organization granularity, organizations are now a first-class resource type in Fine-Grained Admin Permissions. Administrators can create permissions to control which specific organizations a delegated administrator can view or manage — for example, granting access to manage one organization without giving access to all organizations in the realm. When Fine-Grained Admin Permissions is enabled, organization member queries also respect user-level permissions, returning only members the administrator is permitted to view. +== Passkey authenticator icons in login and account console + +The login page and account console now display vendor-specific icons for registered passkeys and security keys. +When a user wants to authenticate with Passkeys, {project_name} shows the authenticator's icon alongside its label, making it easier to identify the correct device. + +As part of this change, the passkey authentication page in the login theme and the signing-in page in the account console were updated. +If you use a custom theme that overrides these pages, verify that your customizations work as expected with this release. + == Realm search now matches by display name When searching for realms in the admin console, the search now also matches against the realm's display name in addition to the realm name. diff --git a/js/apps/account-ui/public/passkeys/1password-dark.svg b/js/apps/account-ui/public/passkeys/1password-dark.svg new file mode 100644 index 00000000000..ff399889848 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/1password-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/1password-light.svg b/js/apps/account-ui/public/passkeys/1password-light.svg new file mode 100644 index 00000000000..dcd5b1ce0cf --- /dev/null +++ b/js/apps/account-ui/public/passkeys/1password-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/acs-light.png b/js/apps/account-ui/public/passkeys/acs-light.png new file mode 100644 index 00000000000..711639ab70a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/acs-light.png differ diff --git a/js/apps/account-ui/public/passkeys/aliasvault-light.svg b/js/apps/account-ui/public/passkeys/aliasvault-light.svg new file mode 100644 index 00000000000..5876600fe70 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/aliasvault-light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/allthenticator-light.png b/js/apps/account-ui/public/passkeys/allthenticator-light.png new file mode 100644 index 00000000000..119ec6cb69e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/allthenticator-light.png differ diff --git a/js/apps/account-ui/public/passkeys/android-light.png b/js/apps/account-ui/public/passkeys/android-light.png new file mode 100644 index 00000000000..d220a9c769e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/android-light.png differ diff --git a/js/apps/account-ui/public/passkeys/apple-light.svg b/js/apps/account-ui/public/passkeys/apple-light.svg new file mode 100644 index 00000000000..bd1715076d6 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/apple-light.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/arculus-light.png b/js/apps/account-ui/public/passkeys/arculus-light.png new file mode 100644 index 00000000000..352c8fa5188 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/arculus-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atkey-light.png b/js/apps/account-ui/public/passkeys/atkey-light.png new file mode 100644 index 00000000000..8e49f89bd8a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atkey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atkey1-light.png b/js/apps/account-ui/public/passkeys/atkey1-light.png new file mode 100644 index 00000000000..e8999b259cd Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atkey1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atkey2-light.png b/js/apps/account-ui/public/passkeys/atkey2-light.png new file mode 100644 index 00000000000..e8999b259cd Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atkey2-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atkey4-light.png b/js/apps/account-ui/public/passkeys/atkey4-light.png new file mode 100644 index 00000000000..13666ed7013 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atkey4-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atlkey-light.png b/js/apps/account-ui/public/passkeys/atlkey-light.png new file mode 100644 index 00000000000..bfd6f75d1ec Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atlkey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/atos-light.png b/js/apps/account-ui/public/passkeys/atos-light.png new file mode 100644 index 00000000000..ce465847683 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/atos-light.png differ diff --git a/js/apps/account-ui/public/passkeys/authenton1-light.png b/js/apps/account-ui/public/passkeys/authenton1-light.png new file mode 100644 index 00000000000..99362a70a7c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/authenton1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/bitwarden-light.svg b/js/apps/account-ui/public/passkeys/bitwarden-light.svg new file mode 100644 index 00000000000..761c97ab74f --- /dev/null +++ b/js/apps/account-ui/public/passkeys/bitwarden-light.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/burp-light.svg b/js/apps/account-ui/public/passkeys/burp-light.svg new file mode 100644 index 00000000000..2460a71db34 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/burp-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/apps/account-ui/public/passkeys/cardos-light.png b/js/apps/account-ui/public/passkeys/cardos-light.png new file mode 100644 index 00000000000..a8b2aec8244 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/cardos-light.png differ diff --git a/js/apps/account-ui/public/passkeys/chipwon-light.png b/js/apps/account-ui/public/passkeys/chipwon-light.png new file mode 100644 index 00000000000..3a8d1eabef3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/chipwon-light.png differ diff --git a/js/apps/account-ui/public/passkeys/chrome-light.svg b/js/apps/account-ui/public/passkeys/chrome-light.svg new file mode 100644 index 00000000000..2a61bf86971 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/chrome-light.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/chunghwa-light.png b/js/apps/account-ui/public/passkeys/chunghwa-light.png new file mode 100644 index 00000000000..9de4b8b7283 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/chunghwa-light.png differ diff --git a/js/apps/account-ui/public/passkeys/crayonic-light.png b/js/apps/account-ui/public/passkeys/crayonic-light.png new file mode 100644 index 00000000000..f7510ba5069 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/crayonic-light.png differ diff --git a/js/apps/account-ui/public/passkeys/cryptnox-light.png b/js/apps/account-ui/public/passkeys/cryptnox-light.png new file mode 100644 index 00000000000..a6df0316c5e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/cryptnox-light.png differ diff --git a/js/apps/account-ui/public/passkeys/dapple-light.png b/js/apps/account-ui/public/passkeys/dapple-light.png new file mode 100644 index 00000000000..e9ca8f26082 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/dapple-light.png differ diff --git a/js/apps/account-ui/public/passkeys/dashlane-dark.svg b/js/apps/account-ui/public/passkeys/dashlane-dark.svg new file mode 100644 index 00000000000..f23ec9e3f26 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/dashlane-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/dashlane-light.svg b/js/apps/account-ui/public/passkeys/dashlane-light.svg new file mode 100644 index 00000000000..49f658ffde4 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/dashlane-light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/deepnet-light.png b/js/apps/account-ui/public/passkeys/deepnet-light.png new file mode 100644 index 00000000000..ddc8ef8226a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/deepnet-light.png differ diff --git a/js/apps/account-ui/public/passkeys/devolutions-light.svg b/js/apps/account-ui/public/passkeys/devolutions-light.svg new file mode 100644 index 00000000000..0ea7851ca1f --- /dev/null +++ b/js/apps/account-ui/public/passkeys/devolutions-light.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/edge-light.svg b/js/apps/account-ui/public/passkeys/edge-light.svg new file mode 100644 index 00000000000..3e7e9eeac16 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/edge-light.svg @@ -0,0 +1 @@ +Edge_Logo_265x265 \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/egomet-light.png b/js/apps/account-ui/public/passkeys/egomet-light.png new file mode 100644 index 00000000000..f630703b671 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/egomet-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ellipticsecure-light.png b/js/apps/account-ui/public/passkeys/ellipticsecure-light.png new file mode 100644 index 00000000000..daf9931998a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ellipticsecure-light.png differ diff --git a/js/apps/account-ui/public/passkeys/enpass-dark.svg b/js/apps/account-ui/public/passkeys/enpass-dark.svg new file mode 100644 index 00000000000..8cf8e7f3123 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/enpass-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/enpass-light.svg b/js/apps/account-ui/public/passkeys/enpass-light.svg new file mode 100644 index 00000000000..a69a66c8a0e --- /dev/null +++ b/js/apps/account-ui/public/passkeys/enpass-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/ensurity-light.png b/js/apps/account-ui/public/passkeys/ensurity-light.png new file mode 100644 index 00000000000..01189dfb2cc Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ensurity-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ensurity1-light.png b/js/apps/account-ui/public/passkeys/ensurity1-light.png new file mode 100644 index 00000000000..b9aae557d8a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ensurity1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ensurity2-light.png b/js/apps/account-ui/public/passkeys/ensurity2-light.png new file mode 100644 index 00000000000..2b5f482e132 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ensurity2-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ensurity3-light.png b/js/apps/account-ui/public/passkeys/ensurity3-light.png new file mode 100644 index 00000000000..22223df9bd9 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ensurity3-light.png differ diff --git a/js/apps/account-ui/public/passkeys/enterprise-light.svg b/js/apps/account-ui/public/passkeys/enterprise-light.svg new file mode 100644 index 00000000000..b9716d72a3b --- /dev/null +++ b/js/apps/account-ui/public/passkeys/enterprise-light.svg @@ -0,0 +1 @@ +YubiKeyYubiKey \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/ess-light.png b/js/apps/account-ui/public/passkeys/ess-light.png new file mode 100644 index 00000000000..80fd970dad0 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ess-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ewbm-light.png b/js/apps/account-ui/public/passkeys/ewbm-light.png new file mode 100644 index 00000000000..8367c4e97f6 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ewbm-light.png differ diff --git a/js/apps/account-ui/public/passkeys/excelsecu-light.png b/js/apps/account-ui/public/passkeys/excelsecu-light.png new file mode 100644 index 00000000000..6801a472a8a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/excelsecu-light.png differ diff --git a/js/apps/account-ui/public/passkeys/feitian-light.png b/js/apps/account-ui/public/passkeys/feitian-light.png new file mode 100644 index 00000000000..6e800533ca3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/feitian-light.png differ diff --git a/js/apps/account-ui/public/passkeys/fido-light.png b/js/apps/account-ui/public/passkeys/fido-light.png new file mode 100644 index 00000000000..502983c48de Binary files /dev/null and b/js/apps/account-ui/public/passkeys/fido-light.png differ diff --git a/js/apps/account-ui/public/passkeys/fido1-light.png b/js/apps/account-ui/public/passkeys/fido1-light.png new file mode 100644 index 00000000000..f32ce4846be Binary files /dev/null and b/js/apps/account-ui/public/passkeys/fido1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/foongtone-light.png b/js/apps/account-ui/public/passkeys/foongtone-light.png new file mode 100644 index 00000000000..d425076cd26 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/foongtone-light.png differ diff --git a/js/apps/account-ui/public/passkeys/goldkey-light.png b/js/apps/account-ui/public/passkeys/goldkey-light.png new file mode 100644 index 00000000000..74b0675986b Binary files /dev/null and b/js/apps/account-ui/public/passkeys/goldkey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/google-light.png b/js/apps/account-ui/public/passkeys/google-light.png new file mode 100644 index 00000000000..875a1c652b4 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/google-light.png differ diff --git a/js/apps/account-ui/public/passkeys/google1-light.svg b/js/apps/account-ui/public/passkeys/google1-light.svg new file mode 100644 index 00000000000..b13ae8a5eb4 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/google1-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/gotrust-light.png b/js/apps/account-ui/public/passkeys/gotrust-light.png new file mode 100644 index 00000000000..1c34cc74fe3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/gotrust-light.png differ diff --git a/js/apps/account-ui/public/passkeys/gstag-light.png b/js/apps/account-ui/public/passkeys/gstag-light.png new file mode 100644 index 00000000000..017c4c83be9 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/gstag-light.png differ diff --git a/js/apps/account-ui/public/passkeys/heimlane-light.svg b/js/apps/account-ui/public/passkeys/heimlane-light.svg new file mode 100644 index 00000000000..7e90bbb85a8 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/heimlane-light.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/hid-light.png b/js/apps/account-ui/public/passkeys/hid-light.png new file mode 100644 index 00000000000..763a54a251e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/hid-light.png differ diff --git a/js/apps/account-ui/public/passkeys/hideez-light.png b/js/apps/account-ui/public/passkeys/hideez-light.png new file mode 100644 index 00000000000..56fa1984102 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/hideez-light.png differ diff --git a/js/apps/account-ui/public/passkeys/hyper-light.png b/js/apps/account-ui/public/passkeys/hyper-light.png new file mode 100644 index 00000000000..9a077c0fd7f Binary files /dev/null and b/js/apps/account-ui/public/passkeys/hyper-light.png differ diff --git a/js/apps/account-ui/public/passkeys/hyper1-light.png b/js/apps/account-ui/public/passkeys/hyper1-light.png new file mode 100644 index 00000000000..0f8ffa00641 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/hyper1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/hypr-light.png b/js/apps/account-ui/public/passkeys/hypr-light.png new file mode 100644 index 00000000000..4d8dc8f423f Binary files /dev/null and b/js/apps/account-ui/public/passkeys/hypr-light.png differ diff --git a/js/apps/account-ui/public/passkeys/icloud-dark.svg b/js/apps/account-ui/public/passkeys/icloud-dark.svg new file mode 100644 index 00000000000..30f4f117ce3 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/icloud-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/icloud-light.svg b/js/apps/account-ui/public/passkeys/icloud-light.svg new file mode 100644 index 00000000000..db821819e5f --- /dev/null +++ b/js/apps/account-ui/public/passkeys/icloud-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/id-one-light.png b/js/apps/account-ui/public/passkeys/id-one-light.png new file mode 100644 index 00000000000..cb3c34a9671 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/id-one-light.png differ diff --git a/js/apps/account-ui/public/passkeys/ideem-light.png b/js/apps/account-ui/public/passkeys/ideem-light.png new file mode 100644 index 00000000000..133098a5086 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ideem-light.png differ diff --git a/js/apps/account-ui/public/passkeys/idemia-light.png b/js/apps/account-ui/public/passkeys/idemia-light.png new file mode 100644 index 00000000000..444bab5f4c1 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/idemia-light.png differ diff --git a/js/apps/account-ui/public/passkeys/idex-light.png b/js/apps/account-ui/public/passkeys/idex-light.png new file mode 100644 index 00000000000..ef6b3c444d7 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/idex-light.png differ diff --git a/js/apps/account-ui/public/passkeys/idmelon-light.svg b/js/apps/account-ui/public/passkeys/idmelon-light.svg new file mode 100644 index 00000000000..a4815b1d7fb --- /dev/null +++ b/js/apps/account-ui/public/passkeys/idmelon-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/idmelon1-light.png b/js/apps/account-ui/public/passkeys/idmelon1-light.png new file mode 100644 index 00000000000..dca9bb18cf0 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/idmelon1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/iist-light.png b/js/apps/account-ui/public/passkeys/iist-light.png new file mode 100644 index 00000000000..115b97985d6 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/iist-light.png differ diff --git a/js/apps/account-ui/public/passkeys/initial-light.svg b/js/apps/account-ui/public/passkeys/initial-light.svg new file mode 100644 index 00000000000..902bf13c795 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/initial-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/js/apps/account-ui/public/passkeys/ipasswords-light.svg b/js/apps/account-ui/public/passkeys/ipasswords-light.svg new file mode 100644 index 00000000000..6fe8a4dfe6d --- /dev/null +++ b/js/apps/account-ui/public/passkeys/ipasswords-light.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/kaspersky-light.svg b/js/apps/account-ui/public/passkeys/kaspersky-light.svg new file mode 100644 index 00000000000..e0f82e19eac --- /dev/null +++ b/js/apps/account-ui/public/passkeys/kaspersky-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/keepassdx-dark.svg b/js/apps/account-ui/public/passkeys/keepassdx-dark.svg new file mode 100644 index 00000000000..0c95ba006f9 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/keepassdx-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/keepassdx-light.svg b/js/apps/account-ui/public/passkeys/keepassdx-light.svg new file mode 100644 index 00000000000..6a1da82dd39 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/keepassdx-light.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/keepassxc-dark.svg b/js/apps/account-ui/public/passkeys/keepassxc-dark.svg new file mode 100644 index 00000000000..80a12953f8c --- /dev/null +++ b/js/apps/account-ui/public/passkeys/keepassxc-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/keepassxc-light.svg b/js/apps/account-ui/public/passkeys/keepassxc-light.svg new file mode 100644 index 00000000000..aad6c5a16be --- /dev/null +++ b/js/apps/account-ui/public/passkeys/keepassxc-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/keeper-light.svg b/js/apps/account-ui/public/passkeys/keeper-light.svg new file mode 100644 index 00000000000..450cef168c5 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/keeper-light.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/key-id-light.png b/js/apps/account-ui/public/passkeys/key-id-light.png new file mode 100644 index 00000000000..9f214041314 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/key-id-light.png differ diff --git a/js/apps/account-ui/public/passkeys/keyvault-light.png b/js/apps/account-ui/public/passkeys/keyvault-light.png new file mode 100644 index 00000000000..ae854f0b31e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/keyvault-light.png differ diff --git a/js/apps/account-ui/public/passkeys/keyxentic-light.png b/js/apps/account-ui/public/passkeys/keyxentic-light.png new file mode 100644 index 00000000000..45d900cf0ec Binary files /dev/null and b/js/apps/account-ui/public/passkeys/keyxentic-light.png differ diff --git a/js/apps/account-ui/public/passkeys/konai-light.png b/js/apps/account-ui/public/passkeys/konai-light.png new file mode 100644 index 00000000000..857225020d6 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/konai-light.png differ diff --git a/js/apps/account-ui/public/passkeys/kqc-light.png b/js/apps/account-ui/public/passkeys/kqc-light.png new file mode 100644 index 00000000000..7931c8b9964 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/kqc-light.png differ diff --git a/js/apps/account-ui/public/passkeys/lastpass-dark.svg b/js/apps/account-ui/public/passkeys/lastpass-dark.svg new file mode 100644 index 00000000000..764d273f583 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/lastpass-dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/lastpass-light.svg b/js/apps/account-ui/public/passkeys/lastpass-light.svg new file mode 100644 index 00000000000..aac8009ea32 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/lastpass-light.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/ledger-light.png b/js/apps/account-ui/public/passkeys/ledger-light.png new file mode 100644 index 00000000000..c424a76ea4a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ledger-light.png differ diff --git a/js/apps/account-ui/public/passkeys/logmeonce-dark.svg b/js/apps/account-ui/public/passkeys/logmeonce-dark.svg new file mode 100644 index 00000000000..3535740492f --- /dev/null +++ b/js/apps/account-ui/public/passkeys/logmeonce-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/apps/account-ui/public/passkeys/logmeonce-light.svg b/js/apps/account-ui/public/passkeys/logmeonce-light.svg new file mode 100644 index 00000000000..f48c5b8f02f --- /dev/null +++ b/js/apps/account-ui/public/passkeys/logmeonce-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/js/apps/account-ui/public/passkeys/mettlesemi-light.png b/js/apps/account-ui/public/passkeys/mettlesemi-light.png new file mode 100644 index 00000000000..02d90d60c24 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/mettlesemi-light.png differ diff --git a/js/apps/account-ui/public/passkeys/microsoft-light.svg b/js/apps/account-ui/public/passkeys/microsoft-light.svg new file mode 100644 index 00000000000..f2e2b2becd3 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/microsoft-light.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/neowave-light.png b/js/apps/account-ui/public/passkeys/neowave-light.png new file mode 100644 index 00000000000..c6a43fdc915 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/neowave-light.png differ diff --git a/js/apps/account-ui/public/passkeys/nitrokey-light.png b/js/apps/account-ui/public/passkeys/nitrokey-light.png new file mode 100644 index 00000000000..5488c47d6f1 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/nitrokey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/nordpass-dark.svg b/js/apps/account-ui/public/passkeys/nordpass-dark.svg new file mode 100644 index 00000000000..8b303ea6cdd --- /dev/null +++ b/js/apps/account-ui/public/passkeys/nordpass-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/nordpass-light.svg b/js/apps/account-ui/public/passkeys/nordpass-light.svg new file mode 100644 index 00000000000..dce77b77e53 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/nordpass-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/js/apps/account-ui/public/passkeys/nxp-light.png b/js/apps/account-ui/public/passkeys/nxp-light.png new file mode 100644 index 00000000000..0f2b10a7d8c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/nxp-light.png differ diff --git a/js/apps/account-ui/public/passkeys/nymi-light.png b/js/apps/account-ui/public/passkeys/nymi-light.png new file mode 100644 index 00000000000..1abafe4d816 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/nymi-light.png differ diff --git a/js/apps/account-ui/public/passkeys/octatco-light.png b/js/apps/account-ui/public/passkeys/octatco-light.png new file mode 100644 index 00000000000..c9eae1bc0bf Binary files /dev/null and b/js/apps/account-ui/public/passkeys/octatco-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onekey-light.png b/js/apps/account-ui/public/passkeys/onekey-light.png new file mode 100644 index 00000000000..8c24418f38c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onekey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan-light.png b/js/apps/account-ui/public/passkeys/onespan-light.png new file mode 100644 index 00000000000..717e0a7e459 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan1-light.png b/js/apps/account-ui/public/passkeys/onespan1-light.png new file mode 100644 index 00000000000..d934d9145ba Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan2-light.png b/js/apps/account-ui/public/passkeys/onespan2-light.png new file mode 100644 index 00000000000..31d00e3da58 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan2-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan3-light.png b/js/apps/account-ui/public/passkeys/onespan3-light.png new file mode 100644 index 00000000000..2effb9cab6c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan3-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan4-light.png b/js/apps/account-ui/public/passkeys/onespan4-light.png new file mode 100644 index 00000000000..31d00e3da58 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan4-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan5-light.png b/js/apps/account-ui/public/passkeys/onespan5-light.png new file mode 100644 index 00000000000..2effb9cab6c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan5-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onespan7-light.png b/js/apps/account-ui/public/passkeys/onespan7-light.png new file mode 100644 index 00000000000..f94573cd42e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onespan7-light.png differ diff --git a/js/apps/account-ui/public/passkeys/onlykey-light.png b/js/apps/account-ui/public/passkeys/onlykey-light.png new file mode 100644 index 00000000000..d527f749c1e Binary files /dev/null and b/js/apps/account-ui/public/passkeys/onlykey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/opensk-light.png b/js/apps/account-ui/public/passkeys/opensk-light.png new file mode 100644 index 00000000000..719ad415be3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/opensk-light.png differ diff --git a/js/apps/account-ui/public/passkeys/pone-light.png b/js/apps/account-ui/public/passkeys/pone-light.png new file mode 100644 index 00000000000..cf961760c53 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/pone-light.png differ diff --git a/js/apps/account-ui/public/passkeys/precision-light.png b/js/apps/account-ui/public/passkeys/precision-light.png new file mode 100644 index 00000000000..01ac45de8d3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/precision-light.png differ diff --git a/js/apps/account-ui/public/passkeys/precision1-light.png b/js/apps/account-ui/public/passkeys/precision1-light.png new file mode 100644 index 00000000000..f5e09a76d56 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/precision1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/precision2-light.png b/js/apps/account-ui/public/passkeys/precision2-light.png new file mode 100644 index 00000000000..f5e09a76d56 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/precision2-light.png differ diff --git a/js/apps/account-ui/public/passkeys/proton-light.svg b/js/apps/account-ui/public/passkeys/proton-light.svg new file mode 100644 index 00000000000..08d95f2785b --- /dev/null +++ b/js/apps/account-ui/public/passkeys/proton-light.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/pwsafe-light.svg b/js/apps/account-ui/public/passkeys/pwsafe-light.svg new file mode 100644 index 00000000000..094897da943 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/pwsafe-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/rsa-light.png b/js/apps/account-ui/public/passkeys/rsa-light.png new file mode 100644 index 00000000000..f09ffa6505f Binary files /dev/null and b/js/apps/account-ui/public/passkeys/rsa-light.png differ diff --git a/js/apps/account-ui/public/passkeys/samsung-light.svg b/js/apps/account-ui/public/passkeys/samsung-light.svg new file mode 100644 index 00000000000..399033941d8 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/samsung-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/secora-light.png b/js/apps/account-ui/public/passkeys/secora-light.png new file mode 100644 index 00000000000..7853293c027 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/secora-light.png differ diff --git a/js/apps/account-ui/public/passkeys/secora1-light.png b/js/apps/account-ui/public/passkeys/secora1-light.png new file mode 100644 index 00000000000..c511d33a45c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/secora1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/securitag-light.png b/js/apps/account-ui/public/passkeys/securitag-light.png new file mode 100644 index 00000000000..01eb9d7feb7 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/securitag-light.png differ diff --git a/js/apps/account-ui/public/passkeys/sentry-light.png b/js/apps/account-ui/public/passkeys/sentry-light.png new file mode 100644 index 00000000000..43679057172 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/sentry-light.png differ diff --git a/js/apps/account-ui/public/passkeys/sesame-light.svg b/js/apps/account-ui/public/passkeys/sesame-light.svg new file mode 100644 index 00000000000..55424277f1e --- /dev/null +++ b/js/apps/account-ui/public/passkeys/sesame-light.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/shalo-light.png b/js/apps/account-ui/public/passkeys/shalo-light.png new file mode 100644 index 00000000000..1dd81821588 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/shalo-light.png differ diff --git a/js/apps/account-ui/public/passkeys/sherlocked-light.svg b/js/apps/account-ui/public/passkeys/sherlocked-light.svg new file mode 100644 index 00000000000..9459ac5d242 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/sherlocked-light.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/smartdisplayer-light.png b/js/apps/account-ui/public/passkeys/smartdisplayer-light.png new file mode 100644 index 00000000000..dd5a5b6dff2 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/smartdisplayer-light.png differ diff --git a/js/apps/account-ui/public/passkeys/solo-light.png b/js/apps/account-ui/public/passkeys/solo-light.png new file mode 100644 index 00000000000..fd13fc23d1a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/solo-light.png differ diff --git a/js/apps/account-ui/public/passkeys/starsign-light.png b/js/apps/account-ui/public/passkeys/starsign-light.png new file mode 100644 index 00000000000..3e27e386532 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/starsign-light.png differ diff --git a/js/apps/account-ui/public/passkeys/sticky-light.svg b/js/apps/account-ui/public/passkeys/sticky-light.svg new file mode 100644 index 00000000000..4b2f5f457ef --- /dev/null +++ b/js/apps/account-ui/public/passkeys/sticky-light.svg @@ -0,0 +1,63 @@ + + + Sticky Password Manager + + + + + + + + + + diff --git a/js/apps/account-ui/public/passkeys/swissbit-light.png b/js/apps/account-ui/public/passkeys/swissbit-light.png new file mode 100644 index 00000000000..ac23d8ea257 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/swissbit-light.png differ diff --git a/js/apps/account-ui/public/passkeys/t-shield-light.png b/js/apps/account-ui/public/passkeys/t-shield-light.png new file mode 100644 index 00000000000..5a405a301f3 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/t-shield-light.png differ diff --git a/js/apps/account-ui/public/passkeys/taglio-light.png b/js/apps/account-ui/public/passkeys/taglio-light.png new file mode 100644 index 00000000000..4d7417e40b9 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/taglio-light.png differ diff --git a/js/apps/account-ui/public/passkeys/thales-light.png b/js/apps/account-ui/public/passkeys/thales-light.png new file mode 100644 index 00000000000..da6aaa1f29a Binary files /dev/null and b/js/apps/account-ui/public/passkeys/thales-light.png differ diff --git a/js/apps/account-ui/public/passkeys/thales1-dark.svg b/js/apps/account-ui/public/passkeys/thales1-dark.svg new file mode 100644 index 00000000000..367d2b49bf0 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/thales1-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/thales1-light.svg b/js/apps/account-ui/public/passkeys/thales1-light.svg new file mode 100644 index 00000000000..baab67dba79 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/thales1-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/thales3-dark.svg b/js/apps/account-ui/public/passkeys/thales3-dark.svg new file mode 100644 index 00000000000..367d2b49bf0 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/thales3-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/thales3-light.svg b/js/apps/account-ui/public/passkeys/thales3-light.svg new file mode 100644 index 00000000000..baab67dba79 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/thales3-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/thetis-light.png b/js/apps/account-ui/public/passkeys/thetis-light.png new file mode 100644 index 00000000000..65bbff0e831 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/thetis-light.png differ diff --git a/js/apps/account-ui/public/passkeys/token-light.png b/js/apps/account-ui/public/passkeys/token-light.png new file mode 100644 index 00000000000..db5ddd7c03b Binary files /dev/null and b/js/apps/account-ui/public/passkeys/token-light.png differ diff --git a/js/apps/account-ui/public/passkeys/token2-light.png b/js/apps/account-ui/public/passkeys/token2-light.png new file mode 100644 index 00000000000..4f3f0df2915 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/token2-light.png differ diff --git a/js/apps/account-ui/public/passkeys/toothpic-dark.svg b/js/apps/account-ui/public/passkeys/toothpic-dark.svg new file mode 100644 index 00000000000..0c4d14840c9 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/toothpic-dark.svg @@ -0,0 +1,91 @@ + +image/svg+xml diff --git a/js/apps/account-ui/public/passkeys/toothpic-light.svg b/js/apps/account-ui/public/passkeys/toothpic-light.svg new file mode 100644 index 00000000000..1117024037c --- /dev/null +++ b/js/apps/account-ui/public/passkeys/toothpic-light.svg @@ -0,0 +1,76 @@ + +image/svg+xml \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/truu-light.png b/js/apps/account-ui/public/passkeys/truu-light.png new file mode 100644 index 00000000000..729e072b151 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/truu-light.png differ diff --git a/js/apps/account-ui/public/passkeys/utrust-light.png b/js/apps/account-ui/public/passkeys/utrust-light.png new file mode 100644 index 00000000000..d22d32f66da Binary files /dev/null and b/js/apps/account-ui/public/passkeys/utrust-light.png differ diff --git a/js/apps/account-ui/public/passkeys/valmido-light.png b/js/apps/account-ui/public/passkeys/valmido-light.png new file mode 100644 index 00000000000..4d763d1801c Binary files /dev/null and b/js/apps/account-ui/public/passkeys/valmido-light.png differ diff --git a/js/apps/account-ui/public/passkeys/veridium-light.png b/js/apps/account-ui/public/passkeys/veridium-light.png new file mode 100644 index 00000000000..a2604ff4041 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/veridium-light.png differ diff --git a/js/apps/account-ui/public/passkeys/verimark-light.png b/js/apps/account-ui/public/passkeys/verimark-light.png new file mode 100644 index 00000000000..7b1c861a222 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/verimark-light.png differ diff --git a/js/apps/account-ui/public/passkeys/verimark1-light.png b/js/apps/account-ui/public/passkeys/verimark1-light.png new file mode 100644 index 00000000000..27da03b2ae1 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/verimark1-light.png differ diff --git a/js/apps/account-ui/public/passkeys/verocard-light.png b/js/apps/account-ui/public/passkeys/verocard-light.png new file mode 100644 index 00000000000..3c557f24582 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/verocard-light.png differ diff --git a/js/apps/account-ui/public/passkeys/vincss-light.png b/js/apps/account-ui/public/passkeys/vincss-light.png new file mode 100644 index 00000000000..d8dad417d06 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/vincss-light.png differ diff --git a/js/apps/account-ui/public/passkeys/vivokey-light.png b/js/apps/account-ui/public/passkeys/vivokey-light.png new file mode 100644 index 00000000000..2a2385d0be5 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/vivokey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/webcomm-light.png b/js/apps/account-ui/public/passkeys/webcomm-light.png new file mode 100644 index 00000000000..b24d4d14fef Binary files /dev/null and b/js/apps/account-ui/public/passkeys/webcomm-light.png differ diff --git a/js/apps/account-ui/public/passkeys/windows-light.svg b/js/apps/account-ui/public/passkeys/windows-light.svg new file mode 100644 index 00000000000..960a7af56e4 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/windows-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/winmagic-light.png b/js/apps/account-ui/public/passkeys/winmagic-light.png new file mode 100644 index 00000000000..07c8c1d82d4 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/winmagic-light.png differ diff --git a/js/apps/account-ui/public/passkeys/yubikey-light.png b/js/apps/account-ui/public/passkeys/yubikey-light.png new file mode 100644 index 00000000000..d1c1b3a87b9 Binary files /dev/null and b/js/apps/account-ui/public/passkeys/yubikey-light.png differ diff --git a/js/apps/account-ui/public/passkeys/zoho-light.svg b/js/apps/account-ui/public/passkeys/zoho-light.svg new file mode 100644 index 00000000000..ccf3e05d528 --- /dev/null +++ b/js/apps/account-ui/public/passkeys/zoho-light.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/apps/account-ui/public/passkeys/ztpass-light.png b/js/apps/account-ui/public/passkeys/ztpass-light.png new file mode 100644 index 00000000000..c12293c80ba Binary files /dev/null and b/js/apps/account-ui/public/passkeys/ztpass-light.png differ diff --git a/js/apps/account-ui/src/account-security/SigningIn.tsx b/js/apps/account-ui/src/account-security/SigningIn.tsx index b67b9f2dbeb..8ff4281824f 100644 --- a/js/apps/account-ui/src/account-security/SigningIn.tsx +++ b/js/apps/account-ui/src/account-security/SigningIn.tsx @@ -38,6 +38,7 @@ import type { TFuncKey } from "../i18n-type"; import { formatDate } from "../utils/formatDate"; import { usePromise } from "../utils/usePromise"; import { AccountEnvironment } from ".."; +import { joinPath } from "../utils/joinPath"; type MobileLinkProps = { title: string; @@ -98,19 +99,67 @@ export const SigningIn = () => { const credentialRowCells = ( credMetadata: CredentialMetadataRepresentation, + showIcon: boolean, ) => { const credential = credMetadata.credential; const maxWidth = { "--pf-v5-u-max-width--MaxWidth": "300px", } as CSSProperties; + const icon = credMetadata.iconLight || credMetadata.iconDark; + const authenticatorProvider = credMetadata.infoProperties?.find( + (p) => p.key === "webauthn-authenticator-provider", + )?.parameters?.[0]; + const iconSrc = icon + ? joinPath(context.environment.resourceUrl, "passkeys", icon) + : joinPath(context.environment.resourceUrl, "favicon.svg"); + const iconDarkSrc = credMetadata.iconDark + ? joinPath( + context.environment.resourceUrl, + "passkeys", + credMetadata.iconDark, + ) + : undefined; + const items = [ + ...(showIcon + ? [ + +
+ + {iconDarkSrc && ( + + )} + + +
+
, + ] + : []), - {t(credential.userLabel) || t(credential.type as TFuncKey)} +
{t(credential.userLabel) || t(credential.type as TFuncKey)}
+ {authenticatorProvider && ( +
+ {authenticatorProvider} +
+ )}
, ]; @@ -119,6 +168,7 @@ export const SigningIn = () => { { "2xl": "15ch", }} > - {credMetadata.infoProperties.map((prop) => ( - - {t(prop.key)} - - {prop.parameters ? prop.parameters[0] : ""} - - - ))} + {credMetadata.infoProperties + .filter( + (prop) => + prop.key !== "webauthn-authenticator-provider", + ) + .map((prop) => ( + + + {t(prop.key)} + + + {prop.parameters ? prop.parameters[0] : ""} + + + ))} @@ -290,9 +347,12 @@ export const SigningIn = () => { producer) { + if (Profile.isFeatureEnabled(Profile.Feature.WEB_AUTHN)) { + producer.produce(new WebAuthnMetadataBuildItem(WebAuthnMetadataService.parseMetadata())); + } + } + + @Record(ExecutionTime.STATIC_INIT) + @Consume(ProfileBuildItem.class) + @Consume(WebAuthnMetadataBuildItem.class) + @BuildStep + void configureWebAuthnMetadata(KeycloakRecorder recorder, WebAuthnMetadataBuildItem metadataBuildItem) { + if (Profile.isFeatureEnabled(Profile.Feature.WEB_AUTHN)) { + recorder.setDefaultWebAuthnMetadata(metadataBuildItem.getMetadata()); + } + } + /** * This will cause quarkus to include specified modules in the jandex index. For example keycloak-services is needed as it includes * most of the JAX-RS resources, which are required to register Resteasy builtin providers. diff --git a/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/WebAuthnMetadataBuildItem.java b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/WebAuthnMetadataBuildItem.java new file mode 100644 index 00000000000..a4a9dbbfcda --- /dev/null +++ b/quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/WebAuthnMetadataBuildItem.java @@ -0,0 +1,20 @@ +package org.keycloak.quarkus.deployment; + +import java.util.Map; + +import org.keycloak.authentication.authenticators.browser.WebAuthnAuthenticatorMetadata; + +import io.quarkus.builder.item.SimpleBuildItem; + +final class WebAuthnMetadataBuildItem extends SimpleBuildItem { + + private final Map metadata; + + WebAuthnMetadataBuildItem(Map metadata) { + this.metadata = metadata; + } + + Map getMetadata() { + return metadata; + } +} diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java index c30029cc0df..e24825af4c9 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakRecorder.java @@ -28,6 +28,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.keycloak.Config; +import org.keycloak.authentication.authenticators.browser.WebAuthnAuthenticatorMetadata; +import org.keycloak.authentication.authenticators.browser.WebAuthnMetadataService; import org.keycloak.common.Profile; import org.keycloak.common.crypto.CryptoIntegration; import org.keycloak.common.crypto.CryptoProvider; @@ -169,6 +171,11 @@ public class KeycloakRecorder { DeclarativeUserProfileProviderFactory.setDefaultConfig(configuration); } + public void setDefaultWebAuthnMetadata(Map metadata) { + WebAuthnMetadataService.setDefaultMetadata(metadata); + } + + public HibernateOrmIntegrationRuntimeInitListener createUserDefinedUnitListener(String name) { return propertyCollector -> { try (InstanceHandle instance = Arc.container().instance( diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 7c5f3eb3679..308ad835cdd 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -801,6 +801,8 @@ public class ModelToRepresentation { .toList()); rep.setWarningMessageDescription(toLocalizedMessage(credentialMetadata.getWarningMessageDescription())); rep.setWarningMessageTitle(toLocalizedMessage(credentialMetadata.getWarningMessageTitle())); + rep.setIconLight(credentialMetadata.getIconLight()); + rep.setIconDark(credentialMetadata.getIconDark()); return rep; } diff --git a/server-spi/src/main/java/org/keycloak/credential/CredentialMetadata.java b/server-spi/src/main/java/org/keycloak/credential/CredentialMetadata.java index e6d999e7386..b0dc6276d28 100644 --- a/server-spi/src/main/java/org/keycloak/credential/CredentialMetadata.java +++ b/server-spi/src/main/java/org/keycloak/credential/CredentialMetadata.java @@ -8,6 +8,8 @@ public class CredentialMetadata { LocalizedMessage warningMessageTitle; LocalizedMessage warningMessageDescription; CredentialModel credentialModel; + private String iconLight; + private String iconDark; public CredentialModel getCredentialModel() { return credentialModel; @@ -52,6 +54,22 @@ public class CredentialMetadata { this.infoProperties = infoProperties; } + public String getIconLight() { + return iconLight; + } + + public void setIconLight(String iconLight) { + this.iconLight = iconLight; + } + + public String getIconDark() { + return iconDark; + } + + public void setIconDark(String iconDark) { + this.iconDark = iconDark; + } + public static class LocalizedMessage { private final String key; private final Object[] parameters; diff --git a/server-spi/src/main/java/org/keycloak/models/credential/dto/WebAuthnCredentialPresentationData.java b/server-spi/src/main/java/org/keycloak/models/credential/dto/WebAuthnCredentialPresentationData.java index ec242b520a5..b8be9a0d9b5 100644 --- a/server-spi/src/main/java/org/keycloak/models/credential/dto/WebAuthnCredentialPresentationData.java +++ b/server-spi/src/main/java/org/keycloak/models/credential/dto/WebAuthnCredentialPresentationData.java @@ -11,6 +11,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class WebAuthnCredentialPresentationData extends WebAuthnCredentialData { private final String authenticatorProvider; + private final String iconLight; + private final String iconDark; @JsonCreator public WebAuthnCredentialPresentationData(@JsonProperty("aaguid") String aaguid, @@ -20,12 +22,24 @@ public class WebAuthnCredentialPresentationData extends WebAuthnCredentialData { @JsonProperty("credentialPublicKey") String credentialPublicKey, @JsonProperty("attestationStatementFormat") String attestationStatementFormat, @JsonProperty("transports") Set transports, - @JsonProperty("authenticatorProvider") String authenticatorProvider) { + @JsonProperty("authenticatorProvider") String authenticatorProvider, + @JsonProperty("iconLight") String iconLight, + @JsonProperty("iconDark") String iconDark) { super(aaguid, credentialId, counter, attestationStatement, credentialPublicKey, attestationStatementFormat, transports); this.authenticatorProvider = authenticatorProvider; + this.iconLight = iconLight; + this.iconDark = iconDark; } public String getAuthenticatorProvider() { return authenticatorProvider; } + + public String getIconLight() { + return iconLight; + } + + public String getIconDark() { + return iconDark; + } } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticator.java index afedcbbb39a..59532742e57 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticator.java @@ -103,7 +103,8 @@ public class WebAuthnAuthenticator implements Authenticator, CredentialValidator boolean isUserIdentified = false; if (user != null) { // in 2 Factor Scenario where the user has already been identified - WebAuthnAuthenticatorsBean authenticators = new WebAuthnAuthenticatorsBean(context.getSession(), context.getRealm(), user, getCredentialType()); + WebAuthnMetadataService metadataService = getCredentialProvider(context.getSession()).getMetadataService(); + WebAuthnAuthenticatorsBean authenticators = new WebAuthnAuthenticatorsBean(context.getSession(), context.getRealm(), user, getCredentialType(), metadataService); if (authenticators.getAuthenticators().isEmpty()) { // require the user to register webauthn authenticator return null; @@ -360,7 +361,8 @@ public class WebAuthnAuthenticator implements Authenticator, CredentialValidator LoginFormsProvider provider = context.form().setError(errorCase, ""); UserModel user = context.getUser(); if (user != null) { - WebAuthnAuthenticatorsBean authenticators = new WebAuthnAuthenticatorsBean(context.getSession(), context.getRealm(), user, getCredentialType()); + WebAuthnMetadataService metadataService = getCredentialProvider(context.getSession()).getMetadataService(); + WebAuthnAuthenticatorsBean authenticators = new WebAuthnAuthenticatorsBean(context.getSession(), context.getRealm(), user, getCredentialType(), metadataService); if (authenticators.getAuthenticators() != null) { provider.setAttribute(WebAuthnConstants.ALLOWED_AUTHENTICATORS, authenticators); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticatorMetadata.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticatorMetadata.java new file mode 100644 index 00000000000..f8f832a6c45 --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnAuthenticatorMetadata.java @@ -0,0 +1,16 @@ +package org.keycloak.authentication.authenticators.browser; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Metadata for a WebAuthn authenticator identified by its AAGUID. + * + * @param name human-readable authenticator provider name + * @param iconLight icon for light theme (data URI) + * @param iconDark icon for dark theme (data URI) + */ +public record WebAuthnAuthenticatorMetadata( + String name, + @JsonProperty("icon_light") String iconLight, + @JsonProperty("icon_dark") String iconDark) { +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnMetadataService.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnMetadataService.java index 9f92372a256..6cbb04fc49b 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnMetadataService.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/WebAuthnMetadataService.java @@ -3,57 +3,66 @@ package org.keycloak.authentication.authenticators.browser; import java.io.IOException; import java.io.InputStream; import java.util.Map; -import java.util.stream.Collectors; import org.keycloak.util.JsonSerialization; import org.keycloak.utils.FileUtils; +import org.keycloak.utils.StringUtil; import com.fasterxml.jackson.core.type.TypeReference; +import org.jboss.logging.Logger; /** - * Provides metadata for WebAuthn credentials + * Provides metadata for WebAuthn credentials. + * Based on passkey-authenticator-aaguids * * @author Marek Posolda */ public class WebAuthnMetadataService { - // Based on https://github.com/duo-labs/webauthn.io/blob/master/_app/homepage/services/metadata.py + private static final Logger logger = Logger.getLogger(WebAuthnMetadataService.class); private static final String FILE_NAME = "keycloak-webauthn-metadata.json"; - private Map aaguidToProviderNames; + private static volatile Map aaguidToMetadata; - private Map readMetadata() { + public static void setDefaultMetadata(Map metadata) { + if (aaguidToMetadata == null) { + aaguidToMetadata = metadata; + } + } + + private Map getAaguidToMetadata() { + if (aaguidToMetadata == null) { + synchronized (this) { + if (aaguidToMetadata == null) { + aaguidToMetadata = parseMetadata(); + } + } + } + return aaguidToMetadata; + } + + public static Map parseMetadata() { try { try (InputStream is = FileUtils.getJsonFileFromClasspathOrConfFolder(FILE_NAME)) { - Map> map = JsonSerialization.readValue(is, new TypeReference<>() {}); - return map.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> { - String value = entry.getValue().get("name"); - if (value == null) { - throw new IllegalStateException("Not found 'name' for the AAGUID '" + entry.getKey() + "' in the file '" + FILE_NAME + "'."); - } - return value; - })); + Map parsed = JsonSerialization.readValue(is, new TypeReference<>() {}); + for (Map.Entry entry : parsed.entrySet()) { + if (StringUtil.isBlank(entry.getValue().name())) { + throw new IllegalStateException("Not found 'name' for the AAGUID '" + entry.getKey() + "' in the file '" + FILE_NAME + "'."); + } + } + return parsed; } } catch (IOException ioe) { throw new IllegalStateException("Error loading the webauthn metadata from file " + FILE_NAME, ioe); } - } - private Map getAaguidToProviderNames() { - if (aaguidToProviderNames == null) { - synchronized (this) { - if (aaguidToProviderNames == null) { - // Make sure the file is not parsed during server startup, but "lazily" when needed for the 1st time - this.aaguidToProviderNames = readMetadata(); - } - } - } - return aaguidToProviderNames; + public WebAuthnAuthenticatorMetadata getAuthenticatorMetadata(String aaguid) { + return aaguid == null ? null : getAaguidToMetadata().get(aaguid); } public String getAuthenticatorProvider(String aaguid) { - return aaguid == null ? null : getAaguidToProviderNames().get(aaguid); + WebAuthnAuthenticatorMetadata metadata = getAuthenticatorMetadata(aaguid); + return metadata == null ? null : metadata.name(); } } diff --git a/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProvider.java b/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProvider.java index 325526a33d4..413c01a9fd4 100644 --- a/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProvider.java +++ b/services/src/main/java/org/keycloak/credential/WebAuthnCredentialProvider.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import jakarta.annotation.Nonnull; +import org.keycloak.authentication.authenticators.browser.WebAuthnAuthenticatorMetadata; import org.keycloak.authentication.authenticators.browser.WebAuthnMetadataService; import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory; import org.keycloak.common.util.Time; @@ -103,13 +104,14 @@ public class WebAuthnCredentialProvider implements CredentialProvider authenticators; - public WebAuthnAuthenticatorsBean(KeycloakSession session, RealmModel realm, UserModel user, String credentialType) { + public WebAuthnAuthenticatorsBean(KeycloakSession session, RealmModel realm, UserModel user, String credentialType, + WebAuthnMetadataService metadataService) { // should consider multiple credentials in the future, but only single credential supported now. this.authenticators = user.credentialManager().getStoredCredentialsByTypeStream(credentialType) .map(WebAuthnCredentialModel::createFromCredentialModel) @@ -47,7 +50,13 @@ public class WebAuthnAuthenticatorsBean { String createdAt = DateTimeFormatterUtil.getDateTimeFromMillis(webAuthnCredential.getCreatedDate(), session.getContext().resolveLocale(user)); final Set transports = webAuthnCredential.getWebAuthnCredentialData().getTransports(); - return new WebAuthnAuthenticatorBean(credentialId, label, createdAt, transports); + String aaguid = webAuthnCredential.getWebAuthnCredentialData().getAaguid(); + WebAuthnAuthenticatorMetadata metadata = metadataService.getAuthenticatorMetadata(aaguid); + String authenticatorProvider = metadata != null ? metadata.name() : null; + String iconLight = metadata != null ? metadata.iconLight() : null; + String iconDark = metadata != null ? metadata.iconDark() : null; + + return new WebAuthnAuthenticatorBean(credentialId, label, createdAt, transports, authenticatorProvider, iconLight, iconDark); }).collect(Collectors.toList()); } @@ -63,12 +72,19 @@ public class WebAuthnAuthenticatorsBean { private final String label; private final String createdAt; private final TransportsBean transports; + private final String authenticatorProvider; + private final String iconLight; + private final String iconDark; - public WebAuthnAuthenticatorBean(String credentialId, String label, String createdAt, Set transports) { + public WebAuthnAuthenticatorBean(String credentialId, String label, String createdAt, Set transports, + String authenticatorProvider, String iconLight, String iconDark) { this.credentialId = credentialId; this.label = label; this.createdAt = createdAt; this.transports = TransportsBean.convertFromSet(transports); + this.authenticatorProvider = authenticatorProvider; + this.iconLight = iconLight; + this.iconDark = iconDark; } public String getCredentialId() { @@ -87,6 +103,18 @@ public class WebAuthnAuthenticatorsBean { return transports; } + public String getAuthenticatorProvider() { + return authenticatorProvider; + } + + public String getIconLight() { + return iconLight; + } + + public String getIconDark() { + return iconDark; + } + public static class TransportsBean { private final Set displayNameProperties; private final String iconClass; diff --git a/services/src/main/resources/WebAuthnMetadataReadme.md b/services/src/main/resources/WebAuthnMetadataReadme.md new file mode 100644 index 00000000000..62e4d8c4bb5 --- /dev/null +++ b/services/src/main/resources/WebAuthnMetadataReadme.md @@ -0,0 +1,29 @@ +# Updating WebAuthn / Passkey Metadata + +The file `keycloak-webauthn-metadata.json` maps passkey authenticator AAGUIDs to +display names and icon filenames. It is generated from the community-maintained +[passkey-authenticator-aaguids](https://github.com/passkeydeveloper/passkey-authenticator-aaguids) registry. + +## Steps to update + +1. Download the latest source data: + + ```sh + curl -LO https://raw.githubusercontent.com/passkeydeveloper/passkey-authenticator-aaguids/refs/heads/main/combined_aaguid.json + ``` + +2. Run the parser script, passing the downloaded file as an argument: + + ```sh + python .github/scripts/parse-webauthn-metadata.py combined_aaguid.json + ``` + +3. The script produces: + - `services/src/main/resources/keycloak-webauthn-metadata.json` (overwritten in place) + - Icon image files in two directories: + - `js/apps/account-ui/public/passkeys/` (account console) + - `themes/src/main/resources/theme/base/login/resources/img/passkeys/` (login theme) + +4. Review the changes before committing. In particular, inspect SVG icon files + for malicious content (e.g. `