Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: chrome/browser/sync/internal_api/base_node.cc

Issue 10147003: [Sync] Move 'syncapi_core' and 'sync_unit_tests' targets to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Win update errors Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "chrome/browser/sync/internal_api/base_node.h"
6
7 #include "base/base64.h"
8 #include "base/sha1.h"
9 #include "base/string_number_conversions.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/sync/internal_api/syncapi_internal.h"
13 #include "chrome/browser/sync/internal_api/base_transaction.h"
14 #include "sync/protocol/app_specifics.pb.h"
15 #include "sync/protocol/autofill_specifics.pb.h"
16 #include "sync/protocol/bookmark_specifics.pb.h"
17 #include "sync/protocol/extension_specifics.pb.h"
18 #include "sync/protocol/nigori_specifics.pb.h"
19 #include "sync/protocol/password_specifics.pb.h"
20 #include "sync/protocol/session_specifics.pb.h"
21 #include "sync/protocol/theme_specifics.pb.h"
22 #include "sync/protocol/typed_url_specifics.pb.h"
23 #include "sync/syncable/syncable.h"
24 #include "sync/syncable/syncable_id.h"
25 #include "sync/util/time.h"
26
27 using syncable::SPECIFICS;
28 using sync_pb::AutofillProfileSpecifics;
29
30 namespace sync_api {
31
32 // Helper function to look up the int64 metahandle of an object given the ID
33 // string.
34 static int64 IdToMetahandle(syncable::BaseTransaction* trans,
35 const syncable::Id& id) {
36 syncable::Entry entry(trans, syncable::GET_BY_ID, id);
37 if (!entry.good())
38 return kInvalidId;
39 return entry.Get(syncable::META_HANDLE);
40 }
41
42 static bool EndsWithSpace(const std::string& string) {
43 return !string.empty() && *string.rbegin() == ' ';
44 }
45
46 // In the reverse direction, if a server name matches the pattern of a
47 // server-illegal name followed by one or more spaces, remove the trailing
48 // space.
49 static void ServerNameToSyncAPIName(const std::string& server_name,
50 std::string* out) {
51 CHECK(out);
52 int length_to_copy = server_name.length();
53 if (IsNameServerIllegalAfterTrimming(server_name) &&
54 EndsWithSpace(server_name)) {
55 --length_to_copy;
56 }
57 *out = std::string(server_name.c_str(), length_to_copy);
58 }
59
60 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {}
61
62 BaseNode::~BaseNode() {}
63
64 std::string BaseNode::GenerateSyncableHash(
65 syncable::ModelType model_type, const std::string& client_tag) {
66 // Blank PB with just the field in it has termination symbol,
67 // handy for delimiter.
68 sync_pb::EntitySpecifics serialized_type;
69 syncable::AddDefaultFieldValue(model_type, &serialized_type);
70 std::string hash_input;
71 serialized_type.AppendToString(&hash_input);
72 hash_input.append(client_tag);
73
74 std::string encode_output;
75 CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
76 return encode_output;
77 }
78
79 bool BaseNode::DecryptIfNecessary() {
80 if (!GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty())
81 return true; // Ignore unique folders.
82 const sync_pb::EntitySpecifics& specifics =
83 GetEntry()->Get(syncable::SPECIFICS);
84 if (specifics.has_password()) {
85 // Passwords have their own legacy encryption structure.
86 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
87 specifics, GetTransaction()->GetCryptographer()));
88 if (!data.get()) {
89 LOG(ERROR) << "Failed to decrypt password specifics.";
90 return false;
91 }
92 password_data_.swap(data);
93 return true;
94 }
95
96 // We assume any node with the encrypted field set has encrypted data and if
97 // not we have no work to do, with the exception of bookmarks. For bookmarks
98 // we must make sure the bookmarks data has the title field supplied. If not,
99 // we fill the unencrypted_data_ with a copy of the bookmark specifics that
100 // follows the new bookmarks format.
101 if (!specifics.has_encrypted()) {
102 if (GetModelType() == syncable::BOOKMARKS &&
103 !specifics.bookmark().has_title() &&
104 !GetTitle().empty()) { // Last check ensures this isn't a new node.
105 // We need to fill in the title.
106 std::string title = GetTitle();
107 std::string server_legal_title;
108 SyncAPINameToServerName(title, &server_legal_title);
109 DVLOG(1) << "Reading from legacy bookmark, manually returning title "
110 << title;
111 unencrypted_data_.CopyFrom(specifics);
112 unencrypted_data_.mutable_bookmark()->set_title(
113 server_legal_title);
114 }
115 return true;
116 }
117
118 const sync_pb::EncryptedData& encrypted = specifics.encrypted();
119 std::string plaintext_data = GetTransaction()->GetCryptographer()->
120 DecryptToString(encrypted);
121 if (plaintext_data.length() == 0 ||
122 !unencrypted_data_.ParseFromString(plaintext_data)) {
123 LOG(ERROR) << "Failed to decrypt encrypted node of type " <<
124 syncable::ModelTypeToString(GetModelType()) << ".";
125 return false;
126 }
127 DVLOG(2) << "Decrypted specifics of type "
128 << syncable::ModelTypeToString(GetModelType())
129 << " with content: " << plaintext_data;
130 return true;
131 }
132
133 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
134 const syncable::Entry* entry) const {
135 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS);
136 if (specifics.has_encrypted()) {
137 DCHECK_NE(syncable::GetModelTypeFromSpecifics(unencrypted_data_),
138 syncable::UNSPECIFIED);
139 return unencrypted_data_;
140 } else {
141 // Due to the change in bookmarks format, we need to check to see if this is
142 // a legacy bookmarks (and has no title field in the proto). If it is, we
143 // return the unencrypted_data_, which was filled in with the title by
144 // DecryptIfNecessary().
145 if (GetModelType() == syncable::BOOKMARKS) {
146 const sync_pb::BookmarkSpecifics& bookmark_specifics =
147 specifics.bookmark();
148 if (bookmark_specifics.has_title() ||
149 GetTitle().empty() || // For the empty node case
150 !GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
151 // It's possible we previously had to convert and set
152 // |unencrypted_data_| but then wrote our own data, so we allow
153 // |unencrypted_data_| to be non-empty.
154 return specifics;
155 } else {
156 DCHECK_EQ(syncable::GetModelTypeFromSpecifics(unencrypted_data_),
157 syncable::BOOKMARKS);
158 return unencrypted_data_;
159 }
160 } else {
161 DCHECK_EQ(syncable::GetModelTypeFromSpecifics(unencrypted_data_),
162 syncable::UNSPECIFIED);
163 return specifics;
164 }
165 }
166 }
167
168 int64 BaseNode::GetParentId() const {
169 return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
170 GetEntry()->Get(syncable::PARENT_ID));
171 }
172
173 int64 BaseNode::GetId() const {
174 return GetEntry()->Get(syncable::META_HANDLE);
175 }
176
177 const base::Time& BaseNode::GetModificationTime() const {
178 return GetEntry()->Get(syncable::MTIME);
179 }
180
181 bool BaseNode::GetIsFolder() const {
182 return GetEntry()->Get(syncable::IS_DIR);
183 }
184
185 std::string BaseNode::GetTitle() const {
186 std::string result;
187 // TODO(zea): refactor bookmarks to not need this functionality.
188 if (syncable::BOOKMARKS == GetModelType() &&
189 GetEntry()->Get(syncable::SPECIFICS).has_encrypted()) {
190 // Special case for legacy bookmarks dealing with encryption.
191 ServerNameToSyncAPIName(GetBookmarkSpecifics().title(), &result);
192 } else {
193 ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME),
194 &result);
195 }
196 return result;
197 }
198
199 GURL BaseNode::GetURL() const {
200 return GURL(GetBookmarkSpecifics().url());
201 }
202
203 bool BaseNode::HasChildren() const {
204 syncable::Directory* dir = GetTransaction()->GetDirectory();
205 syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
206 return dir->HasChildren(trans, GetEntry()->Get(syncable::ID));
207 }
208
209 int64 BaseNode::GetPredecessorId() const {
210 syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
211 if (id_string.IsRoot())
212 return kInvalidId;
213 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
214 }
215
216 int64 BaseNode::GetSuccessorId() const {
217 syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
218 if (id_string.IsRoot())
219 return kInvalidId;
220 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
221 }
222
223 int64 BaseNode::GetFirstChildId() const {
224 syncable::Directory* dir = GetTransaction()->GetDirectory();
225 syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
226 syncable::Id id_string;
227 // TODO(akalin): Propagate up the error further (see
228 // http://crbug.com/100907).
229 CHECK(dir->GetFirstChildId(trans,
230 GetEntry()->Get(syncable::ID), &id_string));
231 if (id_string.IsRoot())
232 return kInvalidId;
233 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
234 }
235
236 DictionaryValue* BaseNode::GetSummaryAsValue() const {
237 DictionaryValue* node_info = new DictionaryValue();
238 node_info->SetString("id", base::Int64ToString(GetId()));
239 node_info->SetBoolean("isFolder", GetIsFolder());
240 node_info->SetString("title", GetTitle());
241 node_info->Set("type", ModelTypeToValue(GetModelType()));
242 return node_info;
243 }
244
245 DictionaryValue* BaseNode::GetDetailsAsValue() const {
246 DictionaryValue* node_info = GetSummaryAsValue();
247 node_info->SetString(
248 "modificationTime",
249 browser_sync::GetTimeDebugString(GetModificationTime()));
250 node_info->SetString("parentId", base::Int64ToString(GetParentId()));
251 // Specifics are already in the Entry value, so no need to duplicate
252 // it here.
253 node_info->SetString("externalId",
254 base::Int64ToString(GetExternalId()));
255 node_info->SetString("predecessorId",
256 base::Int64ToString(GetPredecessorId()));
257 node_info->SetString("successorId",
258 base::Int64ToString(GetSuccessorId()));
259 node_info->SetString("firstChildId",
260 base::Int64ToString(GetFirstChildId()));
261 node_info->Set("entry", GetEntry()->ToValue());
262 return node_info;
263 }
264
265 void BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
266 if (!output)
267 return;
268 const std::string& favicon = GetBookmarkSpecifics().favicon();
269 output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
270 reinterpret_cast<const unsigned char*>(favicon.data() +
271 favicon.length()));
272 }
273
274 int64 BaseNode::GetExternalId() const {
275 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
276 }
277
278 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
279 DCHECK_EQ(syncable::APPS, GetModelType());
280 return GetEntitySpecifics().app();
281 }
282
283 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
284 DCHECK_EQ(syncable::AUTOFILL, GetModelType());
285 return GetEntitySpecifics().autofill();
286 }
287
288 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
289 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
290 return GetEntitySpecifics().autofill_profile();
291 }
292
293 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
294 DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
295 return GetEntitySpecifics().bookmark();
296 }
297
298 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
299 DCHECK_EQ(syncable::NIGORI, GetModelType());
300 return GetEntitySpecifics().nigori();
301 }
302
303 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
304 DCHECK_EQ(syncable::PASSWORDS, GetModelType());
305 return *password_data_;
306 }
307
308 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
309 DCHECK_EQ(syncable::THEMES, GetModelType());
310 return GetEntitySpecifics().theme();
311 }
312
313 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
314 DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
315 return GetEntitySpecifics().typed_url();
316 }
317
318 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
319 DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
320 return GetEntitySpecifics().extension();
321 }
322
323 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
324 DCHECK_EQ(syncable::SESSIONS, GetModelType());
325 return GetEntitySpecifics().session();
326 }
327
328 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const {
329 return GetUnencryptedSpecifics(GetEntry());
330 }
331
332 syncable::ModelType BaseNode::GetModelType() const {
333 return GetEntry()->GetModelType();
334 }
335
336 void BaseNode::SetUnencryptedSpecifics(
337 const sync_pb::EntitySpecifics& specifics) {
338 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(specifics);
339 DCHECK_NE(syncable::UNSPECIFIED, type);
340 if (GetModelType() != syncable::UNSPECIFIED) {
341 DCHECK_EQ(GetModelType(), type);
342 }
343 unencrypted_data_.CopyFrom(specifics);
344 }
345
346 } // namespace sync_api
OLDNEW
« no previous file with comments | « chrome/browser/sync/internal_api/base_node.h ('k') | chrome/browser/sync/internal_api/base_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698