class WebAuthn::FakeClient

def create(

def create(
  challenge: fake_challenge,
  rp_id: nil,
  user_present: true,
  user_verified: false,
  backup_eligibility: false,
  backup_state: false,
  attested_credential_data: true,
  credential_algorithm: nil,
  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,
    backup_eligibility: backup_eligibility,
    backup_state: backup_state,
    attested_credential_data: attested_credential_data,
    algorithm: credential_algorithm,
    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),
    "authenticatorAttachment" => 'platform',
    "clientExtensionResults" => extensions,
    "response" => {
      "attestationObject" => encoder.encode(attestation_object),
      "clientDataJSON" => encoder.encode(client_data_json),
      "transports" => ["internal"],
    }
  }
end

def data_json_for(method, challenge)

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

def encoder

def encoder
  @encoder ||= WebAuthn::Encoder.new(encoding)
end

def fake_challenge

def fake_challenge
  encoder.encode(SecureRandom.random_bytes(32))
end

def fake_origin

def fake_origin
  "http://localhost#{rand(1000)}.test"
end

def get(challenge: fake_challenge,

def get(challenge: fake_challenge,
        rp_id: nil,
        user_present: true,
        user_verified: false,
        backup_eligibility: false,
        backup_state: true,
        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,
    backup_eligibility: backup_eligibility,
    backup_state: backup_state,
    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,
    "authenticatorAttachment" => 'platform',
    "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

def hashed(data)

def hashed(data)
  OpenSSL::Digest::SHA256.digest(data)
end

def initialize(

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

def internal_encoder

def internal_encoder
  WebAuthn.standard_encoder
end

def type_for(method)

def type_for(method)
  TYPES[method]
end