blob: be912707c46e926343fcd118d79bfad564c8739c [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/trusted_vault/trusted_vault_connection_impl.h"
#include <algorithm>
#include <string>
#include <utility>
#include <variant>
#include "base/base64url.h"
#include "base/containers/span.h"
#include "base/files/important_file_writer.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/trusted_vault/download_keys_response_handler.h"
#include "components/trusted_vault/features.h"
#include "components/trusted_vault/proto/vault.pb.h"
#include "components/trusted_vault/proto_string_bytes_conversion.h"
#include "components/trusted_vault/securebox.h"
#include "components/trusted_vault/standalone_trusted_vault_server_constants.h"
#include "components/trusted_vault/trusted_vault_access_token_fetcher.h"
#include "components/trusted_vault/trusted_vault_connection.h"
#include "components/trusted_vault/trusted_vault_crypto.h"
#include "components/trusted_vault/trusted_vault_histograms.h"
#include "components/trusted_vault/trusted_vault_request.h"
#include "components/trusted_vault/trusted_vault_server_constants.h"
#include "net/base/url_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/abseil-cpp/absl/functional/overload.h"
namespace trusted_vault {
namespace {
TrustedVaultRequest::RecordFetchStatusCallback MakeFetchStatusCallback(
SecurityDomainId security_domain_id,
TrustedVaultURLFetchReasonForUMA reason) {
return base::BindRepeating(&RecordTrustedVaultURLFetchResponse,
security_domain_id, reason);
}
// Returns security domain epoch if valid (>0) and nullopt otherwise.
std::optional<int> GetLastKeyVersionFromJoinSecurityDomainsResponse(
const trusted_vault_pb::JoinSecurityDomainsResponse response) {
if (response.security_domain().current_epoch() > 0) {
return response.security_domain().current_epoch();
}
return std::nullopt;
}
// Returns security domain epoch if input is a valid response for already exists
// error case and nullopt otherwise.
std::optional<int> GetLastKeyVersionFromAlreadyExistsResponse(
const std::string& response_body) {
trusted_vault_pb::RPCStatus rpc_status;
rpc_status.ParseFromString(response_body);
for (const trusted_vault_pb::Proto3Any& status_detail :
rpc_status.details()) {
if (status_detail.type_url() != kJoinSecurityDomainsErrorDetailTypeURL) {
continue;
}
trusted_vault_pb::JoinSecurityDomainsErrorDetail error_detail;
error_detail.ParseFromString(status_detail.value());
return GetLastKeyVersionFromJoinSecurityDomainsResponse(
error_detail.already_exists_response());
}
return std::nullopt;
}
trusted_vault_pb::SharedMemberKey CreateSharedMemberKey(
const TrustedVaultKeyAndVersion& trusted_vault_key_and_version,
const SecureBoxPublicKey& public_key) {
trusted_vault_pb::SharedMemberKey shared_member_key;
shared_member_key.set_epoch(trusted_vault_key_and_version.version);
const std::vector<uint8_t>& trusted_vault_key =
trusted_vault_key_and_version.key;
AssignBytesToProtoString(
ComputeTrustedVaultWrappedKey(public_key, trusted_vault_key),
shared_member_key.mutable_wrapped_key());
AssignBytesToProtoString(ComputeMemberProof(public_key, trusted_vault_key),
shared_member_key.mutable_member_proof());
return shared_member_key;
}
trusted_vault_pb::SharedMemberKey CreateSharedMemberKey(
const MemberKeys& precomputed) {
trusted_vault_pb::SharedMemberKey shared_member_key;
shared_member_key.set_epoch(precomputed.version);
AssignBytesToProtoString(precomputed.wrapped_key,
shared_member_key.mutable_wrapped_key());
AssignBytesToProtoString(precomputed.proof,
shared_member_key.mutable_member_proof());
return shared_member_key;
}
trusted_vault_pb::PhysicalDeviceMetadata::DeviceType
GetLocalPhysicalDeviceType() {
// Note that some of the below are unreachable in practice as this code isn't
// currently used or even built on all platforms.
#if BUILDFLAG(IS_CHROMEOS)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_CHROMEOS;
#elif BUILDFLAG(IS_LINUX)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_LINUX;
#elif BUILDFLAG(IS_ANDROID)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_ANDROID;
#elif BUILDFLAG(IS_IOS)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_IOS;
#elif BUILDFLAG(IS_MAC)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_MAC_OS;
#elif BUILDFLAG(IS_WIN)
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_WINDOWS;
#elif BUILDFLAG(IS_FUCHSIA)
// Not used in Fuchsia.
return trusted_vault_pb::PhysicalDeviceMetadata::DEVICE_TYPE_UNKNOWN;
#else
#error Please handle your new device OS here.
#endif
}
trusted_vault_pb::SecurityDomainMember CreateSecurityDomainMember(
const SecureBoxPublicKey& public_key,
AuthenticationFactorTypeAndRegistrationParams
authentication_factor_type_and_registration_params) {
trusted_vault_pb::SecurityDomainMember member;
std::string public_key_string;
AssignBytesToProtoString(public_key.ExportToBytes(), &public_key_string);
std::string encoded_public_key;
base::Base64UrlEncode(public_key_string,
base::Base64UrlEncodePolicy::OMIT_PADDING,
&encoded_public_key);
member.set_name(kSecurityDomainMemberNamePrefix + encoded_public_key);
// Note: |public_key_string| using here is intentional, encoding is required
// only to compute member name.
member.set_public_key(public_key_string);
std::visit(
absl::Overload{
[&member](const LocalPhysicalDevice&) {
member.set_member_type(trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_PHYSICAL_DEVICE);
auto* member_metadata = member.mutable_member_metadata();
auto* physical_device_metadata =
member_metadata->mutable_physical_device_metadata();
physical_device_metadata->set_device_type(
GetLocalPhysicalDeviceType());
},
[&member](const LockScreenKnowledgeFactor&) {
member.set_member_type(trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_LOCKSCREEN_KNOWLEDGE_FACTOR);
},
[&member](const UnspecifiedAuthenticationFactorType&) {
member.set_member_type(trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_UNSPECIFIED);
// The type hint field is in the request protobuf, not the
// security domain member, and so is set in
// `CreateJoinSecurityDomainsRequest`.
},
[&member](const GpmPinMetadata& gpm_pin_metadata) {
member.set_member_type(trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_GOOGLE_PASSWORD_MANAGER_PIN);
auto* member_metadata = member.mutable_member_metadata();
auto* pin_metadata =
member_metadata->mutable_google_password_manager_pin_metadata();
pin_metadata->set_encrypted_pin_hash(
gpm_pin_metadata.usable_pin_metadata->wrapped_pin);
},
[&member](const ICloudKeychain&) {
member.set_member_type(trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_ICLOUD_KEYCHAIN);
}},
authentication_factor_type_and_registration_params);
return member;
}
void AddSharedMemberKeysFromSource(
trusted_vault_pb::JoinSecurityDomainsRequest* request,
const SecureBoxPublicKey& public_key,
const MemberKeysSource& member_keys_source) {
std::visit(
absl::Overload{
[request, &public_key](
const std::vector<TrustedVaultKeyAndVersion>& key_and_versions) {
for (const TrustedVaultKeyAndVersion&
trusted_vault_key_and_version : key_and_versions) {
*request->add_shared_member_key() = CreateSharedMemberKey(
trusted_vault_key_and_version, public_key);
}
},
[request](const MemberKeys& precomputed) {
*request->add_shared_member_key() =
CreateSharedMemberKey(precomputed);
}},
member_keys_source);
}
trusted_vault_pb::JoinSecurityDomainsRequest CreateJoinSecurityDomainsRequest(
SecurityDomainId security_domain,
const MemberKeysSource& member_keys_source,
const SecureBoxPublicKey& public_key,
AuthenticationFactorTypeAndRegistrationParams
authentication_factor_type_and_registration_params) {
trusted_vault_pb::JoinSecurityDomainsRequest request;
request.mutable_security_domain()->set_name(
GetSecurityDomainPath(security_domain));
*request.mutable_security_domain_member() = CreateSecurityDomainMember(
public_key, authentication_factor_type_and_registration_params);
AddSharedMemberKeysFromSource(&request, public_key, member_keys_source);
if (auto* unspecified_type = std::get_if<UnspecifiedAuthenticationFactorType>(
&authentication_factor_type_and_registration_params)) {
request.set_member_type_hint(unspecified_type->value());
} else if (auto* gpm_pin_metadata = std::get_if<GpmPinMetadata>(
&authentication_factor_type_and_registration_params)) {
if (gpm_pin_metadata->public_key) {
request.set_current_public_key_to_replace(*gpm_pin_metadata->public_key);
}
}
return request;
}
void RunRegisterAuthenticationFactorCallback(
TrustedVaultConnection::RegisterAuthenticationFactorCallback callback,
TrustedVaultRegistrationStatus status,
int last_key_version) {
std::move(callback).Run(status, last_key_version);
}
void ProcessJoinSecurityDomainsResponse(
TrustedVaultConnectionImpl::JoinSecurityDomainsCallback callback,
TrustedVaultRequest::HttpStatus http_status,
const std::string& response_body) {
switch (http_status) {
case TrustedVaultRequest::HttpStatus::kSuccess:
case TrustedVaultRequest::HttpStatus::kConflict:
break;
case TrustedVaultRequest::HttpStatus::kNetworkError:
std::move(callback).Run(TrustedVaultRegistrationStatus::kNetworkError,
/*last_key_version=*/0);
return;
case TrustedVaultRequest::HttpStatus::kOtherError:
std::move(callback).Run(TrustedVaultRegistrationStatus::kOtherError,
/*last_key_version=*/0);
return;
case TrustedVaultRequest::HttpStatus::kTransientAccessTokenFetchError:
std::move(callback).Run(
TrustedVaultRegistrationStatus::kTransientAccessTokenFetchError,
/*last_key_version=*/0);
return;
case TrustedVaultRequest::HttpStatus::kPersistentAccessTokenFetchError:
std::move(callback).Run(
TrustedVaultRegistrationStatus::kPersistentAccessTokenFetchError,
/*last_key_version=*/0);
return;
case TrustedVaultRequest::HttpStatus::
kPrimaryAccountChangeAccessTokenFetchError:
std::move(callback).Run(TrustedVaultRegistrationStatus::
kPrimaryAccountChangeAccessTokenFetchError,
/*last_key_version=*/0);
return;
case TrustedVaultRequest::HttpStatus::kNotFound:
case TrustedVaultRequest::HttpStatus::kBadRequest:
// Local trusted vault keys are outdated.
std::move(callback).Run(
TrustedVaultRegistrationStatus::kLocalDataObsolete,
/*last_key_version=*/0);
return;
}
std::optional<int> last_key_version;
if (http_status == TrustedVaultRequest::HttpStatus::kConflict) {
last_key_version =
GetLastKeyVersionFromAlreadyExistsResponse(response_body);
} else {
trusted_vault_pb::JoinSecurityDomainsResponse response;
response.ParseFromString(response_body);
last_key_version =
GetLastKeyVersionFromJoinSecurityDomainsResponse(response);
}
if (!last_key_version.has_value()) {
std::move(callback).Run(TrustedVaultRegistrationStatus::kOtherError,
/*last_key_version=*/0);
return;
}
std::move(callback).Run(
http_status == TrustedVaultRequest::HttpStatus::kConflict
? TrustedVaultRegistrationStatus::kAlreadyRegistered
: TrustedVaultRegistrationStatus::kSuccess,
*last_key_version);
}
base::Time ToTime(const trusted_vault_pb::Timestamp& proto) {
return base::Time::UnixEpoch() + base::Seconds(proto.seconds()) +
base::Nanoseconds(proto.nanos());
}
void ProcessDownloadKeysResponse(
std::unique_ptr<DownloadKeysResponseHandler> response_handler,
TrustedVaultConnection::DownloadNewKeysCallback callback,
TrustedVaultRequest::HttpStatus http_status,
const std::string& response_body) {
DownloadKeysResponseHandler::ProcessedResponse processed_response =
response_handler->ProcessResponse(http_status, response_body);
std::move(callback).Run(processed_response.status,
processed_response.downloaded_keys,
processed_response.last_key_version);
}
void ProcessDownloadIsRecoverabilityDegradedResponse(
TrustedVaultConnection::IsRecoverabilityDegradedCallback callback,
TrustedVaultRequest::HttpStatus http_status,
const std::string& response_body) {
// TODO(crbug.com/40178774): consider special handling when security domain
// doesn't exist.
switch (http_status) {
case TrustedVaultRequest::HttpStatus::kSuccess:
break;
case TrustedVaultRequest::HttpStatus::kNetworkError:
case TrustedVaultRequest::HttpStatus::kOtherError:
case TrustedVaultRequest::HttpStatus::kNotFound:
case TrustedVaultRequest::HttpStatus::kBadRequest:
case TrustedVaultRequest::HttpStatus::kConflict:
case TrustedVaultRequest::HttpStatus::kTransientAccessTokenFetchError:
case TrustedVaultRequest::HttpStatus::kPersistentAccessTokenFetchError:
case TrustedVaultRequest::HttpStatus::
kPrimaryAccountChangeAccessTokenFetchError:
std::move(callback).Run(TrustedVaultRecoverabilityStatus::kError);
return;
}
trusted_vault_pb::SecurityDomain security_domain;
if (!security_domain.ParseFromString(response_body) ||
!security_domain.security_domain_details().has_sync_details()) {
std::move(callback).Run(TrustedVaultRecoverabilityStatus::kError);
return;
}
TrustedVaultRecoverabilityStatus status =
TrustedVaultRecoverabilityStatus::kNotDegraded;
if (security_domain.security_domain_details()
.sync_details()
.degraded_recoverability()) {
status = TrustedVaultRecoverabilityStatus::kDegraded;
}
std::move(callback).Run(status);
}
class DownloadAuthenticationFactorsRegistrationStateRequest
: public TrustedVaultConnection::Request {
public:
DownloadAuthenticationFactorsRegistrationStateRequest(
SecurityDomainId security_domain,
const GURL& request_url,
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<TrustedVaultAccessTokenFetcher> access_token_fetcher,
TrustedVaultConnection::
DownloadAuthenticationFactorsRegistrationStateCallback callback,
base::RepeatingClosure keep_alive_callback)
: security_domain_(security_domain),
base_url_(request_url),
account_id_(account_id),
url_loader_factory_(std::move(url_loader_factory)),
access_token_fetcher_(std::move(access_token_fetcher)),
callback_(std::move(callback)),
keep_alive_callback_(std::move(keep_alive_callback)) {
result_.state =
DownloadAuthenticationFactorsRegistrationStateResult::State::kEmpty;
StartOrContinueRequest();
}
private:
void StartOrContinueRequest(const std::string* next_page_token = nullptr) {
request_ = std::make_unique<TrustedVaultRequest>(
security_domain_, account_id_, TrustedVaultRequest::HttpMethod::kGet,
next_page_token ? net::AppendQueryParameter(base_url_, "page_token",
*next_page_token)
: base_url_,
/*serialized_request_proto=*/std::nullopt,
/*max_retry_duration=*/base::Seconds(0), url_loader_factory_,
access_token_fetcher_->Clone(),
MakeFetchStatusCallback(
security_domain_,
TrustedVaultURLFetchReasonForUMA::
kDownloadAuthenticationFactorsRegistrationState));
// Unretained: this object owns `request_`. When `request_` is deleted, so
// is the `SimpleURLLoader` and thus any callback is canceled.
request_->FetchAccessTokenAndSendRequest(base::BindOnce(
&DownloadAuthenticationFactorsRegistrationStateRequest::ProcessResponse,
base::Unretained(this)));
}
void ProcessResponse(TrustedVaultRequest::HttpStatus http_status,
const std::string& response_body) {
if (http_status != TrustedVaultRequest::HttpStatus::kSuccess) {
result_.state =
DownloadAuthenticationFactorsRegistrationStateResult::State::kError;
FinishWithResultAndMaybeDestroySelf();
return;
}
trusted_vault_pb::ListSecurityDomainMembersResponse response;
if (!response.ParseFromString(response_body)) {
result_.state =
DownloadAuthenticationFactorsRegistrationStateResult::State::kError;
FinishWithResultAndMaybeDestroySelf();
return;
}
const std::string security_domain_name =
GetSecurityDomainPath(security_domain_);
for (const auto& member : response.security_domain_members()) {
bool is_member_of_domain = false;
for (const auto& membership : member.memberships()) {
if (membership.security_domain() == security_domain_name) {
is_member_of_domain = true;
for (const auto& key : membership.keys()) {
const int key_version = key.epoch();
if (key_version != 0 &&
(!result_.key_version.has_value() ||
result_.key_version.value() < key_version)) {
result_.key_version = key_version;
}
}
break;
}
}
if (!is_member_of_domain) {
continue;
}
if (member.has_member_metadata() &&
member.member_metadata().usable_for_retrieval()) {
result_.state = DownloadAuthenticationFactorsRegistrationStateResult::
State::kRecoverable;
} else if (result_.state ==
DownloadAuthenticationFactorsRegistrationStateResult::State::
kEmpty) {
result_.state = DownloadAuthenticationFactorsRegistrationStateResult::
State::kIrrecoverable;
}
if (member.member_type() == trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_GOOGLE_PASSWORD_MANAGER_PIN) {
if (member.member_metadata()
.has_google_password_manager_pin_metadata()) {
pin_status_ = TrustedVaultListSecurityDomainMembersPinStatus::
kPinPresentAndUsableForRecovery;
const auto& pin_metadata =
member.member_metadata().google_password_manager_pin_metadata();
result_.gpm_pin_metadata = GpmPinMetadata(
member.public_key(), UsableRecoveryPinMetadata(
pin_metadata.encrypted_pin_hash(),
ToTime(pin_metadata.expiration_time())));
} else {
result_.gpm_pin_metadata = GpmPinMetadata(
member.public_key(), /*pin_metadata=*/std::nullopt);
pin_status_ = TrustedVaultListSecurityDomainMembersPinStatus::
kPinPresentButUnusableForRecovery;
}
} else if (member.member_type() ==
trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_ICLOUD_KEYCHAIN) {
std::unique_ptr<SecureBoxPublicKey> public_key =
SecureBoxPublicKey::CreateByImport(
ProtoStringToBytes(member.public_key()));
if (!public_key) {
continue;
}
const auto& membership = std::ranges::find_if(
member.memberships(),
[&security_domain_name](const auto& membership) {
return membership.security_domain() == security_domain_name;
});
CHECK(membership != member.memberships().end())
<< "iCloud member should have been tested for membership above";
std::vector<MemberKeys> member_keys;
std::ranges::transform(
membership->keys(), std::back_inserter(member_keys),
[](const auto& key) {
return MemberKeys(key.epoch(),
std::vector<uint8_t>(key.wrapped_key().begin(),
key.wrapped_key().end()),
std::vector<uint8_t>(key.member_proof().begin(),
key.member_proof().end()));
});
result_.icloud_keys.emplace_back(std::move(public_key),
std::move(member_keys));
} else if (member.member_type() ==
trusted_vault_pb::SecurityDomainMember::
MEMBER_TYPE_LOCKSCREEN_KNOWLEDGE_FACTOR &&
member.member_metadata().has_lskf_metadata()) {
const auto& metadata = member.member_metadata().lskf_metadata();
result_.lskf_expiries.push_back(ToTime(metadata.expiration_time()));
}
}
if (!response.next_page_token().empty()) {
StartOrContinueRequest(&response.next_page_token());
if (keep_alive_callback_) {
keep_alive_callback_.Run();
}
return;
}
FinishWithResultAndMaybeDestroySelf();
}
void FinishWithResultAndMaybeDestroySelf() {
base::UmaHistogramEnumeration(
"TrustedVault.DownloadAuthenticationFactorsRegistrationState." +
GetSecurityDomainNameForUma(security_domain_),
result_.state);
RecordTrustedVaultListSecurityDomainMembersPinStatus(security_domain_,
pin_status_);
std::move(callback_).Run(std::move(result_));
}
const SecurityDomainId security_domain_;
const GURL base_url_;
const CoreAccountId account_id_;
const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
const std::unique_ptr<TrustedVaultAccessTokenFetcher> access_token_fetcher_;
TrustedVaultConnection::DownloadAuthenticationFactorsRegistrationStateCallback
callback_;
base::RepeatingClosure keep_alive_callback_;
std::unique_ptr<TrustedVaultRequest> request_;
DownloadAuthenticationFactorsRegistrationStateResult result_;
TrustedVaultListSecurityDomainMembersPinStatus pin_status_ =
TrustedVaultListSecurityDomainMembersPinStatus::kNoPinPresent;
};
TrustedVaultURLFetchReasonForUMA
GetURLFetchReasonForUMAForJoinSecurityDomainsRequest(
AuthenticationFactorTypeAndRegistrationParams
authentication_factor_type_and_registration_params) {
return std::visit(
absl::Overload{
[](const LocalPhysicalDevice&) {
return TrustedVaultURLFetchReasonForUMA::kRegisterDevice;
},
[](const LockScreenKnowledgeFactor&) {
return TrustedVaultURLFetchReasonForUMA::
kRegisterLockScreenKnowledgeFactor;
},
[](const UnspecifiedAuthenticationFactorType&) {
return TrustedVaultURLFetchReasonForUMA::
kRegisterUnspecifiedAuthenticationFactor;
},
[](const GpmPinMetadata&) {
return TrustedVaultURLFetchReasonForUMA::kRegisterGpmPin;
},
[](const ICloudKeychain&) {
return TrustedVaultURLFetchReasonForUMA::kRegisterICloudKeychain;
}},
authentication_factor_type_and_registration_params);
}
std::vector<TrustedVaultKeyAndVersion> ConstantKeySource() {
return {{GetConstantTrustedVaultKey(),
/*version=*/kUnknownConstantKeyVersion}};
}
} // namespace
std::vector<TrustedVaultKeyAndVersion> GetTrustedVaultKeysWithVersions(
const std::vector<std::vector<uint8_t>>& trusted_vault_keys,
int last_key_version) {
const int first_key_version =
last_key_version - static_cast<int>(trusted_vault_keys.size()) + 1;
std::vector<TrustedVaultKeyAndVersion> result;
for (size_t i = 0; i < trusted_vault_keys.size(); ++i) {
result.emplace_back(trusted_vault_keys[i], first_key_version + i);
}
return result;
}
TrustedVaultConnectionImpl::TrustedVaultConnectionImpl(
SecurityDomainId security_domain,
const GURL& trusted_vault_service_url,
std::unique_ptr<network::PendingSharedURLLoaderFactory>
pending_url_loader_factory,
std::unique_ptr<TrustedVaultAccessTokenFetcher> access_token_fetcher)
: security_domain_(security_domain),
pending_url_loader_factory_(std::move(pending_url_loader_factory)),
access_token_fetcher_(std::move(access_token_fetcher)),
trusted_vault_service_url_(trusted_vault_service_url) {
DCHECK(trusted_vault_service_url_.is_valid());
}
TrustedVaultConnectionImpl::~TrustedVaultConnectionImpl() = default;
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::RegisterAuthenticationFactor(
const CoreAccountInfo& account_info,
const MemberKeysSource& member_keys_source,
const SecureBoxPublicKey& authentication_factor_public_key,
AuthenticationFactorTypeAndRegistrationParams
authentication_factor_type_and_registration_params,
RegisterAuthenticationFactorCallback callback) {
return SendJoinSecurityDomainsRequest(
account_info, member_keys_source, authentication_factor_public_key,
authentication_factor_type_and_registration_params,
base::BindOnce(&RunRegisterAuthenticationFactorCallback,
std::move(callback)));
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::RegisterLocalDeviceWithoutKeys(
const CoreAccountInfo& account_info,
const SecureBoxPublicKey& device_public_key,
RegisterAuthenticationFactorCallback callback) {
return SendJoinSecurityDomainsRequest(
account_info, ConstantKeySource(), device_public_key,
LocalPhysicalDevice(),
base::BindOnce(&RunRegisterAuthenticationFactorCallback,
std::move(callback)));
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::DownloadNewKeys(
const CoreAccountInfo& account_info,
const TrustedVaultKeyAndVersion& last_trusted_vault_key_and_version,
std::unique_ptr<SecureBoxKeyPair> device_key_pair,
DownloadNewKeysCallback callback) {
// TODO(crbug.com/40255601): consider retries for keys downloading after
// initial failure returned to the upper layers.
auto request = std::make_unique<TrustedVaultRequest>(
security_domain_, account_info.account_id,
TrustedVaultRequest::HttpMethod::kGet,
GetGetSecurityDomainMemberURL(
trusted_vault_service_url_,
device_key_pair->public_key().ExportToBytes()),
/*serialized_request_proto=*/std::nullopt,
/*max_retry_duration=*/base::Seconds(0), GetOrCreateURLLoaderFactory(),
access_token_fetcher_->Clone(),
MakeFetchStatusCallback(security_domain_,
TrustedVaultURLFetchReasonForUMA::kDownloadKeys));
request->FetchAccessTokenAndSendRequest(
base::BindOnce(&ProcessDownloadKeysResponse,
/*response_processor=*/
std::make_unique<DownloadKeysResponseHandler>(
security_domain_, last_trusted_vault_key_and_version,
std::move(device_key_pair)),
std::move(callback)));
return request;
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::DownloadIsRecoverabilityDegraded(
const CoreAccountInfo& account_info,
IsRecoverabilityDegradedCallback callback) {
auto request = std::make_unique<TrustedVaultRequest>(
security_domain_, account_info.account_id,
TrustedVaultRequest::HttpMethod::kGet,
GetGetSecurityDomainURL(trusted_vault_service_url_, security_domain_),
/*serialized_request_proto=*/std::nullopt,
/*max_retry_duration=*/base::Seconds(0), GetOrCreateURLLoaderFactory(),
access_token_fetcher_->Clone(),
MakeFetchStatusCallback(
security_domain_,
TrustedVaultURLFetchReasonForUMA::kDownloadIsRecoverabilityDegraded));
request->FetchAccessTokenAndSendRequest(base::BindOnce(
&ProcessDownloadIsRecoverabilityDegradedResponse, std::move(callback)));
return request;
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::DownloadAuthenticationFactorsRegistrationState(
const CoreAccountInfo& account_info,
DownloadAuthenticationFactorsRegistrationStateCallback callback,
base::RepeatingClosure keep_alive_callback) {
return DownloadAuthenticationFactorsRegistrationState(
account_info, {}, std::move(callback), std::move(keep_alive_callback));
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::DownloadAuthenticationFactorsRegistrationState(
const CoreAccountInfo& account_info,
std::set<trusted_vault_pb::SecurityDomainMember_MemberType>
recovery_factor_filter,
DownloadAuthenticationFactorsRegistrationStateCallback callback,
base::RepeatingClosure keep_alive_callback) {
GURL request_url = GetGetSecurityDomainMembersURL(
trusted_vault_service_url_, {security_domain_}, recovery_factor_filter);
return std::make_unique<
DownloadAuthenticationFactorsRegistrationStateRequest>(
security_domain_, request_url, account_info.account_id,
GetOrCreateURLLoaderFactory(), access_token_fetcher_->Clone(),
std::move(callback), std::move(keep_alive_callback));
}
std::unique_ptr<TrustedVaultConnection::Request>
TrustedVaultConnectionImpl::SendJoinSecurityDomainsRequest(
const CoreAccountInfo& account_info,
const MemberKeysSource& member_keys_source,
const SecureBoxPublicKey& authentication_factor_public_key,
AuthenticationFactorTypeAndRegistrationParams
authentication_factor_type_and_registration_params,
JoinSecurityDomainsCallback callback) {
auto request = std::make_unique<TrustedVaultRequest>(
security_domain_, account_info.account_id,
TrustedVaultRequest::HttpMethod::kPost,
GetJoinSecurityDomainURL(trusted_vault_service_url_, security_domain_),
/*serialized_request_proto=*/
CreateJoinSecurityDomainsRequest(
security_domain_, member_keys_source,
authentication_factor_public_key,
authentication_factor_type_and_registration_params)
.SerializeAsString(),
kMaxJoinSecurityDomainRetryDuration, GetOrCreateURLLoaderFactory(),
access_token_fetcher_->Clone(),
MakeFetchStatusCallback(
security_domain_,
GetURLFetchReasonForUMAForJoinSecurityDomainsRequest(
authentication_factor_type_and_registration_params)));
request->FetchAccessTokenAndSendRequest(
base::BindOnce(&ProcessJoinSecurityDomainsResponse, std::move(callback)));
return request;
}
scoped_refptr<network::SharedURLLoaderFactory>
TrustedVaultConnectionImpl::GetOrCreateURLLoaderFactory() {
if (!url_loader_factory_) {
url_loader_factory_ = network::SharedURLLoaderFactory::Create(
std::move(pending_url_loader_factory_));
}
return url_loader_factory_;
}
} // namespace trusted_vault