Auto-suggest name for new Passkeys

- Use plain client data json everywhere
- Expose AAGUID and backed_up on Credentials
- Make attestation verifiers configurable
- Auto-suggest names for passkeys and show icons
This commit is contained in:
Stanko K.R.
2026-02-19 10:56:22 +01:00
parent b23660d897
commit fbe9252db1
53 changed files with 666 additions and 172 deletions
@@ -98,7 +98,7 @@ class ActionPack::WebAuthn::Authenticator::AttestationResponseTest < ActiveSuppo
assert_equal "Origin does not match", error.message
end
test "validate! raises when attestation format is not supported" do
test "validate! raises when attestation format is not registered" do
response = ActionPack::WebAuthn::Authenticator::AttestationResponse.new(
client_data_json: @client_data_json,
attestation_object: build_attestation_object(user_verified: true, format: "packed")
@@ -111,6 +111,24 @@ class ActionPack::WebAuthn::Authenticator::AttestationResponseTest < ActiveSuppo
assert_equal "Unsupported attestation format: packed", error.message
end
test "validate! calls registered verifier for custom format" do
verified = false
custom_verifier = Object.new
custom_verifier.define_singleton_method(:verify!) { |_attestation, client_data_json:| verified = true }
ActionPack::WebAuthn.register_attestation_verifier("packed", custom_verifier)
response = ActionPack::WebAuthn::Authenticator::AttestationResponse.new(
client_data_json: @client_data_json,
attestation_object: build_attestation_object(user_verified: true, format: "packed")
)
response.validate!(challenge: @challenge, origin: @origin)
assert verified
ensure
ActionPack::WebAuthn.attestation_verifiers.delete("packed")
end
private
def build_attestation_object(user_verified:, format: "none")
auth_data = build_authenticator_data(user_verified: user_verified)
@@ -0,0 +1,33 @@
require "test_helper"
class ActionPack::WebAuthn::Authenticator::AttestationVerifiers::NoneTest < ActiveSupport::TestCase
setup do
@verifier = ActionPack::WebAuthn::Authenticator::AttestationVerifiers::None.new
end
test "verify! passes with nil attestation statement" do
attestation = stub(attestation_statement: nil)
assert_nothing_raised do
@verifier.verify!(attestation, client_data_json: "")
end
end
test "verify! passes with empty attestation statement" do
attestation = stub(attestation_statement: {})
assert_nothing_raised do
@verifier.verify!(attestation, client_data_json: "")
end
end
test "verify! raises with non-empty attestation statement" do
attestation = stub(attestation_statement: { "sig" => "abc" })
error = assert_raises(ActionPack::WebAuthn::Authenticator::Response::InvalidResponseError) do
@verifier.verify!(attestation, client_data_json: "")
end
assert_equal "Attestation statement must be empty for 'none' format", error.message
end
end
@@ -84,6 +84,34 @@ class ActionPack::WebAuthn::PublicKeyCredential::CreationOptionsTest < ActiveSup
], options.as_json[:excludeCredentials]
end
test "as_json excludes attestation when none" do
assert_nil @options.as_json[:attestation]
end
test "as_json includes attestation when not none" do
options = ActionPack::WebAuthn::PublicKeyCredential::CreationOptions.new(
id: "user-123",
name: "user@example.com",
display_name: "Test User",
attestation: :direct,
relying_party: @relying_party
)
assert_equal "direct", options.as_json[:attestation]
end
test "raises with invalid attestation preference" do
assert_raises(ArgumentError) do
ActionPack::WebAuthn::PublicKeyCredential::CreationOptions.new(
id: "user-123",
name: "user@example.com",
display_name: "Test User",
attestation: :invalid,
relying_party: @relying_party
)
end
end
test "as_json excludeCredentials omits transports when empty" do
options = ActionPack::WebAuthn::PublicKeyCredential::CreationOptions.new(
id: "user-123",