42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/better_auth/passkey/routes/registration.rb', line 42
def verify_passkey_registration_endpoint(config)
Endpoint.new(path: "/passkey/verify-registration", method: "POST") do |ctx|
body = Utils.normalize_hash(ctx.body)
Utils.require_key!(body, :response)
require_session = config.dig(:registration, :require_session) != false
session = require_session ? BetterAuth::Routes.current_session(ctx, sensitive: true) : BetterAuth::Routes.current_session(ctx, allow_nil: true)
origin = Utils.origin(config, ctx)
raise APIError.new("BAD_REQUEST", message: ErrorCodes::PASSKEY_ERROR_CODES.fetch("FAILED_TO_VERIFY_REGISTRATION")) if origin.to_s.empty?
verification_token = Challenges.challenge_token(ctx, config)
raise APIError.new("BAD_REQUEST", message: ErrorCodes::PASSKEY_ERROR_CODES.fetch("CHALLENGE_NOT_FOUND")) unless verification_token
challenge = Challenges.find_challenge(ctx, verification_token)
unless challenge
raise APIError.new("BAD_REQUEST", message: ErrorCodes::PASSKEY_ERROR_CODES.fetch("CHALLENGE_NOT_FOUND"))
end
if session && challenge.fetch("userData").fetch("id") != session.fetch(:user).fetch("id")
raise APIError.new("UNAUTHORIZED", message: ErrorCodes::PASSKEY_ERROR_CODES.fetch("YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY"))
end
response = Credentials.webauthn_response(body[:response])
relying_party = Utils.relying_party(config, ctx, origin: origin)
credential = WebAuthn::Credential.from_create(response, relying_party: relying_party)
credential.verify(challenge.fetch("expectedChallenge"), user_verification: false)
authenticator_data = Credentials.authenticator_data(credential)
target_user_id = Utils.after_registration_verification_user_id(config, ctx, credential, challenge, response, session)
data = ctx.context.adapter.create(
model: "passkey",
data: {
name: body[:name],
userId: target_user_id,
credentialID: credential.id,
publicKey: Base64.strict_encode64(credential.public_key),
counter: credential.sign_count,
deviceType: authenticator_data&.credential_backup_eligible? ? "multiDevice" : "singleDevice",
backedUp: authenticator_data&.credential_backed_up? || false,
transports: Array(Credentials.attestation_response(credential)&.transports).join(","),
createdAt: Time.now,
aaguid: Credentials.attestation_response(credential)&.aaguid
}
)
ctx.context.internal_adapter.delete_verification_by_identifier(verification_token)
ctx.json(Credentials.wire(data))
rescue WebAuthn::Error => error
ctx.context.logger&.error("Failed to verify registration", error)
raise APIError.new("INTERNAL_SERVER_ERROR", message: ErrorCodes::PASSKEY_ERROR_CODES.fetch("FAILED_TO_VERIFY_REGISTRATION"))
end
end
|