Files
fizzy/lib/action_pack/web_authn/authenticator/attestation_response.rb
T
Stanko K.R. 017bcc9ce1 Polish up Passkey interface
- Fix indentation
- Split awkward initializer into separate methods
- Rename credentials to passkeys
- Simplify authenticator registry loading
- Flatten nested errors under ActionPack::WebAuthn
- Set passkey current params only requests that use it
- Inline anemic methods
- Replace custom validation with ActiveModel::Validation
- Rename identity to holder in Passkey
- Rename credentials to passkeys in JS
- Extract framework library out of controllers
- Pass params hashes down to ActionPack
- Attempt to simplify public interface
- Push data decoding down to the classes representing the data
- Introduce has_passkeys
- Add CBOR bigint support
- Rename ActionPack::WebAuthn::Passkey to ActionPack::Passkey
- Add create_passkey_button helper
- Rename public-key to creation-options
- Add sign_in_with_passkey_button helper
- Dispatch events for the whole Passkey lifecycle
- Add ED25519 support
- Prevent crash on missing meta tag
- Validate resident key options
- Don't clobber existing ActionPack config options
- Validate cryptographic params
- Move CurrentWebAuthnRequest into ActionPack::Passkey
- Use ActiveModel::Attributes for Options objects
- Implement expiring challanges
- Add lifecycle events
- Extract param helpers into Request
- Add passkey_creation_options and passkey_request_options helpers
- Add create_passkey_challenge to make it easier to override the create method if needed
- Prefix all view helpers with passkey_
- Auto-include ActionPack::Passkey::Holder
- Make the passkey challange url configurable
- Add a reminder about Passkeys to the magic link email
2026-03-18 11:51:10 +01:00

69 lines
2.2 KiB
Ruby

# = Action Pack WebAuthn Attestation Response
#
# Handles the authenticator response from a WebAuthn registration ceremony.
# When a user registers a new credential, the authenticator returns an
# attestation response containing the new public key and credential ID.
#
# == Usage
#
# response = ActionPack::WebAuthn::Authenticator::AttestationResponse.new(
# client_data_json: params[:response][:clientDataJSON],
# attestation_object: params[:response][:attestationObject],
# challenge: ActionPack::WebAuthn::Current.challenge,
# origin: "https://example.com"
# )
#
# response.validate!
#
# # Store the credential
# credential_id = response.attestation.credential_id
# public_key = response.attestation.public_key
#
# == Validation
#
# In addition to the base Response validations, this class verifies:
#
# * The client data type is "webauthn.create"
# * The attestation format has a registered verifier
# * The attestation statement passes format-specific verification
#
class ActionPack::WebAuthn::Authenticator::AttestationResponse < ActionPack::WebAuthn::Authenticator::Response
attr_reader :attestation_object
validate :client_data_type_must_be_create
validate :attestation_must_be_valid
def initialize(attestation_object:, **attributes)
super(**attributes)
@attestation_object = attestation_object
end
# Returns the decoded Attestation object, lazily parsed from the raw
# attestation object bytes.
def attestation
@attestation ||= ActionPack::WebAuthn::Authenticator::Attestation.wrap(attestation_object)
end
# Returns the authenticator data extracted from the attestation object.
def authenticator_data
attestation.authenticator_data
end
private
def client_data_type_must_be_create
unless client_data["type"] == "webauthn.create"
errors.add(:base, "Client data type is not webauthn.create")
end
end
def attestation_must_be_valid
verifier = ActionPack::WebAuthn.attestation_verifiers[attestation.format]
if verifier
verifier.verify!(attestation, client_data_json: client_data_json)
else
errors.add(:base, "Unsupported attestation format: #{attestation.format}")
end
end
end