1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/wifi_sync/wifi_credential_syncable_service.h"
10 #include "base/logging.h"
11 #include "components/wifi_sync/wifi_credential.h"
12 #include "components/wifi_sync/wifi_security_class.h"
13 #include "sync/api/sync_change.h"
14 #include "sync/api/sync_data.h"
15 #include "sync/api/sync_error.h"
16 #include "sync/api/sync_error_factory.h"
17 #include "sync/api/sync_merge_result.h"
18 #include "sync/protocol/sync.pb.h"
24 struct RawCredentialData
{
25 std::vector
<uint8_t> ssid
;
26 WifiSecurityClass security_class
;
27 std::string passphrase
;
30 void BuildSpecifics(const WifiCredential
& credential
,
31 sync_pb::EntitySpecifics
* out_buffer
) {
33 sync_pb::WifiCredentialSpecifics
* credential_specifics
=
34 out_buffer
->mutable_wifi_credential();
35 DCHECK(credential_specifics
);
36 credential_specifics
->set_ssid(credential
.ssid().data(),
37 credential
.ssid().size());
38 credential_specifics
->set_security_class(
39 WifiSecurityClassToSyncSecurityClass(credential
.security_class()));
40 if (WifiSecurityClassSupportsPassphrases(credential
.security_class())) {
41 credential_specifics
->set_passphrase(credential
.passphrase().data(),
42 credential
.passphrase().size());
46 bool ParseSpecifics(const sync_pb::EntitySpecifics
& specifics
,
47 RawCredentialData
* raw_credential
) {
48 DCHECK(raw_credential
);
49 if (!specifics
.has_wifi_credential()) {
50 LOG(ERROR
) << "Specifics with missing wifi_credential; skipping";
54 const sync_pb::WifiCredentialSpecifics
& credential_specifics
=
55 specifics
.wifi_credential();
56 if (!credential_specifics
.has_ssid()) {
57 LOG(ERROR
) << "Specifics with missing SSID; skipping";
60 if (!credential_specifics
.has_security_class()) {
61 LOG(ERROR
) << "Specifics with missing security class; skipping";
65 const WifiSecurityClass security_class
=
66 WifiSecurityClassFromSyncSecurityClass(
67 credential_specifics
.security_class());
68 if (WifiSecurityClassSupportsPassphrases(security_class
) &&
69 !credential_specifics
.has_passphrase()) {
70 LOG(ERROR
) << "Specifics for security class "
71 << credential_specifics
.security_class()
72 << " is missing passphrase; skipping";
76 raw_credential
->ssid
.assign(credential_specifics
.ssid().begin(),
77 credential_specifics
.ssid().end());
78 raw_credential
->security_class
= security_class
;
79 raw_credential
->passphrase
= credential_specifics
.passphrase();
83 // TODO(quiche): Separate SyncData validation from parsing of
84 // WifiCredentialSpecifics.
85 bool ParseSyncData(const syncer::SyncData
& sync_data
,
86 RawCredentialData
* raw_credential
) {
87 DCHECK(raw_credential
);
88 if (!sync_data
.IsValid()) {
89 LOG(WARNING
) << "Invalid SyncData; skipping item";
93 if (sync_data
.GetDataType() != syncer::WIFI_CREDENTIALS
) {
94 LOG(WARNING
) << "Unexpected SyncData of type "
95 << syncer::ModelTypeToString(sync_data
.GetDataType())
100 return ParseSpecifics(sync_data
.GetSpecifics(), raw_credential
);
105 const syncer::ModelType
WifiCredentialSyncableService::kModelType
=
106 syncer::WIFI_CREDENTIALS
;
108 WifiCredentialSyncableService::WifiCredentialSyncableService(
109 scoped_ptr
<WifiConfigDelegate
> network_config_delegate
)
110 : network_config_delegate_(network_config_delegate
.Pass()) {
111 DCHECK(network_config_delegate_
);
114 WifiCredentialSyncableService::~WifiCredentialSyncableService() {
117 syncer::SyncMergeResult
WifiCredentialSyncableService::MergeDataAndStartSyncing(
118 syncer::ModelType type
,
119 const syncer::SyncDataList
& initial_sync_data
,
120 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor
,
121 scoped_ptr
<syncer::SyncErrorFactory
> /* error_handler */) {
122 DCHECK(!sync_processor_
.get());
123 DCHECK(sync_processor
.get());
124 DCHECK_EQ(kModelType
, type
);
126 sync_processor_
= sync_processor
.Pass();
128 // TODO(quiche): Update local WiFi configuration from |initial_sync_data|.
129 // TODO(quiche): Notify upper layers that sync is ready.
132 return syncer::SyncMergeResult(type
);
135 void WifiCredentialSyncableService::StopSyncing(syncer::ModelType type
) {
136 DCHECK_EQ(kModelType
, type
);
137 sync_processor_
.reset();
140 syncer::SyncDataList
WifiCredentialSyncableService::GetAllSyncData(
141 syncer::ModelType type
) const {
142 DCHECK_EQ(kModelType
, type
);
144 return syncer::SyncDataList();
147 syncer::SyncError
WifiCredentialSyncableService::ProcessSyncChanges(
148 const tracked_objects::Location
& /* caller_location */,
149 const syncer::SyncChangeList
& change_list
) {
150 if (!sync_processor_
.get()) {
151 return syncer::SyncError(
152 FROM_HERE
, syncer::SyncError::UNREADY_ERROR
,
153 "ProcessSyncChanges called before MergeDataAndStartSyncing",
157 for (const syncer::SyncChange
& sync_change
: change_list
) {
158 DCHECK(sync_change
.IsValid());
159 RawCredentialData raw_credential
;
160 if (!ParseSyncData(sync_change
.sync_data(), &raw_credential
)) {
161 LOG(WARNING
) << "Failed to parse item; skipping "
162 << syncer::SyncChange::ChangeTypeToString(
163 sync_change
.change_type());
167 scoped_ptr
<WifiCredential
> credential
;
168 switch (sync_change
.change_type()) {
169 case syncer::SyncChange::ACTION_ADD
:
170 credential
= WifiCredential::Create(raw_credential
.ssid
,
171 raw_credential
.security_class
,
172 raw_credential
.passphrase
);
174 LOG(WARNING
) << "Failed to create credential; skipping";
176 network_config_delegate_
->AddToLocalNetworks(*credential
);
178 case syncer::SyncChange::ACTION_UPDATE
:
179 // TODO(quiche): Implement update, and add appropriate tests.
182 case syncer::SyncChange::ACTION_DELETE
:
183 // TODO(quiche): Implement delete, and add appropriate tests.
187 return syncer::SyncError(
188 FROM_HERE
, syncer::SyncError::DATATYPE_ERROR
,
189 "ProcessSyncChanges given invalid SyncChangeType", kModelType
);
193 return syncer::SyncError();
196 bool WifiCredentialSyncableService::AddToSyncedNetworks(
197 const std::string
& item_id
,
198 const WifiCredential
& credential
) {
199 if (!sync_processor_
.get()) {
200 // Callers must queue updates until MergeDataAndStartSyncing has
201 // been called on this SyncableService.
202 LOG(WARNING
) << "WifiCredentials syncable service is not started.";
206 const SsidAndSecurityClass
network_id(
207 credential
.ssid(), credential
.security_class());
208 if (synced_networks_and_passphrases_
.find(network_id
) !=
209 synced_networks_and_passphrases_
.end()) {
210 // TODO(quiche): If passphrase has changed, submit this to sync as
211 // an ACTION_UPDATE. crbug.com/431436
215 syncer::SyncChangeList change_list
;
216 syncer::SyncError sync_error
;
217 sync_pb::EntitySpecifics wifi_credential_specifics
;
218 BuildSpecifics(credential
, &wifi_credential_specifics
);
219 change_list
.push_back(
220 syncer::SyncChange(FROM_HERE
, syncer::SyncChange::ACTION_ADD
,
221 syncer::SyncData::CreateLocalData(
222 item_id
, item_id
, wifi_credential_specifics
)));
223 sync_error
= sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
224 if (sync_error
.IsSet()) {
225 LOG(ERROR
) << sync_error
.ToString();
229 synced_networks_and_passphrases_
[network_id
] = credential
.passphrase();
233 } // namespace wifi_sync