blob: 9faaed816806b637201ed914de939a34130d8885 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/password_manager/core/browser/sync/password_sync_bridge.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_store_sync.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model_impl/sync_metadata_store_change_list.h"
#include "net/base/escape.h"
#include "url/gurl.h"
namespace password_manager {
namespace {
sync_pb::PasswordSpecifics SpecificsFromPassword(
const autofill::PasswordForm& password_form) {
sync_pb::PasswordSpecifics specifics;
sync_pb::PasswordSpecificsData* password_data =
specifics.mutable_client_only_encrypted_data();
password_data->set_scheme(password_form.scheme);
password_data->set_signon_realm(password_form.signon_realm);
password_data->set_origin(password_form.origin.spec());
password_data->set_action(password_form.action.spec());
password_data->set_username_element(
base::UTF16ToUTF8(password_form.username_element));
password_data->set_password_element(
base::UTF16ToUTF8(password_form.password_element));
password_data->set_username_value(
base::UTF16ToUTF8(password_form.username_value));
password_data->set_password_value(
base::UTF16ToUTF8(password_form.password_value));
password_data->set_preferred(password_form.preferred);
password_data->set_date_created(
password_form.date_created.ToDeltaSinceWindowsEpoch().InMicroseconds());
password_data->set_blacklisted(password_form.blacklisted_by_user);
password_data->set_type(password_form.type);
password_data->set_times_used(password_form.times_used);
password_data->set_display_name(
base::UTF16ToUTF8(password_form.display_name));
password_data->set_avatar_url(password_form.icon_url.spec());
password_data->set_federation_url(
password_form.federation_origin.opaque()
? std::string()
: password_form.federation_origin.Serialize());
return specifics;
}
std::unique_ptr<syncer::EntityData> CreateEntityData(
const autofill::PasswordForm& form) {
auto entity_data = std::make_unique<syncer::EntityData>();
*entity_data->specifics.mutable_password() = SpecificsFromPassword(form);
entity_data->non_unique_name = form.signon_realm;
return entity_data;
}
} // namespace
PasswordSyncBridge::PasswordSyncBridge(
std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor,
PasswordStoreSync* password_store_sync)
: ModelTypeSyncBridge(std::move(change_processor)),
password_store_sync_(password_store_sync) {
DCHECK(password_store_sync_);
}
PasswordSyncBridge::~PasswordSyncBridge() = default;
void PasswordSyncBridge::ActOnPasswordStoreChanges(
const PasswordStoreChangeList& local_changes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// It's the responsibility of the callers to call this method within the same
// transaction as the data changes to fulfill atomic writes of data and
// metadata constraint.
// TODO(mamir):ActOnPasswordStoreChanges() DCHECK we are inside a
// transaction!;
if (!change_processor()->IsTrackingMetadata()) {
return; // Sync processor not yet ready, don't sync.
}
// TODO(mamir):ActOnPasswordStoreChanges() can be called from
// ApplySyncChanges(). Do nothing in this case.
syncer::SyncMetadataStoreChangeList metadata_change_list(
password_store_sync_->GetMetadataStore(), syncer::PASSWORDS);
for (const PasswordStoreChange& change : local_changes) {
const std::string storage_key = base::NumberToString(change.primary_key());
switch (change.type()) {
case PasswordStoreChange::ADD:
case PasswordStoreChange::UPDATE: {
change_processor()->Put(storage_key, CreateEntityData(change.form()),
&metadata_change_list);
break;
}
case PasswordStoreChange::REMOVE: {
change_processor()->Delete(storage_key, &metadata_change_list);
break;
}
}
}
}
void PasswordSyncBridge::OnSyncStarting(
const syncer::DataTypeActivationRequest& request) {
NOTIMPLEMENTED();
}
std::unique_ptr<syncer::MetadataChangeList>
PasswordSyncBridge::CreateMetadataChangeList() {
NOTIMPLEMENTED();
return nullptr;
}
base::Optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_data) {
NOTIMPLEMENTED();
return base::nullopt;
}
base::Optional<syncer::ModelError> PasswordSyncBridge::ApplySyncChanges(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList entity_changes) {
NOTIMPLEMENTED();
return base::nullopt;
}
void PasswordSyncBridge::GetData(StorageKeyList storage_keys,
DataCallback callback) {
NOTIMPLEMENTED();
}
void PasswordSyncBridge::GetAllDataForDebugging(DataCallback callback) {
NOTIMPLEMENTED();
}
std::string PasswordSyncBridge::GetClientTag(
const syncer::EntityData& entity_data) {
DCHECK(entity_data.specifics.has_password())
<< "EntityData does not have password specifics.";
const sync_pb::PasswordSpecificsData& password_data =
entity_data.specifics.password().client_only_encrypted_data();
return (net::EscapePath(GURL(password_data.origin()).spec()) + "|" +
net::EscapePath(password_data.username_element()) + "|" +
net::EscapePath(password_data.username_value()) + "|" +
net::EscapePath(password_data.password_element()) + "|" +
net::EscapePath(password_data.signon_realm()));
}
std::string PasswordSyncBridge::GetStorageKey(
const syncer::EntityData& entity_data) {
NOTREACHED() << "PasswordSyncBridge does not support GetStorageKey.";
return std::string();
}
bool PasswordSyncBridge::SupportsGetStorageKey() const {
return false;
}
syncer::ModelTypeSyncBridge::StopSyncResponse
PasswordSyncBridge::ApplyStopSyncChanges(
std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) {
NOTIMPLEMENTED();
return ModelTypeSyncBridge::StopSyncResponse::kModelNoLongerReadyToSync;
}
} // namespace password_manager