class WebAuthn::FakeClient

Constants

TYPES

Attributes

authenticator[R]
encoding[R]
origin[R]
token_binding[R]

Public Class Methods

new( origin = fake_origin, token_binding: nil, authenticator: WebAuthn::FakeAuthenticator.new, encoding: WebAuthn.configuration.encoding ) click to toggle source
# File lib/webauthn/fake_client.rb, line 15
def initialize(
  origin = fake_origin,
  token_binding: nil,
  authenticator: WebAuthn::FakeAuthenticator.new,
  encoding: WebAuthn.configuration.encoding
)
  @origin = origin
  @token_binding = token_binding
  @authenticator = authenticator
  @encoding = encoding
end

Public Instance Methods

create( challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false, attested_credential_data: true, extensions: nil ) click to toggle source
# File lib/webauthn/fake_client.rb, line 27
def create(
  challenge: fake_challenge,
  rp_id: nil,
  user_present: true,
  user_verified: false,
  attested_credential_data: true,
  extensions: nil
)
  rp_id ||= URI.parse(origin).host

  client_data_json = data_json_for(:create, encoder.decode(challenge))
  client_data_hash = hashed(client_data_json)

  attestation_object = authenticator.make_credential(
    rp_id: rp_id,
    client_data_hash: client_data_hash,
    user_present: user_present,
    user_verified: user_verified,
    attested_credential_data: attested_credential_data,
    extensions: extensions
  )

  id =
    if attested_credential_data
      WebAuthn::AuthenticatorData
        .deserialize(CBOR.decode(attestation_object)["authData"])
        .attested_credential_data
        .id
    else
      "id-for-pk-without-attested-credential-data"
    end

  {
    "type" => "public-key",
    "id" => internal_encoder.encode(id),
    "rawId" => encoder.encode(id),
    "clientExtensionResults" => extensions,
    "response" => {
      "attestationObject" => encoder.encode(attestation_object),
      "clientDataJSON" => encoder.encode(client_data_json)
    }
  }
end
get(challenge: fake_challenge, rp_id: nil, user_present: true, user_verified: false, sign_count: nil, extensions: nil, user_handle: nil, allow_credentials: nil) click to toggle source
# File lib/webauthn/fake_client.rb, line 71
def get(challenge: fake_challenge,
        rp_id: nil,
        user_present: true,
        user_verified: false,
        sign_count: nil,
        extensions: nil,
        user_handle: nil,
        allow_credentials: nil)
  rp_id ||= URI.parse(origin).host

  client_data_json = data_json_for(:get, encoder.decode(challenge))
  client_data_hash = hashed(client_data_json)

  if allow_credentials
    allow_credentials = allow_credentials.map { |credential| encoder.decode(credential) }
  end

  assertion = authenticator.get_assertion(
    rp_id: rp_id,
    client_data_hash: client_data_hash,
    user_present: user_present,
    user_verified: user_verified,
    sign_count: sign_count,
    extensions: extensions,
    allow_credentials: allow_credentials
  )

  {
    "type" => "public-key",
    "id" => internal_encoder.encode(assertion[:credential_id]),
    "rawId" => encoder.encode(assertion[:credential_id]),
    "clientExtensionResults" => extensions,
    "response" => {
      "clientDataJSON" => encoder.encode(client_data_json),
      "authenticatorData" => encoder.encode(assertion[:authenticator_data]),
      "signature" => encoder.encode(assertion[:signature]),
      "userHandle" => user_handle ? encoder.encode(user_handle) : nil
    }
  }
end

Private Instance Methods

data_json_for(method, challenge) click to toggle source
# File lib/webauthn/fake_client.rb, line 116
def data_json_for(method, challenge)
  data = {
    type: type_for(method),
    challenge: internal_encoder.encode(challenge),
    origin: origin
  }

  if token_binding
    data[:tokenBinding] = token_binding
  end

  data.to_json
end
encoder() click to toggle source
# File lib/webauthn/fake_client.rb, line 130
def encoder
  @encoder ||= WebAuthn::Encoder.new(encoding)
end
fake_challenge() click to toggle source
# File lib/webauthn/fake_client.rb, line 142
def fake_challenge
  encoder.encode(SecureRandom.random_bytes(32))
end
fake_origin() click to toggle source
# File lib/webauthn/fake_client.rb, line 146
def fake_origin
  "http://localhost#{rand(1000)}.test"
end
hashed(data) click to toggle source
# File lib/webauthn/fake_client.rb, line 138
def hashed(data)
  OpenSSL::Digest::SHA256.digest(data)
end
internal_encoder() click to toggle source
# File lib/webauthn/fake_client.rb, line 134
def internal_encoder
  WebAuthn.standard_encoder
end
type_for(method) click to toggle source
# File lib/webauthn/fake_client.rb, line 150
def type_for(method)
  TYPES[method]
end