blob: dd41ad280d6bbccc6d9af496d9e3b6ae41036ec0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h"
#include <algorithm>
#include <utility>
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom-blink.h"
#include "third_party/blink/public/mojom/webid/digital_identity_request.mojom-blink.h"
#include "third_party/blink/public/mojom/webid/federated_auth_request.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_client_inputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_client_outputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_large_blob_inputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_large_blob_outputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_payment_inputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_prf_inputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_prf_outputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_prf_values.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_supplemental_pub_keys_inputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_supplemental_pub_keys_outputs.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_authenticator_selection_criteria.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_cable_authentication_data.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_credential_disconnect_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_credential_request_options_context.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_credential_request_options_mode.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_provider_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_provider_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_identity_user_info.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_creation_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_descriptor.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_parameters.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_rp_entity.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_user_entity.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_remote_desktop_client_override.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
#include "third_party/blink/renderer/modules/credentialmanagement/credential.h"
#include "third_party/blink/renderer/modules/credentialmanagement/federated_credential.h"
#include "third_party/blink/renderer/modules/credentialmanagement/password_credential.h"
#include "third_party/blink/renderer/modules/credentialmanagement/public_key_credential.h"
#include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
namespace mojo {
using blink::mojom::blink::AttestationConveyancePreference;
using blink::mojom::blink::AuthenticationExtensionsClientInputs;
using blink::mojom::blink::AuthenticationExtensionsClientInputsPtr;
using blink::mojom::blink::AuthenticatorAttachment;
using blink::mojom::blink::AuthenticatorSelectionCriteria;
using blink::mojom::blink::AuthenticatorSelectionCriteriaPtr;
using blink::mojom::blink::AuthenticatorTransport;
using blink::mojom::blink::CableAuthentication;
using blink::mojom::blink::CableAuthenticationPtr;
using blink::mojom::blink::CredentialInfo;
using blink::mojom::blink::CredentialInfoPtr;
using blink::mojom::blink::CredentialType;
using blink::mojom::blink::Hint;
using blink::mojom::blink::IdentityCredentialDisconnectOptions;
using blink::mojom::blink::IdentityCredentialDisconnectOptionsPtr;
using blink::mojom::blink::IdentityProviderConfig;
using blink::mojom::blink::IdentityProviderConfigPtr;
using blink::mojom::blink::IdentityProviderRequestOptions;
using blink::mojom::blink::IdentityProviderRequestOptionsPtr;
using blink::mojom::blink::IdentityUserInfo;
using blink::mojom::blink::IdentityUserInfoPtr;
using blink::mojom::blink::LargeBlobSupport;
using blink::mojom::blink::PRFValues;
using blink::mojom::blink::PRFValuesPtr;
using blink::mojom::blink::PublicKeyCredentialCreationOptionsPtr;
using blink::mojom::blink::PublicKeyCredentialDescriptor;
using blink::mojom::blink::PublicKeyCredentialDescriptorPtr;
using blink::mojom::blink::PublicKeyCredentialParameters;
using blink::mojom::blink::PublicKeyCredentialParametersPtr;
using blink::mojom::blink::PublicKeyCredentialRequestOptionsPtr;
using blink::mojom::blink::PublicKeyCredentialRpEntity;
using blink::mojom::blink::PublicKeyCredentialRpEntityPtr;
using blink::mojom::blink::PublicKeyCredentialType;
using blink::mojom::blink::PublicKeyCredentialUserEntity;
using blink::mojom::blink::PublicKeyCredentialUserEntityPtr;
using blink::mojom::blink::RemoteDesktopClientOverride;
using blink::mojom::blink::RemoteDesktopClientOverridePtr;
using blink::mojom::blink::ResidentKeyRequirement;
using blink::mojom::blink::RpContext;
using blink::mojom::blink::RpMode;
using blink::mojom::blink::SupplementalPubKeysRequest;
using blink::mojom::blink::SupplementalPubKeysRequestPtr;
using blink::mojom::blink::UserVerificationRequirement;
namespace {
static constexpr int kCoseEs256 = -7;
static constexpr int kCoseRs256 = -257;
PublicKeyCredentialParametersPtr CreatePublicKeyCredentialParameter(int alg) {
auto mojo_parameter = PublicKeyCredentialParameters::New();
mojo_parameter->type = PublicKeyCredentialType::PUBLIC_KEY;
mojo_parameter->algorithm_identifier = alg;
return mojo_parameter;
}
// SortPRFValuesByCredentialId is a "less than" function that puts the single,
// optional element without a credential ID at the beginning and otherwise
// lexicographically sorts by credential ID. The browser requires that PRF
// values be presented in this order so that it can easily establish that there
// are no duplicates.
bool SortPRFValuesByCredentialId(const PRFValuesPtr& a, const PRFValuesPtr& b) {
if (!a->id.has_value()) {
return true;
} else if (!b->id.has_value()) {
return false;
} else {
return std::lexicographical_compare(a->id->begin(), a->id->end(),
b->id->begin(), b->id->end());
}
}
} // namespace
// static
CredentialInfoPtr TypeConverter<CredentialInfoPtr, blink::Credential*>::Convert(
blink::Credential* credential) {
auto info = CredentialInfo::New();
info->id = credential->id();
if (credential->IsPasswordCredential()) {
::blink::PasswordCredential* password_credential =
static_cast<::blink::PasswordCredential*>(credential);
info->type = CredentialType::PASSWORD;
info->password = password_credential->password();
info->name = password_credential->name();
info->icon = password_credential->iconURL();
info->federation = blink::SecurityOrigin::CreateUniqueOpaque();
} else {
DCHECK(credential->IsFederatedCredential());
::blink::FederatedCredential* federated_credential =
static_cast<::blink::FederatedCredential*>(credential);
info->type = CredentialType::FEDERATED;
info->password = g_empty_string;
info->federation = federated_credential->GetProviderAsOrigin();
info->name = federated_credential->name();
info->icon = federated_credential->iconURL();
}
return info;
}
// static
blink::Credential*
TypeConverter<blink::Credential*, CredentialInfoPtr>::Convert(
const CredentialInfoPtr& info) {
switch (info->type) {
case CredentialType::FEDERATED:
return blink::FederatedCredential::Create(info->id, info->federation,
info->name, info->icon);
case CredentialType::PASSWORD:
return blink::PasswordCredential::Create(info->id, info->password,
info->name, info->icon);
case CredentialType::EMPTY:
return nullptr;
}
NOTREACHED();
return nullptr;
}
static blink::DOMArrayBuffer* VectorToDOMArrayBuffer(
const Vector<uint8_t> buffer) {
return blink::DOMArrayBuffer::Create(static_cast<const void*>(buffer.data()),
buffer.size());
}
#if BUILDFLAG(IS_ANDROID)
static Vector<Vector<uint32_t>> UvmEntryToArray(
const Vector<blink::mojom::blink::UvmEntryPtr>& user_verification_methods) {
Vector<Vector<uint32_t>> uvm_array;
for (const auto& uvm : user_verification_methods) {
Vector<uint32_t> uvmEntry = {uvm->user_verification_method,
uvm->key_protection_type,
uvm->matcher_protection_type};
uvm_array.push_back(uvmEntry);
}
return uvm_array;
}
#endif
// static
blink::AuthenticationExtensionsClientOutputs*
TypeConverter<blink::AuthenticationExtensionsClientOutputs*,
blink::mojom::blink::AuthenticationExtensionsClientOutputsPtr>::
Convert(const blink::mojom::blink::AuthenticationExtensionsClientOutputsPtr&
extensions) {
auto* extension_outputs =
blink::AuthenticationExtensionsClientOutputs::Create();
if (extensions->echo_appid_extension) {
extension_outputs->setAppid(extensions->appid_extension);
}
#if BUILDFLAG(IS_ANDROID)
if (extensions->echo_user_verification_methods) {
extension_outputs->setUvm(
UvmEntryToArray(std::move(*extensions->user_verification_methods)));
}
#endif
if (extensions->echo_large_blob) {
DCHECK(blink::RuntimeEnabledFeatures::
WebAuthenticationLargeBlobExtensionEnabled());
blink::AuthenticationExtensionsLargeBlobOutputs* large_blob_outputs =
blink::AuthenticationExtensionsLargeBlobOutputs::Create();
if (extensions->large_blob) {
large_blob_outputs->setBlob(
VectorToDOMArrayBuffer(std::move(*extensions->large_blob)));
}
if (extensions->echo_large_blob_written) {
large_blob_outputs->setWritten(extensions->large_blob_written);
}
extension_outputs->setLargeBlob(large_blob_outputs);
}
if (extensions->get_cred_blob) {
extension_outputs->setGetCredBlob(
VectorToDOMArrayBuffer(std::move(*extensions->get_cred_blob)));
}
if (extensions->supplemental_pub_keys) {
extension_outputs->setSupplementalPubKeys(
ConvertTo<blink::AuthenticationExtensionsSupplementalPubKeysOutputs*>(
extensions->supplemental_pub_keys));
}
if (extensions->echo_prf) {
auto* prf_outputs = blink::AuthenticationExtensionsPRFOutputs::Create();
if (extensions->prf_results) {
auto* values = blink::AuthenticationExtensionsPRFValues::Create();
values->setFirst(
MakeGarbageCollected<blink::V8UnionArrayBufferOrArrayBufferView>(
VectorToDOMArrayBuffer(
std::move(extensions->prf_results->first))));
if (extensions->prf_results->second) {
values->setSecond(
MakeGarbageCollected<blink::V8UnionArrayBufferOrArrayBufferView>(
VectorToDOMArrayBuffer(
std::move(extensions->prf_results->second.value()))));
}
prf_outputs->setResults(values);
}
extension_outputs->setPrf(prf_outputs);
}
return extension_outputs;
}
// static
blink::AuthenticationExtensionsSupplementalPubKeysOutputs*
TypeConverter<blink::AuthenticationExtensionsSupplementalPubKeysOutputs*,
blink::mojom::blink::SupplementalPubKeysResponsePtr>::
Convert(const blink::mojom::blink::SupplementalPubKeysResponsePtr&
supplemental_pub_keys) {
blink::HeapVector<blink::Member<blink::DOMArrayBuffer>> signatures;
for (const auto& sig : supplemental_pub_keys->signatures) {
signatures.push_back(VectorToDOMArrayBuffer(std::move(sig)));
}
auto* spk_outputs =
blink::AuthenticationExtensionsSupplementalPubKeysOutputs::Create();
spk_outputs->setSignatures(std::move(signatures));
return spk_outputs;
}
// static
Vector<uint8_t>
TypeConverter<Vector<uint8_t>, blink::V8UnionArrayBufferOrArrayBufferView*>::
Convert(const blink::V8UnionArrayBufferOrArrayBufferView* buffer) {
DCHECK(buffer);
Vector<uint8_t> vector;
switch (buffer->GetContentType()) {
case blink::V8UnionArrayBufferOrArrayBufferView::ContentType::kArrayBuffer:
vector.Append(static_cast<uint8_t*>(buffer->GetAsArrayBuffer()->Data()),
base::checked_cast<wtf_size_t>(
buffer->GetAsArrayBuffer()->ByteLength()));
break;
case blink::V8UnionArrayBufferOrArrayBufferView::ContentType::
kArrayBufferView:
vector.Append(
static_cast<uint8_t*>(buffer->GetAsArrayBufferView()->BaseAddress()),
base::checked_cast<wtf_size_t>(
buffer->GetAsArrayBufferView()->byteLength()));
break;
}
return vector;
}
// static
PublicKeyCredentialType TypeConverter<PublicKeyCredentialType, String>::Convert(
const String& type) {
if (type == "public-key")
return PublicKeyCredentialType::PUBLIC_KEY;
NOTREACHED();
return PublicKeyCredentialType::PUBLIC_KEY;
}
// static
std::optional<AuthenticatorTransport>
TypeConverter<std::optional<AuthenticatorTransport>, String>::Convert(
const String& transport) {
if (transport == "usb")
return AuthenticatorTransport::USB;
if (transport == "nfc")
return AuthenticatorTransport::NFC;
if (transport == "ble")
return AuthenticatorTransport::BLE;
// "cable" is the old name for "hybrid" and we accept either.
if (transport == "cable" || transport == "hybrid")
return AuthenticatorTransport::HYBRID;
if (transport == "internal")
return AuthenticatorTransport::INTERNAL;
return std::nullopt;
}
// static
String TypeConverter<String, AuthenticatorTransport>::Convert(
const AuthenticatorTransport& transport) {
if (transport == AuthenticatorTransport::USB)
return "usb";
if (transport == AuthenticatorTransport::NFC)
return "nfc";
if (transport == AuthenticatorTransport::BLE)
return "ble";
if (transport == AuthenticatorTransport::HYBRID)
return "hybrid";
if (transport == AuthenticatorTransport::INTERNAL)
return "internal";
NOTREACHED();
return "usb";
}
// static
std::optional<blink::mojom::blink::ResidentKeyRequirement>
TypeConverter<std::optional<blink::mojom::blink::ResidentKeyRequirement>,
String>::Convert(const String& requirement) {
if (requirement == "discouraged")
return ResidentKeyRequirement::DISCOURAGED;
if (requirement == "preferred")
return ResidentKeyRequirement::PREFERRED;
if (requirement == "required")
return ResidentKeyRequirement::REQUIRED;
// AuthenticatorSelection.resident_key is defined as DOMString expressing a
// ResidentKeyRequirement and unknown values must be treated as if the
// property were unset.
return std::nullopt;
}
// static
std::optional<UserVerificationRequirement>
TypeConverter<std::optional<UserVerificationRequirement>, String>::Convert(
const String& requirement) {
if (requirement == "required")
return UserVerificationRequirement::REQUIRED;
if (requirement == "preferred")
return UserVerificationRequirement::PREFERRED;
if (requirement == "discouraged")
return UserVerificationRequirement::DISCOURAGED;
return std::nullopt;
}
// static
std::optional<AttestationConveyancePreference>
TypeConverter<std::optional<AttestationConveyancePreference>, String>::Convert(
const String& preference) {
if (preference == "none")
return AttestationConveyancePreference::NONE;
if (preference == "indirect")
return AttestationConveyancePreference::INDIRECT;
if (preference == "direct")
return AttestationConveyancePreference::DIRECT;
if (preference == "enterprise")
return AttestationConveyancePreference::ENTERPRISE;
return std::nullopt;
}
// static
std::optional<AuthenticatorAttachment> TypeConverter<
std::optional<AuthenticatorAttachment>,
std::optional<String>>::Convert(const std::optional<String>& attachment) {
if (!attachment.has_value())
return AuthenticatorAttachment::NO_PREFERENCE;
if (attachment.value() == "platform")
return AuthenticatorAttachment::PLATFORM;
if (attachment.value() == "cross-platform")
return AuthenticatorAttachment::CROSS_PLATFORM;
return std::nullopt;
}
// static
LargeBlobSupport
TypeConverter<LargeBlobSupport, std::optional<String>>::Convert(
const std::optional<String>& large_blob_support) {
if (large_blob_support) {
if (*large_blob_support == "required")
return LargeBlobSupport::REQUIRED;
if (*large_blob_support == "preferred")
return LargeBlobSupport::PREFERRED;
}
// Unknown values are treated as preferred.
return LargeBlobSupport::PREFERRED;
}
// static
AuthenticatorSelectionCriteriaPtr
TypeConverter<AuthenticatorSelectionCriteriaPtr,
blink::AuthenticatorSelectionCriteria>::
Convert(const blink::AuthenticatorSelectionCriteria& criteria) {
auto mojo_criteria =
blink::mojom::blink::AuthenticatorSelectionCriteria::New();
mojo_criteria->authenticator_attachment =
AuthenticatorAttachment::NO_PREFERENCE;
if (criteria.hasAuthenticatorAttachment()) {
std::optional<String> attachment = criteria.authenticatorAttachment();
auto maybe_attachment =
ConvertTo<std::optional<AuthenticatorAttachment>>(attachment);
if (maybe_attachment) {
mojo_criteria->authenticator_attachment = *maybe_attachment;
}
}
std::optional<ResidentKeyRequirement> resident_key;
if (criteria.hasResidentKey()) {
resident_key = ConvertTo<std::optional<ResidentKeyRequirement>>(
criteria.residentKey());
}
if (resident_key) {
mojo_criteria->resident_key = *resident_key;
} else {
mojo_criteria->resident_key = criteria.requireResidentKey()
? ResidentKeyRequirement::REQUIRED
: ResidentKeyRequirement::DISCOURAGED;
}
mojo_criteria->user_verification = UserVerificationRequirement::PREFERRED;
if (criteria.hasUserVerification()) {
std::optional<UserVerificationRequirement> user_verification =
ConvertTo<std::optional<UserVerificationRequirement>>(
criteria.userVerification());
if (user_verification) {
mojo_criteria->user_verification = *user_verification;
}
}
return mojo_criteria;
}
// static
PublicKeyCredentialUserEntityPtr
TypeConverter<PublicKeyCredentialUserEntityPtr,
blink::PublicKeyCredentialUserEntity>::
Convert(const blink::PublicKeyCredentialUserEntity& user) {
auto entity = PublicKeyCredentialUserEntity::New();
// PublicKeyCredentialEntity
entity->name = user.name();
// PublicKeyCredentialUserEntity
entity->id = ConvertTo<Vector<uint8_t>>(user.id());
entity->display_name = user.displayName();
return entity;
}
// static
PublicKeyCredentialRpEntityPtr
TypeConverter<PublicKeyCredentialRpEntityPtr,
blink::PublicKeyCredentialRpEntity>::
Convert(const blink::PublicKeyCredentialRpEntity& rp) {
auto entity = PublicKeyCredentialRpEntity::New();
// PublicKeyCredentialEntity
if (!rp.name()) {
return nullptr;
}
entity->name = rp.name();
// PublicKeyCredentialRpEntity
if (rp.hasId()) {
entity->id = rp.id();
}
return entity;
}
// static
PublicKeyCredentialDescriptorPtr
TypeConverter<PublicKeyCredentialDescriptorPtr,
blink::PublicKeyCredentialDescriptor>::
Convert(const blink::PublicKeyCredentialDescriptor& descriptor) {
auto mojo_descriptor = PublicKeyCredentialDescriptor::New();
mojo_descriptor->type = ConvertTo<PublicKeyCredentialType>(
blink::IDLEnumAsString(descriptor.type()));
mojo_descriptor->id = ConvertTo<Vector<uint8_t>>(descriptor.id());
if (descriptor.hasTransports() && !descriptor.transports().empty()) {
for (const auto& transport : descriptor.transports()) {
auto maybe_transport(
ConvertTo<std::optional<AuthenticatorTransport>>(transport));
if (maybe_transport) {
mojo_descriptor->transports.push_back(*maybe_transport);
}
}
} else {
mojo_descriptor->transports = {
AuthenticatorTransport::USB, AuthenticatorTransport::BLE,
AuthenticatorTransport::NFC, AuthenticatorTransport::HYBRID,
AuthenticatorTransport::INTERNAL};
}
return mojo_descriptor;
}
// static
PublicKeyCredentialParametersPtr
TypeConverter<PublicKeyCredentialParametersPtr,
blink::PublicKeyCredentialParameters>::
Convert(const blink::PublicKeyCredentialParameters& parameter) {
auto mojo_parameter = PublicKeyCredentialParameters::New();
mojo_parameter->type = ConvertTo<PublicKeyCredentialType>(
blink::IDLEnumAsString(parameter.type()));
// A COSEAlgorithmIdentifier's value is a number identifying a cryptographic
// algorithm. Values are registered in the IANA COSE Algorithms registry.
// https://www.iana.org/assignments/cose/cose.xhtml#algorithms
mojo_parameter->algorithm_identifier = parameter.alg();
return mojo_parameter;
}
// static
PublicKeyCredentialCreationOptionsPtr
TypeConverter<PublicKeyCredentialCreationOptionsPtr,
blink::PublicKeyCredentialCreationOptions>::
Convert(const blink::PublicKeyCredentialCreationOptions& options) {
auto mojo_options =
blink::mojom::blink::PublicKeyCredentialCreationOptions::New();
mojo_options->relying_party =
PublicKeyCredentialRpEntity::From(*options.rp());
mojo_options->user = PublicKeyCredentialUserEntity::From(*options.user());
if (!mojo_options->relying_party || !mojo_options->user) {
return nullptr;
}
mojo_options->challenge = ConvertTo<Vector<uint8_t>>(options.challenge());
// Steps 7 and 8 of https://w3c.github.io/webauthn/#sctn-createCredential
Vector<PublicKeyCredentialParametersPtr> parameters;
if (options.pubKeyCredParams().size() == 0) {
parameters.push_back(CreatePublicKeyCredentialParameter(kCoseEs256));
parameters.push_back(CreatePublicKeyCredentialParameter(kCoseRs256));
} else {
for (auto& parameter : options.pubKeyCredParams()) {
PublicKeyCredentialParametersPtr normalized_parameter =
PublicKeyCredentialParameters::From(*parameter);
if (normalized_parameter) {
parameters.push_back(std::move(normalized_parameter));
}
}
if (parameters.empty()) {
return nullptr;
}
}
mojo_options->public_key_parameters = std::move(parameters);
if (options.hasTimeout()) {
mojo_options->timeout = base::Milliseconds(options.timeout());
}
// Adds the excludeCredentials members
for (auto& descriptor : options.excludeCredentials()) {
PublicKeyCredentialDescriptorPtr mojo_descriptor =
PublicKeyCredentialDescriptor::From(*descriptor);
if (mojo_descriptor) {
mojo_options->exclude_credentials.push_back(std::move(mojo_descriptor));
}
}
if (options.hasAuthenticatorSelection()) {
mojo_options->authenticator_selection =
AuthenticatorSelectionCriteria::From(*options.authenticatorSelection());
}
mojo_options->hints = ConvertTo<Vector<Hint>>(options.hints());
mojo_options->attestation = AttestationConveyancePreference::NONE;
if (options.hasAttestation()) {
std::optional<AttestationConveyancePreference> attestation =
ConvertTo<std::optional<AttestationConveyancePreference>>(
options.attestation());
if (attestation) {
mojo_options->attestation = *attestation;
}
}
mojo_options->protection_policy = blink::mojom::ProtectionPolicy::UNSPECIFIED;
mojo_options->enforce_protection_policy = false;
if (options.hasExtensions()) {
auto* extensions = options.extensions();
if (extensions->hasAppidExclude()) {
mojo_options->appid_exclude = extensions->appidExclude();
}
if (extensions->hasHmacCreateSecret()) {
mojo_options->hmac_create_secret = extensions->hmacCreateSecret();
}
if (extensions->hasCredentialProtectionPolicy()) {
const auto& policy = extensions->credentialProtectionPolicy();
if (policy == "userVerificationOptional") {
mojo_options->protection_policy = blink::mojom::ProtectionPolicy::NONE;
} else if (policy == "userVerificationOptionalWithCredentialIDList") {
mojo_options->protection_policy =
blink::mojom::ProtectionPolicy::UV_OR_CRED_ID_REQUIRED;
} else if (policy == "userVerificationRequired") {
mojo_options->protection_policy =
blink::mojom::ProtectionPolicy::UV_REQUIRED;
} else {
return nullptr;
}
}
if (extensions->hasEnforceCredentialProtectionPolicy() &&
extensions->enforceCredentialProtectionPolicy()) {
mojo_options->enforce_protection_policy = true;
}
if (extensions->credProps()) {
mojo_options->cred_props = true;
}
if (extensions->hasLargeBlob()) {
std::optional<WTF::String> support;
if (extensions->largeBlob()->hasSupport()) {
support = extensions->largeBlob()->support();
}
mojo_options->large_blob_enable = ConvertTo<LargeBlobSupport>(support);
}
if (extensions->hasCredBlob()) {
mojo_options->cred_blob =
ConvertTo<Vector<uint8_t>>(extensions->credBlob());
}
if (extensions->hasPayment() && extensions->payment()->hasIsPayment() &&
extensions->payment()->isPayment()) {
mojo_options->is_payment_credential_creation = true;
}
if (extensions->hasMinPinLength() && extensions->minPinLength()) {
mojo_options->min_pin_length_requested = true;
}
if (extensions->hasRemoteDesktopClientOverride()) {
mojo_options->remote_desktop_client_override =
RemoteDesktopClientOverride::From(
*extensions->remoteDesktopClientOverride());
}
if (extensions->hasSupplementalPubKeys()) {
auto supplemental_pub_keys =
ConvertTo<std::optional<SupplementalPubKeysRequestPtr>>(
*extensions->supplementalPubKeys());
if (supplemental_pub_keys) {
mojo_options->supplemental_pub_keys = std::move(*supplemental_pub_keys);
}
}
if (extensions->hasPrf()) {
mojo_options->prf_enable = true;
if (extensions->prf()->hasEval()) {
mojo_options->prf_input =
ConvertTo<PRFValuesPtr>(*extensions->prf()->eval());
}
}
}
return mojo_options;
}
static Vector<uint8_t> ConvertFixedSizeArray(
const blink::V8BufferSource* buffer,
unsigned length) {
if (blink::DOMArrayPiece(buffer).ByteLength() != length) {
return {};
}
return ConvertTo<Vector<uint8_t>>(buffer);
}
// static
CableAuthenticationPtr
TypeConverter<CableAuthenticationPtr, blink::CableAuthenticationData>::Convert(
const blink::CableAuthenticationData& data) {
auto entity = CableAuthentication::New();
entity->version = data.version();
switch (entity->version) {
case 1:
entity->client_eid = ConvertFixedSizeArray(data.clientEid(), 16);
entity->authenticator_eid =
ConvertFixedSizeArray(data.authenticatorEid(), 16);
entity->session_pre_key = ConvertFixedSizeArray(data.sessionPreKey(), 32);
if (entity->client_eid->empty() || entity->authenticator_eid->empty() ||
entity->session_pre_key->empty()) {
return nullptr;
}
break;
case 2:
entity->server_link_data =
ConvertTo<Vector<uint8_t>>(data.sessionPreKey());
if (entity->server_link_data->empty()) {
return nullptr;
}
entity->experiments = ConvertTo<Vector<uint8_t>>(data.clientEid());
break;
default:
return nullptr;
}
return entity;
}
// static
PublicKeyCredentialRequestOptionsPtr
TypeConverter<PublicKeyCredentialRequestOptionsPtr,
blink::PublicKeyCredentialRequestOptions>::
Convert(const blink::PublicKeyCredentialRequestOptions& options) {
auto mojo_options =
blink::mojom::blink::PublicKeyCredentialRequestOptions::New();
mojo_options->challenge = ConvertTo<Vector<uint8_t>>(options.challenge());
if (options.hasTimeout()) {
mojo_options->timeout = base::Milliseconds(options.timeout());
}
if (options.hasRpId()) {
mojo_options->relying_party_id = options.rpId();
}
// Adds the allowList members
for (auto descriptor : options.allowCredentials()) {
PublicKeyCredentialDescriptorPtr mojo_descriptor =
PublicKeyCredentialDescriptor::From(*descriptor);
if (mojo_descriptor) {
mojo_options->allow_credentials.push_back(std::move(mojo_descriptor));
}
}
mojo_options->user_verification = UserVerificationRequirement::PREFERRED;
if (options.hasUserVerification()) {
std::optional<UserVerificationRequirement> user_verification =
ConvertTo<std::optional<UserVerificationRequirement>>(
options.userVerification());
if (user_verification) {
mojo_options->user_verification = *user_verification;
}
}
mojo_options->hints = ConvertTo<Vector<Hint>>(options.hints());
if (options.hasExtensions()) {
mojo_options->extensions =
ConvertTo<blink::mojom::blink::AuthenticationExtensionsClientInputsPtr>(
*options.extensions());
} else {
mojo_options->extensions =
blink::mojom::blink::AuthenticationExtensionsClientInputs::New();
}
return mojo_options;
}
// static
AuthenticationExtensionsClientInputsPtr
TypeConverter<AuthenticationExtensionsClientInputsPtr,
blink::AuthenticationExtensionsClientInputs>::
Convert(const blink::AuthenticationExtensionsClientInputs& inputs) {
auto mojo_inputs =
blink::mojom::blink::AuthenticationExtensionsClientInputs::New();
if (inputs.hasAppid()) {
mojo_inputs->appid = inputs.appid();
}
if (inputs.hasCableAuthentication()) {
Vector<CableAuthenticationPtr> mojo_data;
for (auto& data : inputs.cableAuthentication()) {
if (data->version() < 1 || data->version() > 2) {
continue;
}
CableAuthenticationPtr mojo_cable = CableAuthentication::From(*data);
if (mojo_cable) {
mojo_data.push_back(std::move(mojo_cable));
}
}
if (mojo_data.size() > 0) {
mojo_inputs->cable_authentication_data = std::move(mojo_data);
}
}
#if BUILDFLAG(IS_ANDROID)
if (inputs.hasUvm()) {
mojo_inputs->user_verification_methods = inputs.uvm();
}
#endif
if (inputs.hasLargeBlob()) {
if (inputs.largeBlob()->hasRead()) {
mojo_inputs->large_blob_read = inputs.largeBlob()->read();
}
if (inputs.largeBlob()->hasWrite()) {
mojo_inputs->large_blob_write =
ConvertTo<Vector<uint8_t>>(inputs.largeBlob()->write());
}
}
if (inputs.hasGetCredBlob() && inputs.getCredBlob()) {
mojo_inputs->get_cred_blob = true;
}
if (inputs.hasRemoteDesktopClientOverride()) {
mojo_inputs->remote_desktop_client_override =
RemoteDesktopClientOverride::From(
*inputs.remoteDesktopClientOverride());
}
if (inputs.hasSupplementalPubKeys()) {
auto supplemental_pub_keys =
ConvertTo<std::optional<SupplementalPubKeysRequestPtr>>(
*inputs.supplementalPubKeys());
if (supplemental_pub_keys) {
mojo_inputs->supplemental_pub_keys = std::move(*supplemental_pub_keys);
}
}
if (inputs.hasPrf()) {
mojo_inputs->prf = true;
mojo_inputs->prf_inputs = ConvertTo<Vector<PRFValuesPtr>>(*inputs.prf());
}
return mojo_inputs;
}
// static
RemoteDesktopClientOverridePtr
TypeConverter<RemoteDesktopClientOverridePtr,
blink::RemoteDesktopClientOverride>::
Convert(const blink::RemoteDesktopClientOverride& blink_value) {
return RemoteDesktopClientOverride::New(
blink::SecurityOrigin::CreateFromString(blink_value.origin()),
blink_value.sameOriginWithAncestors());
}
// static
IdentityProviderConfigPtr
TypeConverter<IdentityProviderConfigPtr, blink::IdentityProviderConfig>::
Convert(const blink::IdentityProviderConfig& provider) {
auto mojo_provider = IdentityProviderConfig::New();
mojo_provider->config_url = blink::KURL(provider.configURL());
mojo_provider->client_id = provider.clientId();
return mojo_provider;
}
// static
IdentityProviderRequestOptionsPtr
TypeConverter<IdentityProviderRequestOptionsPtr,
blink::IdentityProviderRequestOptions>::
Convert(const blink::IdentityProviderRequestOptions& options) {
auto mojo_options = IdentityProviderRequestOptions::New();
mojo_options->config = IdentityProviderConfig::New();
CHECK(options.hasConfigURL());
if (blink::RuntimeEnabledFeatures::FedCmIdPRegistrationEnabled() &&
options.configURL() == "any") {
mojo_options->config->use_registered_config_urls = true;
} else {
mojo_options->config->config_url = blink::KURL(options.configURL());
}
mojo_options->config->client_id = options.clientId();
mojo_options->nonce = options.getNonceOr("");
mojo_options->login_hint = options.getLoginHintOr("");
mojo_options->domain_hint =
blink::RuntimeEnabledFeatures::FedCmDomainHintEnabled()
? options.getDomainHintOr("")
: "";
// We do not need to check whether authz is enabled because the bindings
// code will check that for us due to the RuntimeEnabled= flag in the IDL.
if (options.hasScope()) {
mojo_options->scope = options.scope();
}
if (options.hasParams()) {
HashMap<String, String> params;
for (const auto& pair : options.params()) {
params.Set(pair.first, pair.second);
}
mojo_options->params = std::move(params);
}
return mojo_options;
}
// static
RpContext
TypeConverter<RpContext, blink::V8IdentityCredentialRequestOptionsContext>::
Convert(const blink::V8IdentityCredentialRequestOptionsContext& context) {
switch (context.AsEnum()) {
case blink::V8IdentityCredentialRequestOptionsContext::Enum::kSignin:
return RpContext::kSignIn;
case blink::V8IdentityCredentialRequestOptionsContext::Enum::kSignup:
return RpContext::kSignUp;
case blink::V8IdentityCredentialRequestOptionsContext::Enum::kUse:
return RpContext::kUse;
case blink::V8IdentityCredentialRequestOptionsContext::Enum::kContinue:
return RpContext::kContinue;
}
}
// static
RpMode
TypeConverter<RpMode, blink::V8IdentityCredentialRequestOptionsMode>::Convert(
const blink::V8IdentityCredentialRequestOptionsMode& mode) {
switch (mode.AsEnum()) {
case blink::V8IdentityCredentialRequestOptionsMode::Enum::kWidget:
return RpMode::kWidget;
case blink::V8IdentityCredentialRequestOptionsMode::Enum::kButton:
return RpMode::kButton;
}
}
IdentityUserInfoPtr
TypeConverter<IdentityUserInfoPtr, blink::IdentityUserInfo>::Convert(
const blink::IdentityUserInfo& user_info) {
auto mojo_user_info = IdentityUserInfo::New();
mojo_user_info->email = user_info.email();
mojo_user_info->given_name = user_info.givenName();
mojo_user_info->name = user_info.name();
mojo_user_info->picture = user_info.picture();
return mojo_user_info;
}
// static
std::optional<SupplementalPubKeysRequestPtr>
TypeConverter<std::optional<SupplementalPubKeysRequestPtr>,
blink::AuthenticationExtensionsSupplementalPubKeysInputs>::
Convert(const blink::AuthenticationExtensionsSupplementalPubKeysInputs&
supplemental_pub_keys) {
bool device_scope_requested = false;
bool provider_scope_requested = false;
for (auto& scope : supplemental_pub_keys.scopes()) {
if (scope == "device") {
device_scope_requested = true;
} else if (scope == "provider") {
provider_scope_requested = true;
}
}
if (!device_scope_requested && !provider_scope_requested) {
return std::nullopt;
}
auto ret = SupplementalPubKeysRequest::New();
ret->device_scope_requested = device_scope_requested;
ret->provider_scope_requested = provider_scope_requested;
ret->attestation = ConvertTo<std::optional<AttestationConveyancePreference>>(
supplemental_pub_keys.attestation())
.value_or(AttestationConveyancePreference::NONE);
ret->attestation_formats = supplemental_pub_keys.attestationFormats();
return ret;
}
// static
PRFValuesPtr
TypeConverter<PRFValuesPtr, blink::AuthenticationExtensionsPRFValues>::Convert(
const blink::AuthenticationExtensionsPRFValues& values) {
PRFValuesPtr ret = PRFValues::New();
ret->first = ConvertTo<Vector<uint8_t>>(values.first());
if (values.hasSecond()) {
ret->second = ConvertTo<Vector<uint8_t>>(values.second());
}
return ret;
}
// static
Vector<PRFValuesPtr>
TypeConverter<Vector<PRFValuesPtr>, blink::AuthenticationExtensionsPRFInputs>::
Convert(const blink::AuthenticationExtensionsPRFInputs& prf) {
Vector<PRFValuesPtr> ret;
if (prf.hasEval()) {
ret.push_back(ConvertTo<PRFValuesPtr>(*prf.eval()));
}
if (prf.hasEvalByCredential()) {
for (const auto& pair : prf.evalByCredential()) {
Vector<char> cred_id;
// The fact that this decodes successfully has already been tested.
CHECK(WTF::Base64UnpaddedURLDecode(pair.first, cred_id));
PRFValuesPtr values = ConvertTo<PRFValuesPtr>(*pair.second);
values->id = Vector<uint8_t>(base::as_bytes(base::make_span(cred_id)));
ret.emplace_back(std::move(values));
}
}
std::sort(ret.begin(), ret.end(), SortPRFValuesByCredentialId);
return ret;
}
// static
IdentityCredentialDisconnectOptionsPtr
TypeConverter<IdentityCredentialDisconnectOptionsPtr,
blink::IdentityCredentialDisconnectOptions>::
Convert(const blink::IdentityCredentialDisconnectOptions& options) {
auto mojo_disconnect_options = IdentityCredentialDisconnectOptions::New();
mojo_disconnect_options->config = IdentityProviderConfig::New();
mojo_disconnect_options->config->config_url =
blink::KURL(options.configURL());
mojo_disconnect_options->config->client_id = options.clientId();
mojo_disconnect_options->account_hint = options.accountHint();
return mojo_disconnect_options;
}
Vector<Hint> TypeConverter<Vector<Hint>, Vector<String>>::Convert(
const Vector<String>& hints) {
Vector<Hint> ret;
for (const String& hint : hints) {
if (hint == "security-key") {
ret.push_back(Hint::SECURITY_KEY);
} else if (hint == "client-device") {
ret.push_back(Hint::CLIENT_DEVICE);
} else if (hint == "hybrid") {
ret.push_back(Hint::HYBRID);
}
// Unrecognised values are ignored.
}
return ret;
}
} // namespace mojo