017bcc9ce1
- 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
69 lines
2.2 KiB
Ruby
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
|