blob: 6a08e54aa5fec20559090ecce9785affc0d7e2c8 [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/sync/sync_encryption_keys_tab_helper.h"
#include <string>
#include <utility>
#include <vector>
#include "base/no_destructor.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/common/sync_encryption_keys_extension.mojom.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_binding_set.h"
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/gaia_urls.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "url/origin.h"
namespace {
const url::Origin& GetAllowedOrigin() {
static const base::NoDestructor<url::Origin> origin(
url::Origin::Create(GaiaUrls::GetInstance()->gaia_url()));
CHECK(!origin->opaque());
return *origin;
}
bool ShouldExposeMojoApi(content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage()) {
return false;
}
// Restrict to allowed origin only.
return url::Origin::Create(navigation_handle->GetURL()) == GetAllowedOrigin();
}
} // namespace
class SyncEncryptionKeysTabHelper::EncryptionKeyApi
: public chrome::mojom::SyncEncryptionKeysExtension {
public:
EncryptionKeyApi(content::WebContents* web_contents,
syncer::SyncService* sync_service)
: sync_service_(sync_service), bindings_(web_contents, this) {
DCHECK(web_contents);
DCHECK(sync_service);
}
// chrome::mojom::SyncEncryptionKeysExtension:
void SetEncryptionKeys(const std::vector<std::string>& encryption_keys,
const std::string& gaia_id,
SetEncryptionKeysCallback callback) override {
CHECK_EQ(bindings_.GetCurrentTargetFrame()->GetLastCommittedOrigin(),
GetAllowedOrigin());
sync_service_->GetUserSettings()->AddTrustedVaultDecryptionKeys(
gaia_id, encryption_keys);
std::move(callback).Run();
}
private:
syncer::SyncService* const sync_service_;
content::WebContentsFrameBindingSet<
chrome::mojom::SyncEncryptionKeysExtension>
bindings_;
DISALLOW_COPY_AND_ASSIGN(EncryptionKeyApi);
};
// static
void SyncEncryptionKeysTabHelper::CreateForWebContents(
content::WebContents* web_contents) {
DCHECK(web_contents);
if (FromWebContents(web_contents)) {
return;
}
if (web_contents->GetBrowserContext()->IsOffTheRecord()) {
return;
}
syncer::SyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
if (!sync_service) {
return;
}
web_contents->SetUserData(UserDataKey(),
base::WrapUnique(new SyncEncryptionKeysTabHelper(
web_contents, sync_service)));
}
SyncEncryptionKeysTabHelper::SyncEncryptionKeysTabHelper(
content::WebContents* web_contents,
syncer::SyncService* sync_service)
: content::WebContentsObserver(web_contents), sync_service_(sync_service) {
DCHECK(web_contents);
DCHECK(sync_service);
}
SyncEncryptionKeysTabHelper::~SyncEncryptionKeysTabHelper() = default;
void SyncEncryptionKeysTabHelper::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsSameDocument()) {
return;
}
if (!ShouldExposeMojoApi(navigation_handle)) {
encryption_key_api_.reset();
} else if (!encryption_key_api_) {
encryption_key_api_ =
std::make_unique<EncryptionKeyApi>(web_contents(), sync_service_);
}
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(SyncEncryptionKeysTabHelper)