class WebAuthn::FakeAuthenticator

def get_assertion(

def get_assertion(
  rp_id:,
  client_data_hash:,
  user_present: true,
  user_verified: false,
  backup_eligibility: false,
  backup_state: false,
  aaguid: AuthenticatorData::AAGUID,
  sign_count: nil,
  extensions: nil,
  allow_credentials: nil
)
  credential_options = credentials[rp_id]
  if credential_options
    allow_credentials ||= credential_options.keys
    credential_id = (credential_options.keys & allow_credentials).first
    unless credential_id
      raise "No matching credentials (allowed=#{allow_credentials}) " \
            "found for RP #{rp_id} among credentials=#{credential_options}"
    end
    credential = credential_options[credential_id]
    credential_key = credential[:credential_key]
    credential_sign_count = credential[:sign_count]
    authenticator_data = AuthenticatorData.new(
      rp_id_hash: hashed(rp_id),
      user_present: user_present,
      user_verified: user_verified,
      backup_eligibility: backup_eligibility,
      backup_state: backup_state,
      aaguid: aaguid,
      credential: nil,
      sign_count: sign_count || credential_sign_count,
      extensions: extensions
    ).serialize
    signature_digest_algorithm =
      case credential_key
      when OpenSSL::PKey::RSA, OpenSSL::PKey::EC
        'SHA256'
      when OpenSSL::PKey::PKey
        nil
      end
    signature = credential_key.sign(signature_digest_algorithm, authenticator_data + client_data_hash)
    credential[:sign_count] += 1
    {
      credential_id: credential_id,
      authenticator_data: authenticator_data,
      signature: signature
    }
  else
    raise "No credentials found for RP #{rp_id}"
  end
end

def hashed(target)

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

def initialize

def initialize
  @credentials = {}
end

def make_credential(

def make_credential(
  rp_id:,
  client_data_hash:,
  user_present: true,
  user_verified: false,
  backup_eligibility: false,
  backup_state: false,
  attested_credential_data: true,
  algorithm: nil,
  sign_count: nil,
  extensions: nil
)
  credential_id, credential_key, credential_sign_count = new_credential(algorithm)
  sign_count ||= credential_sign_count
  credentials[rp_id] ||= {}
  credentials[rp_id][credential_id] = {
    credential_key: credential_key,
    sign_count: sign_count + 1
  }
  AttestationObject.new(
    client_data_hash: client_data_hash,
    rp_id_hash: hashed(rp_id),
    credential_id: credential_id,
    credential_key: credential_key,
    user_present: user_present,
    user_verified: user_verified,
    backup_eligibility: backup_eligibility,
    backup_state: backup_state,
    attested_credential_data: attested_credential_data,
    sign_count: sign_count,
    extensions: extensions
  ).serialize
end

def new_credential(algorithm)

def new_credential(algorithm)
  algorithm ||= 'ES256'
  credential_key =
    case algorithm
    when 'ES256'
      OpenSSL::PKey::EC.generate('prime256v1')
    when 'RS256'
      OpenSSL::PKey::RSA.new(2048)
    when 'EdDSA'
      OpenSSL::PKey.generate_key("ED25519")
    else
      raise "Unsupported algorithm #{algorithm}"
    end
  [SecureRandom.random_bytes(16), credential_key, 0]
end