summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-31 19:44:25 +0000
committerzea@chromium.org <zea@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-31 19:44:25 +0000
commit310512cc361ab20d11a236095664fafae2250fac (patch)
treece779afc56fb845f043ea7f54e905c7ff4d8d697
parent126f1d652abfd11204fb7b4aed48dcb9999903d9 (diff)
downloadchromium_src-310512cc361ab20d11a236095664fafae2250fac.zip
chromium_src-310512cc361ab20d11a236095664fafae2250fac.tar.gz
chromium_src-310512cc361ab20d11a236095664fafae2250fac.tar.bz2
[Sync] Add support for performing a GetKey on startup.
The functionality is behind the --sync-keystore-encryption flag, and the key is not currently consumed by anything, but this lays the groundwork for testing the server and client interaction. We request a key anytime we perform a GetUpdates while the cryptographer does not have a keystore key. But, it is considered an error to request a key and not receive one, putting us into a state of backoff. BUG=129665 TEST=sync_unit_tests, running against python server Review URL: https://chromiumcodereview.appspot.com/10455012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149248 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync/about_sync_util.cc4
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc2
-rw-r--r--chrome/browser/sync/test/integration/sync_test.cc4
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--net/tools/testserver/chromiumsync.py21
-rwxr-xr-xnet/tools/testserver/chromiumsync_test.py6
-rw-r--r--sync/engine/download_updates_command.cc42
-rw-r--r--sync/engine/sync_scheduler.h7
-rw-r--r--sync/engine/sync_scheduler_impl.cc11
-rw-r--r--sync/engine/sync_scheduler_unittest.cc21
-rw-r--r--sync/engine/sync_scheduler_whitebox_unittest.cc3
-rw-r--r--sync/engine/syncer_unittest.cc37
-rw-r--r--sync/internal_api/internal_components_factory_impl.cc6
-rw-r--r--sync/internal_api/public/internal_components_factory.h3
-rw-r--r--sync/internal_api/public/internal_components_factory_impl.h3
-rw-r--r--sync/internal_api/public/sessions/model_neutral_state.cc1
-rw-r--r--sync/internal_api/public/sessions/model_neutral_state.h4
-rw-r--r--sync/internal_api/public/sync_manager.h5
-rw-r--r--sync/internal_api/public/test/fake_sync_manager.h1
-rw-r--r--sync/internal_api/public/test/test_internal_components_factory.h3
-rw-r--r--sync/internal_api/sync_manager_impl.cc10
-rw-r--r--sync/internal_api/sync_manager_impl.h1
-rw-r--r--sync/internal_api/syncapi_unittest.cc1
-rw-r--r--sync/internal_api/test/fake_sync_manager.cc1
-rw-r--r--sync/internal_api/test/test_internal_components_factory.cc7
-rw-r--r--sync/protocol/sync.proto49
-rw-r--r--sync/sessions/status_controller.cc8
-rw-r--r--sync/sessions/status_controller.h3
-rw-r--r--sync/sessions/sync_session.cc7
-rw-r--r--sync/sessions/sync_session_context.cc6
-rw-r--r--sync/sessions/sync_session_context.h13
-rw-r--r--sync/sessions/sync_session_unittest.cc3
-rw-r--r--sync/sessions/test_util.cc10
-rw-r--r--sync/sessions/test_util.h2
-rw-r--r--sync/test/engine/mock_connection_manager.cc13
-rw-r--r--sync/test/engine/mock_connection_manager.h6
-rw-r--r--sync/test/engine/syncer_command_test.h3
-rw-r--r--sync/tools/sync_client.cc1
-rw-r--r--sync/util/cryptographer.cc21
-rw-r--r--sync/util/cryptographer.h10
-rw-r--r--sync/util/get_session_name.cc2
42 files changed, 288 insertions, 77 deletions
diff --git a/chrome/browser/sync/about_sync_util.cc b/chrome/browser/sync/about_sync_util.cc
index b0a56dcd..c0487ad 100644
--- a/chrome/browser/sync/about_sync_util.cc
+++ b/chrome/browser/sync/about_sync_util.cc
@@ -197,6 +197,7 @@ scoped_ptr<DictionaryValue> ConstructAboutInformation(
ListValue* section_last_session = AddSection(
stats_list, "Status from Last Completed Session");
StringSyncStat session_source(section_last_session, "Sync Source");
+ StringSyncStat get_key_result(section_last_session, "GetKey Step Result");
StringSyncStat download_result(section_last_session, "Download Step Result");
StringSyncStat commit_result(section_last_session, "Commit Step Result");
@@ -297,6 +298,9 @@ scoped_ptr<DictionaryValue> ConstructAboutInformation(
if (snapshot.is_initialized()) {
session_source.SetValue(
syncer::GetUpdatesSourceString(snapshot.source().updates_source));
+ get_key_result.SetValue(
+ GetSyncerErrorString(
+ snapshot.model_neutral_state().last_get_key_result));
download_result.SetValue(
GetSyncerErrorString(
snapshot.model_neutral_state().last_download_updates_result));
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 295bb8c..8c0d8c7 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -992,6 +992,8 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
options.chrome_sync_notification_bridge,
options.sync_notifier_factory->CreateSyncNotifier())),
options.restored_key_for_bootstrapping,
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSyncKeystoreEncryption),
scoped_ptr<InternalComponentsFactory>(
options.internal_components_factory),
&encryptor_,
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 7bc6ab8..e9ab9c9 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -197,6 +197,10 @@ void SyncTest::AddTestSwitches(CommandLine* cl) {
// Disable non-essential access of external network resources.
if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
cl->AppendSwitch(switches::kDisableBackgroundNetworking);
+
+ // TODO(sync): remove this once keystore encryption is enabled by default.
+ if (!cl->HasSwitch(switches::kSyncKeystoreEncryption))
+ cl->AppendSwitch(switches::kSyncKeystoreEncryption);
}
void SyncTest::AddOptionalTypesToCommandLine(CommandLine* cl) {}
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 77dfee8..3204947 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1240,6 +1240,9 @@ const char kSyncAllowInsecureXmppConnection[] =
// Invalidates any login info passed into sync's XMPP connection.
const char kSyncInvalidateXmppLogin[] = "sync-invalidate-xmpp-login";
+// Enable support for keystore key based encryption.
+const char kSyncKeystoreEncryption[] = "sync-keystore-encryption";
+
// Overrides the default notification method for sync.
const char kSyncNotificationMethod[] = "sync-notification-method";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 192f0d2..6fad18d 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -328,6 +328,7 @@ extern const char kSuggestionNtpGaussianFilter[];
extern const char kSuggestionNtpLinearFilter[];
extern const char kSyncAllowInsecureXmppConnection[];
extern const char kSyncInvalidateXmppLogin[];
+extern const char kSyncKeystoreEncryption[];
extern const char kSyncNotificationMethod[];
extern const char kSyncNotificationHostPort[];
extern const char kSyncServiceURL[];
diff --git a/net/tools/testserver/chromiumsync.py b/net/tools/testserver/chromiumsync.py
index d789bcb..24325f5 100644
--- a/net/tools/testserver/chromiumsync.py
+++ b/net/tools/testserver/chromiumsync.py
@@ -13,6 +13,7 @@ import copy
import operator
import pickle
import random
+import string
import sys
import threading
import time
@@ -97,6 +98,9 @@ ROOT_ID = '0'
# Jan 1 1970, 00:00:00, non-dst.
UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0)
+# The number of characters in the server-generated encryption key.
+KEYSTORE_KEY_LENGTH = 16
+
class Error(Exception):
"""Error class for this module."""
@@ -468,6 +472,9 @@ class SyncDataModel(object):
self.induced_error_frequency = 0
self.sync_count_before_errors = 0
+ self._key = ''.join(random.choice(string.ascii_uppercase + string.digits)
+ for x in xrange(KEYSTORE_KEY_LENGTH))
+
def _SaveEntry(self, entry):
"""Insert or update an entry in the change log, and give it a new version.
@@ -664,6 +671,11 @@ class SyncDataModel(object):
# batch, even if that item was filtered out.
return (batch[-1].version, filtered, len(new_changes) - len(batch))
+ def GetKey(self):
+ """Returns the encryption key for this account."""
+ print "Returning encryption key: %s" % self._key
+ return self._key
+
def _CopyOverImmutableFields(self, entry):
"""Preserve immutable fields by copying pre-commit state.
@@ -1043,7 +1055,7 @@ class TestServer(object):
def HandleSetInducedError(self, path):
query = urlparse.urlparse(path)[4]
self.account_lock.acquire()
- code = 200;
+ code = 200
response = 'Success'
error = sync_pb2.ClientToServerResponse.Error()
try:
@@ -1132,8 +1144,8 @@ class TestServer(object):
response.error_code = sync_enums_pb2.SyncEnums.SUCCESS
self.CheckStoreBirthday(request)
response.store_birthday = self.account.store_birthday
- self.CheckTransientError();
- self.CheckSendError();
+ self.CheckTransientError()
+ self.CheckSendError()
print_context('->')
@@ -1262,3 +1274,6 @@ class TestServer(object):
reply = update_response.entries.add()
reply.CopyFrom(entry)
update_sieve.SaveProgress(new_timestamp, update_response)
+
+ if update_request.need_encryption_key:
+ update_response.encryption_key = self.account.GetKey()
diff --git a/net/tools/testserver/chromiumsync_test.py b/net/tools/testserver/chromiumsync_test.py
index 2485b0f..e680d41 100755
--- a/net/tools/testserver/chromiumsync_test.py
+++ b/net/tools/testserver/chromiumsync_test.py
@@ -600,6 +600,12 @@ class SyncDataModelTest(unittest.TestCase):
len(changes))
self.assertEqual(version2, version)
+ def testGetKey(self):
+ key1 = self.model.GetKey()
+ key2 = self.model.GetKey()
+ self.assertTrue(len(key1) > 0)
+ self.assertEqual(key1, key2)
+
if __name__ == '__main__':
unittest.main()
diff --git a/sync/engine/download_updates_command.cc b/sync/engine/download_updates_command.cc
index e7e1b08..65677fb 100644
--- a/sync/engine/download_updates_command.cc
+++ b/sync/engine/download_updates_command.cc
@@ -11,6 +11,7 @@
#include "sync/engine/syncer_proto_util.h"
#include "sync/internal_api/public/base/model_type_payload_map.h"
#include "sync/syncable/directory.h"
+#include "sync/syncable/read_transaction.h"
using sync_pb::DebugInfo;
@@ -25,6 +26,30 @@ DownloadUpdatesCommand::DownloadUpdatesCommand(
DownloadUpdatesCommand::~DownloadUpdatesCommand() {}
+namespace {
+
+SyncerError HandleGetEncryptionKeyResponse(
+ const sync_pb::ClientToServerResponse& update_response,
+ syncable::Directory* dir) {
+ bool success = false;
+ if (!update_response.get_updates().has_encryption_key()) {
+ LOG(ERROR) << "Failed to receive encryption key from server.";
+ return SERVER_RESPONSE_VALIDATION_FAILED;
+ }
+ syncable::ReadTransaction trans(FROM_HERE, dir);
+ Cryptographer* cryptographer = dir->GetCryptographer(&trans);
+ success = cryptographer->SetKeystoreKey(
+ update_response.get_updates().encryption_key());
+
+ DVLOG(1) << "GetUpdates returned encryption key of length "
+ << update_response.get_updates().encryption_key().length()
+ << ". Cryptographer keystore key "
+ << (success ? "" : "not ") << "updated.";
+ return (success ? SYNCER_OK : SERVER_RESPONSE_VALIDATION_FAILED);
+}
+
+} // namespace
+
SyncerError DownloadUpdatesCommand::ExecuteImpl(SyncSession* session) {
sync_pb::ClientToServerMessage client_to_server_message;
sync_pb::ClientToServerResponse update_response;
@@ -61,6 +86,17 @@ SyncerError DownloadUpdatesCommand::ExecuteImpl(SyncSession* session) {
}
}
+ bool need_encryption_key = false;
+ if (session->context()->keystore_encryption_enabled()) {
+ syncable::Directory* dir = session->context()->directory();
+ syncable::ReadTransaction trans(FROM_HERE, dir);
+ Cryptographer* cryptographer =
+ session->context()->directory()->GetCryptographer(&trans);
+ need_encryption_key = !cryptographer->HasKeystoreKey();
+ get_updates->set_need_encryption_key(need_encryption_key);
+
+ }
+
// We want folders for our associated types, always. If we were to set
// this to false, the server would send just the non-container items
// (e.g. Bookmark URLs but not their containing folders).
@@ -102,6 +138,12 @@ SyncerError DownloadUpdatesCommand::ExecuteImpl(SyncSession* session) {
<< " updates and indicated "
<< update_response.get_updates().changes_remaining()
<< " updates left on server.";
+
+ if (need_encryption_key) {
+ status->set_last_get_key_result(
+ HandleGetEncryptionKeyResponse(update_response, dir));
+ }
+
return result;
}
diff --git a/sync/engine/sync_scheduler.h b/sync/engine/sync_scheduler.h
index c8226f4..8967a83 100644
--- a/sync/engine/sync_scheduler.h
+++ b/sync/engine/sync_scheduler.h
@@ -26,16 +26,11 @@ namespace syncer {
struct ServerConnectionEvent;
struct ConfigurationParams {
- enum KeystoreKeyStatus {
- KEYSTORE_KEY_UNNECESSARY,
- KEYSTORE_KEY_NEEDED
- };
ConfigurationParams();
ConfigurationParams(
const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
const ModelTypeSet& types_to_download,
const ModelSafeRoutingInfo& routing_info,
- KeystoreKeyStatus keystore_key_status,
const base::Closure& ready_task);
~ConfigurationParams();
@@ -45,8 +40,6 @@ struct ConfigurationParams {
ModelTypeSet types_to_download;
// The new routing info (superset of types to be downloaded).
ModelSafeRoutingInfo routing_info;
- // Whether we need to perform a GetKey command.
- KeystoreKeyStatus keystore_key_status;
// Callback to invoke on configuration completion.
base::Closure ready_task;
};
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index 72f8243..ec7143d 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -65,18 +65,15 @@ bool IsActionableError(
} // namespace
ConfigurationParams::ConfigurationParams()
- : source(GetUpdatesCallerInfo::UNKNOWN),
- keystore_key_status(KEYSTORE_KEY_UNNECESSARY) {}
+ : source(GetUpdatesCallerInfo::UNKNOWN) {}
ConfigurationParams::ConfigurationParams(
const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
const ModelTypeSet& types_to_download,
const ModelSafeRoutingInfo& routing_info,
- KeystoreKeyStatus keystore_key_status,
const base::Closure& ready_task)
: source(source),
types_to_download(types_to_download),
routing_info(routing_info),
- keystore_key_status(keystore_key_status),
ready_task(ready_task) {
DCHECK(!ready_task.is_null());
}
@@ -353,12 +350,6 @@ bool SyncSchedulerImpl::ScheduleConfiguration(
&restricted_workers);
session_context_->set_routing_info(params.routing_info);
- if (params.keystore_key_status == ConfigurationParams::KEYSTORE_KEY_NEEDED) {
- // TODO(zea): implement in such a way that we can handle failures and the
- // subsequent retrys the scheduler might perform. See crbug.com/129665.
- NOTIMPLEMENTED();
- }
-
// Only reconfigure if we have types to download.
if (!params.types_to_download.Empty()) {
DCHECK(!restricted_routes.empty());
diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc
index 7581c4dc..2b9ea87 100644
--- a/sync/engine/sync_scheduler_unittest.cc
+++ b/sync/engine/sync_scheduler_unittest.cc
@@ -120,7 +120,8 @@ class SyncSchedulerTest : public testing::Test {
context_.reset(new SyncSessionContext(
connection_.get(), directory(), workers,
&extensions_activity_monitor_, throttled_data_type_tracker_.get(),
- std::vector<SyncEngineEventListener*>(), NULL, NULL));
+ std::vector<SyncEngineEventListener*>(), NULL, NULL,
+ true /* enable keystore encryption */));
context_->set_routing_info(routing_info);
context_->set_notifications_enabled(true);
context_->set_account_name("Test");
@@ -312,7 +313,6 @@ TEST_F(SyncSchedulerTest, Config) {
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_TRUE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(1, counter.times_called());
@@ -346,7 +346,6 @@ TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_FALSE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(0, counter.times_called());
@@ -389,7 +388,6 @@ TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_FALSE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(0, counter.times_called());
@@ -730,7 +728,6 @@ TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_FALSE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(0, counter.times_called());
@@ -784,7 +781,6 @@ TEST_F(SyncSchedulerTest, ConfigurationMode) {
GetUpdatesCallerInfo::RECONFIGURATION,
config_types,
TypesToRoutingInfo(config_types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_TRUE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(1, counter.times_called());
@@ -848,6 +844,17 @@ TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
EXPECT_TRUE(RunAndGetBackoff());
}
+// Have the syncer fail to get the encryption key yet succeed in downloading
+// updates. Expect this will leave the scheduler in backoff.
+TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) {
+ EXPECT_CALL(*syncer(), SyncShare(_,_,_))
+ .WillOnce(Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed))
+ .WillRepeatedly(DoAll(
+ Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
+ QuitLoopNowAction()));
+ EXPECT_TRUE(RunAndGetBackoff());
+}
+
// Test that no polls or extraneous nudges occur when in backoff.
TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
SyncShareRecords r;
@@ -899,7 +906,6 @@ TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_FALSE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(0, counter.times_called());
@@ -1074,7 +1080,6 @@ TEST_F(SyncSchedulerTest, SyncerSteps) {
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY,
base::Bind(&CallbackCounter::Callback, base::Unretained(&counter)));
ASSERT_TRUE(scheduler()->ScheduleConfiguration(params));
ASSERT_EQ(1, counter.times_called());
diff --git a/sync/engine/sync_scheduler_whitebox_unittest.cc b/sync/engine/sync_scheduler_whitebox_unittest.cc
index b035686..f6f88c2 100644
--- a/sync/engine/sync_scheduler_whitebox_unittest.cc
+++ b/sync/engine/sync_scheduler_whitebox_unittest.cc
@@ -50,7 +50,8 @@ class SyncSchedulerWhiteboxTest : public testing::Test {
connection_.get(), dir_maker_.directory(),
workers, &extensions_activity_monitor_,
throttled_data_type_tracker_.get(),
- std::vector<SyncEngineEventListener*>(), NULL, NULL));
+ std::vector<SyncEngineEventListener*>(), NULL, NULL,
+ true /* enable keystore encryption */));
context_->set_notifications_enabled(true);
context_->set_account_name("Test");
scheduler_.reset(
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index 053fc1d..7372f68 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -238,7 +238,8 @@ class SyncerTest : public testing::Test,
new SyncSessionContext(
mock_server_.get(), directory(), workers,
&extensions_activity_monitor_, throttled_data_type_tracker_.get(),
- listeners, NULL, &traffic_recorder_));
+ listeners, NULL, &traffic_recorder_,
+ true /* enable keystore encryption */));
context_->set_routing_info(routing_info);
ASSERT_FALSE(context_->resolver());
syncer_ = new Syncer();
@@ -252,6 +253,8 @@ class SyncerTest : public testing::Test,
root_id_ = TestIdFactory::root();
parent_id_ = ids_.MakeServer("parent id");
child_id_ = ids_.MakeServer("child id");
+ directory()->set_store_birthday(mock_server_->store_birthday());
+ mock_server_->SetKeystoreKey("encryption_key");
}
virtual void TearDown() {
@@ -2307,7 +2310,6 @@ class EntryCreatedInNewFolderTest : public SyncerTest {
};
TEST_F(EntryCreatedInNewFolderTest, EntryCreatedInNewFolderMidSync) {
- directory()->set_store_birthday(mock_server_->store_birthday());
{
WriteTransaction trans(FROM_HERE, UNITTEST, directory());
MutableEntry entry(&trans, syncable::CREATE, trans.root_id(),
@@ -4167,6 +4169,37 @@ TEST_F(SyncerTest, ConfigureFailsDontApplyUpdates) {
EXPECT_FALSE(initial_sync_ended_for_type(BOOKMARKS));
}
+TEST_F(SyncerTest, GetKeySuccess) {
+ {
+ syncable::ReadTransaction rtrans(FROM_HERE, directory());
+ EXPECT_FALSE(cryptographer(&rtrans)->HasKeystoreKey());
+ }
+
+ SyncShareConfigure();
+
+ EXPECT_EQ(session_->status_controller().last_get_key_result(), SYNCER_OK);
+ {
+ syncable::ReadTransaction rtrans(FROM_HERE, directory());
+ EXPECT_TRUE(cryptographer(&rtrans)->HasKeystoreKey());
+ }
+}
+
+TEST_F(SyncerTest, GetKeyEmpty) {
+ {
+ syncable::ReadTransaction rtrans(FROM_HERE, directory());
+ EXPECT_FALSE(cryptographer(&rtrans)->HasKeystoreKey());
+ }
+
+ mock_server_->SetKeystoreKey("");
+ SyncShareConfigure();
+
+ EXPECT_NE(session_->status_controller().last_get_key_result(), SYNCER_OK);
+ {
+ syncable::ReadTransaction rtrans(FROM_HERE, directory());
+ EXPECT_FALSE(cryptographer(&rtrans)->HasKeystoreKey());
+ }
+}
+
// Test what happens if a client deletes, then recreates, an object very
// quickly. It is possible that the deletion gets sent as a commit, and
// the undelete happens during the commit request. The principle here
diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc
index 062ee0b..3342d09 100644
--- a/sync/internal_api/internal_components_factory_impl.cc
+++ b/sync/internal_api/internal_components_factory_impl.cc
@@ -29,12 +29,14 @@ InternalComponentsFactoryImpl::BuildContext(
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
sessions::DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder) {
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled) {
return scoped_ptr<sessions::SyncSessionContext>(
new sessions::SyncSessionContext(
connection_manager, directory, workers, monitor,
throttled_data_type_tracker, listeners, debug_info_getter,
- traffic_recorder));
+ traffic_recorder,
+ keystore_encryption_enabled));
}
scoped_ptr<syncable::DirectoryBackingStore>
diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h
index 40c703e..145c225 100644
--- a/sync/internal_api/public/internal_components_factory.h
+++ b/sync/internal_api/public/internal_components_factory.h
@@ -51,7 +51,8 @@ class InternalComponentsFactory {
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
sessions::DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder) = 0;
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled) = 0;
virtual scoped_ptr<syncable::DirectoryBackingStore>
BuildDirectoryBackingStore(
diff --git a/sync/internal_api/public/internal_components_factory_impl.h b/sync/internal_api/public/internal_components_factory_impl.h
index d15287a..c8f76ed 100644
--- a/sync/internal_api/public/internal_components_factory_impl.h
+++ b/sync/internal_api/public/internal_components_factory_impl.h
@@ -29,7 +29,8 @@ class InternalComponentsFactoryImpl : public InternalComponentsFactory {
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
sessions::DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder) OVERRIDE;
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled) OVERRIDE;
virtual scoped_ptr<syncable::DirectoryBackingStore>
BuildDirectoryBackingStore(
diff --git a/sync/internal_api/public/sessions/model_neutral_state.cc b/sync/internal_api/public/sessions/model_neutral_state.cc
index b25d3c7..9ae8436 100644
--- a/sync/internal_api/public/sessions/model_neutral_state.cc
+++ b/sync/internal_api/public/sessions/model_neutral_state.cc
@@ -15,6 +15,7 @@ ModelNeutralState::ModelNeutralState()
num_reflected_updates_downloaded_total(0),
num_local_overwrites(0),
num_server_overwrites(0),
+ last_get_key_result(UNSET),
last_download_updates_result(UNSET),
commit_result(UNSET),
conflicts_resolved(false),
diff --git a/sync/internal_api/public/sessions/model_neutral_state.h b/sync/internal_api/public/sessions/model_neutral_state.h
index 6b0cec8..c1d8862 100644
--- a/sync/internal_api/public/sessions/model_neutral_state.h
+++ b/sync/internal_api/public/sessions/model_neutral_state.h
@@ -48,7 +48,9 @@ struct ModelNeutralState {
// Any protocol errors that we received during this sync session.
SyncProtocolError sync_protocol_error;
- // Records the most recent results of PostCommit and GetUpdates commands.
+ // Records the most recent results of GetKey, PostCommit and GetUpdates
+ // commands.
+ SyncerError last_get_key_result;
SyncerError last_download_updates_result;
SyncerError commit_result;
diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h
index 2cbbd5c..93c3787b 100644
--- a/sync/internal_api/public/sync_manager.h
+++ b/sync/internal_api/public/sync_manager.h
@@ -359,6 +359,10 @@ class SyncManager {
// |user_agent| is a 7-bit ASCII string suitable for use as the User-Agent
// HTTP header. Used internally when collecting stats to classify clients.
// |sync_notifier| is owned and used to listen for notifications.
+ // |restored_key_for_bootstrapping| is the key used to boostrap the
+ // cryptographer
+ // |keystore_encryption_enabled| determines whether we enable the keystore
+ // encryption functionality in the cryptographer/nigori.
// |report_unrecoverable_error_function| may be NULL.
//
// TODO(akalin): Replace the |post_factory| parameter with a
@@ -377,6 +381,7 @@ class SyncManager {
const SyncCredentials& credentials,
scoped_ptr<SyncNotifier> sync_notifier,
const std::string& restored_key_for_bootstrapping,
+ bool keystore_encryption_enabled,
scoped_ptr<InternalComponentsFactory> internal_components_factory,
Encryptor* encryptor,
UnrecoverableErrorHandler* unrecoverable_error_handler,
diff --git a/sync/internal_api/public/test/fake_sync_manager.h b/sync/internal_api/public/test/fake_sync_manager.h
index 015605f..b33b27d 100644
--- a/sync/internal_api/public/test/fake_sync_manager.h
+++ b/sync/internal_api/public/test/fake_sync_manager.h
@@ -67,6 +67,7 @@ class FakeSyncManager : public SyncManager {
const SyncCredentials& credentials,
scoped_ptr<SyncNotifier> sync_notifier,
const std::string& restored_key_for_bootstrapping,
+ bool keystore_encryption_enabled,
scoped_ptr<InternalComponentsFactory> internal_components_factory,
Encryptor* encryptor,
UnrecoverableErrorHandler* unrecoverable_error_handler,
diff --git a/sync/internal_api/public/test/test_internal_components_factory.h b/sync/internal_api/public/test/test_internal_components_factory.h
index 3755447..a97164d 100644
--- a/sync/internal_api/public/test/test_internal_components_factory.h
+++ b/sync/internal_api/public/test/test_internal_components_factory.h
@@ -34,7 +34,8 @@ class TestInternalComponentsFactory : public InternalComponentsFactory {
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
sessions::DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder) OVERRIDE;
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled) OVERRIDE;
virtual scoped_ptr<syncable::DirectoryBackingStore>
BuildDirectoryBackingStore(
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index 7e173d1..e069df4 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -351,15 +351,9 @@ void SyncManagerImpl::ConfigureSyncer(
return;
}
- // TODO(zea): set this based on whether cryptographer has keystore
- // encryption key or not (requires opening a transaction). crbug.com/129665.
- ConfigurationParams::KeystoreKeyStatus keystore_key_status =
- ConfigurationParams::KEYSTORE_KEY_UNNECESSARY;
-
ConfigurationParams params(GetSourceFromReason(reason),
types_to_config,
new_routing_info,
- keystore_key_status,
ready_task);
scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
@@ -382,6 +376,7 @@ bool SyncManagerImpl::Init(
const SyncCredentials& credentials,
scoped_ptr<SyncNotifier> sync_notifier,
const std::string& restored_key_for_bootstrapping,
+ bool keystore_encryption_enabled,
scoped_ptr<InternalComponentsFactory> internal_components_factory,
Encryptor* encryptor,
UnrecoverableErrorHandler* unrecoverable_error_handler,
@@ -469,7 +464,8 @@ bool SyncManagerImpl::Init(
&throttled_data_type_tracker_,
listeners,
&debug_info_event_listener_,
- &traffic_recorder_).Pass();
+ &traffic_recorder_,
+ keystore_encryption_enabled).Pass();
session_context_->set_account_name(credentials.email);
scheduler_ = internal_components_factory->BuildScheduler(
name_, session_context_.get()).Pass();
diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h
index 190f77d..3ce4679 100644
--- a/sync/internal_api/sync_manager_impl.h
+++ b/sync/internal_api/sync_manager_impl.h
@@ -71,6 +71,7 @@ class SyncManagerImpl : public SyncManager,
const SyncCredentials& credentials,
scoped_ptr<SyncNotifier> sync_notifier,
const std::string& restored_key_for_bootstrapping,
+ bool keystore_encryption_enabled,
scoped_ptr<InternalComponentsFactory> internal_components_factory,
Encryptor* encryptor,
UnrecoverableErrorHandler* unrecoverable_error_handler,
diff --git a/sync/internal_api/syncapi_unittest.cc b/sync/internal_api/syncapi_unittest.cc
index e43a2e2..d0ec527 100644
--- a/sync/internal_api/syncapi_unittest.cc
+++ b/sync/internal_api/syncapi_unittest.cc
@@ -764,6 +764,7 @@ class SyncManagerTest : public testing::Test,
credentials,
scoped_ptr<SyncNotifier>(sync_notifier_mock_),
"",
+ true, // enable keystore encryption
scoped_ptr<InternalComponentsFactory>(GetFactory()),
&encryptor_,
&handler_,
diff --git a/sync/internal_api/test/fake_sync_manager.cc b/sync/internal_api/test/fake_sync_manager.cc
index 1af7fac..a507239 100644
--- a/sync/internal_api/test/fake_sync_manager.cc
+++ b/sync/internal_api/test/fake_sync_manager.cc
@@ -62,6 +62,7 @@ bool FakeSyncManager::Init(
const SyncCredentials& credentials,
scoped_ptr<SyncNotifier> sync_notifier,
const std::string& restored_key_for_bootstrapping,
+ bool keystore_encryption_enabled,
scoped_ptr<InternalComponentsFactory> internal_components_factory,
Encryptor* encryptor,
UnrecoverableErrorHandler* unrecoverable_error_handler,
diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc
index ac3f8a8..cffaedb 100644
--- a/sync/internal_api/test/test_internal_components_factory.cc
+++ b/sync/internal_api/test/test_internal_components_factory.cc
@@ -32,7 +32,8 @@ TestInternalComponentsFactory::BuildContext(
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
sessions::DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder) {
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled) {
// Tests don't wire up listeners.
std::vector<SyncEngineEventListener*> empty_listeners;
@@ -40,7 +41,9 @@ TestInternalComponentsFactory::BuildContext(
new sessions::SyncSessionContext(
connection_manager, directory, workers, monitor,
throttled_data_type_tracker, empty_listeners, debug_info_getter,
- traffic_recorder));
+ traffic_recorder,
+ keystore_encryption_enabled));
+
}
scoped_ptr<syncable::DirectoryBackingStore>
diff --git a/sync/protocol/sync.proto b/sync/protocol/sync.proto
index ec9a1d2..8f44823 100644
--- a/sync/protocol/sync.proto
+++ b/sync/protocol/sync.proto
@@ -446,6 +446,14 @@ message GetUpdatesMessage {
// delimited by a length prefix, which is encoded as a varint.
optional bool streaming = 7 [default = false];
+ // Whether the client needs the server to provide an encryption key for this
+ // account.
+ // Note: this should typically only be set on the first GetUpdates a client
+ // requests. Clients are expected to persist the encryption key from then on.
+ // The allowed frequency for requesting encryption keys is much lower than
+ // other datatypes, so repeated usage will likely result in throttling.
+ optional bool need_encryption_key = 8 [default = false];
+
// Whether to create the mobile bookmarks folder if it's not
// already created. Should be set to true only by mobile clients.
optional bool create_mobile_bookmarks_folder = 1000 [default = false];
@@ -572,6 +580,10 @@ message GetUpdatesResponse {
// Progress markers in the context of a response will never have the
// |timestamp_token_for_migration| field set.
repeated DataTypeProgressMarker new_progress_marker = 5;
+
+ // The current encryption key associated with this account. Only set if the
+ // GetUpdatesMessage in the request had need_encryption_key == true.
+ optional bytes encryption_key = 6;
};
// The metadata response for GetUpdatesMessage. This response is sent when
@@ -625,25 +637,6 @@ message ClientToServerResponse {
optional CommitResponse commit = 1;
optional GetUpdatesResponse get_updates = 2;
optional AuthenticateResponse authenticate = 3;
- // DEPRECATED - this field was never used in production.
- // optional ClearUserDataResponse clear_user_data = 9;
- optional GetUpdatesMetadataResponse stream_metadata = 10;
- // If GetUpdatesStreamingResponse is contained in the ClientToServerResponse,
- // none of the other fields (error_code and etc) will be set.
- optional GetUpdatesStreamingResponse stream_data = 11;
-
- message Error {
- optional SyncEnums.ErrorType error_type = 1 [default = UNKNOWN];
- optional string error_description = 2;
- optional string url = 3;
- optional SyncEnums.Action action = 4 [default = UNKNOWN_ACTION];
-
- // Currently only meaningful if |error_type| is throttled. If this field
- // is absent then the whole client (all datatypes) is throttled.
- repeated int32 error_data_type_ids = 5;
- }
-
- optional Error error = 13;
// Up until protocol_version 24, the default was SUCCESS which made it
// impossible to add new enum values since older clients would parse any
@@ -663,9 +656,27 @@ message ClientToServerResponse {
optional ClientCommand client_command = 7;
optional ProfilingData profiling_data = 8;
+ // DEPRECATED - this field was never used in production.
+ // optional ClearUserDataResponse clear_user_data = 9;
+ optional GetUpdatesMetadataResponse stream_metadata = 10;
+ // If GetUpdatesStreamingResponse is contained in the ClientToServerResponse,
+ // none of the other fields (error_code and etc) will be set.
+ optional GetUpdatesStreamingResponse stream_data = 11;
// The data types whose storage has been migrated. Present when the value of
// error_code is MIGRATION_DONE.
repeated int32 migrated_data_type_id = 12;
+
+ message Error {
+ optional SyncEnums.ErrorType error_type = 1 [default = UNKNOWN];
+ optional string error_description = 2;
+ optional string url = 3;
+ optional SyncEnums.Action action = 4 [default = UNKNOWN_ACTION];
+
+ // Currently only meaningful if |error_type| is throttled. If this field
+ // is absent then the whole client (all datatypes) is throttled.
+ repeated int32 error_data_type_ids = 5;
+ }
+ optional Error error = 13;
};
diff --git a/sync/sessions/status_controller.cc b/sync/sessions/status_controller.cc
index 3694fe4..61b1094 100644
--- a/sync/sessions/status_controller.cc
+++ b/sync/sessions/status_controller.cc
@@ -142,6 +142,10 @@ void StatusController::set_sync_protocol_error(
model_neutral_.sync_protocol_error = error;
}
+void StatusController::set_last_get_key_result(const SyncerError result) {
+ model_neutral_.last_get_key_result = result;
+}
+
void StatusController::set_last_download_updates_result(
const SyncerError result) {
model_neutral_.last_download_updates_result = result;
@@ -151,6 +155,10 @@ void StatusController::set_commit_result(const SyncerError result) {
model_neutral_.commit_result = result;
}
+SyncerError StatusController::last_get_key_result() const {
+ return model_neutral_.last_get_key_result;
+}
+
void StatusController::update_conflicts_resolved(bool resolved) {
model_neutral_.conflicts_resolved |= resolved;
}
diff --git a/sync/sessions/status_controller.h b/sync/sessions/status_controller.h
index 8542b48..752d07d 100644
--- a/sync/sessions/status_controller.h
+++ b/sync/sessions/status_controller.h
@@ -149,6 +149,8 @@ class StatusController {
return model_neutral_;
}
+ SyncerError last_get_key_result() const;
+
// A toolbelt full of methods for updating counters and flags.
void set_num_server_changes_remaining(int64 changes_remaining);
void set_num_successful_bookmark_commits(int value);
@@ -161,6 +163,7 @@ class StatusController {
void increment_num_local_overwrites();
void increment_num_server_overwrites();
void set_sync_protocol_error(const SyncProtocolError& error);
+ void set_last_get_key_result(const SyncerError result);
void set_last_download_updates_result(const SyncerError result);
void set_commit_result(const SyncerError result);
diff --git a/sync/sessions/sync_session.cc b/sync/sessions/sync_session.cc
index 7af4c50..f432978 100644
--- a/sync/sessions/sync_session.cc
+++ b/sync/sessions/sync_session.cc
@@ -241,17 +241,17 @@ std::set<ModelSafeGroup>
namespace {
// Return true if the command in question was attempted and did not complete
// successfully.
-//
bool IsError(SyncerError error) {
return error != UNSET && error != SYNCER_OK;
}
// Returns false iff one of the command results had an error.
bool HadErrors(const ModelNeutralState& state) {
+ const bool get_key_error = IsError(state.last_get_key_result);
const bool download_updates_error =
IsError(state.last_download_updates_result);
const bool commit_error = IsError(state.commit_result);
- return download_updates_error || commit_error;
+ return get_key_error || download_updates_error || commit_error;
}
} // namespace
@@ -261,7 +261,8 @@ bool SyncSession::Succeeded() const {
bool SyncSession::SuccessfullyReachedServer() const {
const ModelNeutralState& state = status_controller_->model_neutral_state();
- bool reached_server = state.last_download_updates_result == SYNCER_OK;
+ bool reached_server = state.last_get_key_result == SYNCER_OK ||
+ state.last_download_updates_result == SYNCER_OK;
// It's possible that we reached the server on one attempt, then had an error
// on the next (or didn't perform some of the server-communicating commands).
// We want to verify that, for all commands attempted, we successfully spoke
diff --git a/sync/sessions/sync_session_context.cc b/sync/sessions/sync_session_context.cc
index 7b6349b..fa946d0 100644
--- a/sync/sessions/sync_session_context.cc
+++ b/sync/sessions/sync_session_context.cc
@@ -22,7 +22,8 @@ SyncSessionContext::SyncSessionContext(
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder)
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled)
: resolver_(NULL),
connection_manager_(connection_manager),
directory_(directory),
@@ -32,7 +33,8 @@ SyncSessionContext::SyncSessionContext(
max_commit_batch_size_(kDefaultMaxCommitBatchSize),
throttled_data_type_tracker_(throttled_data_type_tracker),
debug_info_getter_(debug_info_getter),
- traffic_recorder_(traffic_recorder) {
+ traffic_recorder_(traffic_recorder),
+ keystore_encryption_enabled_(keystore_encryption_enabled) {
std::vector<SyncEngineEventListener*>::const_iterator it;
for (it = listeners.begin(); it != listeners.end(); ++it)
listeners_.AddObserver(*it);
diff --git a/sync/sessions/sync_session_context.h b/sync/sessions/sync_session_context.h
index 400a6aa..3f01150 100644
--- a/sync/sessions/sync_session_context.h
+++ b/sync/sessions/sync_session_context.h
@@ -56,7 +56,9 @@ class SyncSessionContext {
ThrottledDataTypeTracker* throttled_data_type_tracker,
const std::vector<SyncEngineEventListener*>& listeners,
DebugInfoGetter* debug_info_getter,
- TrafficRecorder* traffic_recorder);
+ TrafficRecorder* traffic_recorder,
+ bool keystore_encryption_enabled);
+
~SyncSessionContext();
ConflictResolver* resolver() { return resolver_; }
@@ -118,6 +120,10 @@ class SyncSessionContext {
return traffic_recorder_;
}
+ bool keystore_encryption_enabled() const {
+ return keystore_encryption_enabled_;
+ }
+
private:
// Rather than force clients to set and null-out various context members, we
// extend our encapsulation boundary to scoped helpers that take care of this
@@ -162,6 +168,11 @@ class SyncSessionContext {
TrafficRecorder* traffic_recorder_;
+ // Temporary variable while keystore encryption is behind a flag. True if
+ // we should attempt performing keystore encryption related work, false if
+ // the experiment is not enabled.
+ bool keystore_encryption_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(SyncSessionContext);
};
diff --git a/sync/sessions/sync_session_unittest.cc b/sync/sessions/sync_session_unittest.cc
index bd17d359..ae2922d 100644
--- a/sync/sessions/sync_session_unittest.cc
+++ b/sync/sessions/sync_session_unittest.cc
@@ -67,7 +67,8 @@ class SyncSessionTest : public testing::Test,
throttled_data_type_tracker_.get(),
std::vector<SyncEngineEventListener*>(),
NULL,
- NULL));
+ NULL,
+ true /* enable keystore encryption */));
context_->set_routing_info(routes_);
session_.reset(MakeSession());
diff --git a/sync/sessions/test_util.cc b/sync/sessions/test_util.cc
index 875d133..ef734b7 100644
--- a/sync/sessions/test_util.cc
+++ b/sync/sessions/test_util.cc
@@ -14,8 +14,17 @@ void SimulateHasMoreToSync(sessions::SyncSession* session,
ASSERT_TRUE(session->HasMoreToSync());
}
+void SimulateGetEncryptionKeyFailed(sessions::SyncSession* session,
+ SyncerStep begin, SyncerStep end) {
+ session->mutable_status_controller()->set_last_get_key_result(
+ SERVER_RESPONSE_VALIDATION_FAILED);
+ session->mutable_status_controller()->set_last_download_updates_result(
+ SYNCER_OK);
+}
+
void SimulateDownloadUpdatesFailed(sessions::SyncSession* session,
SyncerStep begin, SyncerStep end) {
+ session->mutable_status_controller()->set_last_get_key_result(SYNCER_OK);
session->mutable_status_controller()->set_last_download_updates_result(
SERVER_RETURN_TRANSIENT_ERROR);
}
@@ -40,6 +49,7 @@ void SimulateSuccess(sessions::SyncSession* session,
ASSERT_EQ(0U, session->status_controller().num_server_changes_remaining());
session->SetFinished();
if (end == SYNCER_END) {
+ session->mutable_status_controller()->set_last_get_key_result(SYNCER_OK);
session->mutable_status_controller()->set_last_download_updates_result(
SYNCER_OK);
session->mutable_status_controller()->set_commit_result(SYNCER_OK);
diff --git a/sync/sessions/test_util.h b/sync/sessions/test_util.h
index 9cfe9e2..a6fa431 100644
--- a/sync/sessions/test_util.h
+++ b/sync/sessions/test_util.h
@@ -17,6 +17,8 @@ namespace test_util {
void SimulateHasMoreToSync(sessions::SyncSession* session,
SyncerStep begin, SyncerStep end);
+void SimulateGetEncryptionKeyFailed(sessions::SyncSession* session,
+ SyncerStep begin, SyncerStep end);
void SimulateDownloadUpdatesFailed(sessions::SyncSession* session,
SyncerStep begin, SyncerStep end);
void SimulateCommitFailed(sessions::SyncSession* session,
diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc
index 5b5174d..3739bf3 100644
--- a/sync/test/engine/mock_connection_manager.cc
+++ b/sync/test/engine/mock_connection_manager.cc
@@ -11,6 +11,7 @@
#include "base/location.h"
#include "base/stringprintf.h"
#include "sync/engine/syncer_proto_util.h"
+#include "sync/test/engine/test_id_factory.h"
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/write_transaction.h"
@@ -427,7 +428,7 @@ void MockConnectionManager::ProcessGetUpdates(
if (!updates->entries(i).deleted()) {
ModelType entry_type = GetModelType(updates->entries(i));
EXPECT_TRUE(
- IsModelTypePresentInSpecifics(gu.from_progress_marker(), entry_type))
+ IsModelTypePresentInSpecifics(gu.from_progress_marker(), entry_type))
<< "Syncer did not request updates being provided by the test.";
}
}
@@ -447,9 +448,19 @@ void MockConnectionManager::ProcessGetUpdates(
}
}
+ // Fill the keystore key if requested.
+ if (gu.need_encryption_key())
+ response->mutable_get_updates()->set_encryption_key(keystore_key_);
+
update_queue_.pop_front();
}
+void MockConnectionManager::SetKeystoreKey(const std::string& key) {
+ // Note: this is not a thread-safe set, ok for now. NOT ok if tests
+ // run the syncer on the background thread while this method is called.
+ keystore_key_ = key;
+}
+
bool MockConnectionManager::ShouldConflictThisCommit() {
bool conflict = false;
if (conflict_all_commits_) {
diff --git a/sync/test/engine/mock_connection_manager.h b/sync/test/engine/mock_connection_manager.h
index eb98471..5aabe7f 100644
--- a/sync/test/engine/mock_connection_manager.h
+++ b/sync/test/engine/mock_connection_manager.h
@@ -122,6 +122,8 @@ class MockConnectionManager : public ServerConnectionManager {
void FailNextPostBufferToPathCall() { countdown_to_postbuffer_fail_ = 1; }
void FailNthPostBufferToPathCall(int n) { countdown_to_postbuffer_fail_ = n; }
+ void SetKeystoreKey(const std::string& key);
+
void FailNonPeriodicGetUpdates() { fail_non_periodic_get_updates_ = true; }
// Simple inspectors.
@@ -302,8 +304,8 @@ class MockConnectionManager : public ServerConnectionManager {
base::Closure mid_commit_callback_;
MidCommitObserver* mid_commit_observer_;
- // The clear data response we'll return in the next response
- sync_pb::SyncEnums::ErrorType clear_user_data_response_errortype_;
+ // The keystore key we return for a GetUpdates with need_encryption_key set.
+ std::string keystore_key_;
// The AUTHENTICATE response we'll return for auth requests.
sync_pb::AuthenticateResponse auth_response_;
diff --git a/sync/test/engine/syncer_command_test.h b/sync/test/engine/syncer_command_test.h
index 0c0185e..803ef18 100644
--- a/sync/test/engine/syncer_command_test.h
+++ b/sync/test/engine/syncer_command_test.h
@@ -127,7 +127,8 @@ class SyncerCommandTestBase : public testing::Test,
throttled_data_type_tracker_.get(),
std::vector<SyncEngineEventListener*>(),
&mock_debug_info_getter_,
- &traffic_recorder_));
+ &traffic_recorder_,
+ true /* enable keystore encryption*/ ));
context_->set_account_name(directory()->name());
ClearSession();
}
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index 4da8cc1..357b694 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -362,6 +362,7 @@ int SyncClientMain(int argc, char* argv[]) {
scoped_ptr<SyncNotifier>(
sync_notifier_factory.CreateSyncNotifier()),
kRestoredKeyForBootstrapping,
+ true, // enable keystore encryption
scoped_ptr<InternalComponentsFactory>(
new InternalComponentsFactoryImpl()),
&null_encryptor,
diff --git a/sync/util/cryptographer.cc b/sync/util/cryptographer.cc
index 2c0d794..d63166b 100644
--- a/sync/util/cryptographer.cc
+++ b/sync/util/cryptographer.cc
@@ -25,6 +25,7 @@ Cryptographer::Observer::~Observer() {}
Cryptographer::Cryptographer(Encryptor* encryptor)
: encryptor_(encryptor),
default_nigori_(NULL),
+ keystore_nigori_(NULL),
encrypted_types_(SensitiveTypes()),
encrypt_everything_(false) {
DCHECK(encryptor);
@@ -308,6 +309,26 @@ Cryptographer::UpdateResult Cryptographer::Update(
return Cryptographer::SUCCESS;
}
+bool Cryptographer::SetKeystoreKey(const std::string& keystore_key) {
+ if (keystore_key.empty())
+ return false;
+ KeyParams params = {"localhost", "dummy", keystore_key};
+
+ // AddKey updates the default nigori, so we save the current default and
+ // make sure the keystore_nigori_ gets updated instead.
+ NigoriMap::value_type* old_default = default_nigori_;
+ if (AddKey(params)) {
+ keystore_nigori_ = default_nigori_;
+ default_nigori_ = old_default;
+ return true;
+ }
+ return false;
+}
+
+bool Cryptographer::HasKeystoreKey() {
+ return keystore_nigori_ != NULL;
+}
+
// Static
ModelTypeSet Cryptographer::SensitiveTypes() {
// Both of these have their own encryption schemes, but we include them
diff --git a/sync/util/cryptographer.h b/sync/util/cryptographer.h
index f02875a..d664020 100644
--- a/sync/util/cryptographer.h
+++ b/sync/util/cryptographer.h
@@ -179,6 +179,15 @@ class Cryptographer {
// stored in the |pending_keys_|.
UpdateResult Update(const sync_pb::NigoriSpecifics& nigori);
+ // Set the keystore-derived nigori from the provided key.
+ // Returns true if we succesfully create the keystore derived nigori from the
+ // provided key, false otherwise.
+ bool SetKeystoreKey(const std::string& keystore_key);
+
+ // Returns true if we currently have a keystore-derived nigori, false
+ // otherwise.
+ bool HasKeystoreKey();
+
// The set of types that are always encrypted.
static ModelTypeSet SensitiveTypes();
@@ -237,6 +246,7 @@ class Cryptographer {
NigoriMap nigoris_; // The Nigoris we know about, mapped by key name.
NigoriMap::value_type* default_nigori_; // The Nigori used for encryption.
+ NigoriMap::value_type* keystore_nigori_; // Nigori generated from keystore.
scoped_ptr<sync_pb::EncryptedData> pending_keys_;
diff --git a/sync/util/get_session_name.cc b/sync/util/get_session_name.cc
index 99a4ce0..8c86c5c 100644
--- a/sync/util/get_session_name.cc
+++ b/sync/util/get_session_name.cc
@@ -43,7 +43,7 @@ std::string GetSessionNameSynchronously() {
#elif defined(OS_LINUX)
session_name = base::GetLinuxDistro();
#elif defined(OS_MACOSX)
- session_name = internal::GetHardwareModelName();
+// session_name = internal::GetHardwareModelName();
#elif defined(OS_WIN)
session_name = internal::GetComputerName();
#elif defined(OS_ANDROID)