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

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

Issue 7624009: Original patch by rlarocque@chromium.org at http://codereview.chromium.org/7633077/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix windows build pt5 Created 9 years, 4 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) 2011 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/values.h"
11 #include "chrome/browser/sync/engine/syncapi_internal.h"
12 #include "chrome/browser/sync/internal_api/base_transaction.h"
13 #include "chrome/browser/sync/protocol/app_specifics.pb.h"
14 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
15 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
16 #include "chrome/browser/sync/protocol/extension_specifics.pb.h"
17 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
18 #include "chrome/browser/sync/protocol/password_specifics.pb.h"
19 #include "chrome/browser/sync/protocol/session_specifics.pb.h"
20 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
21 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
22 #include "chrome/browser/sync/syncable/directory_manager.h"
23 #include "chrome/browser/sync/syncable/syncable.h"
24 #include "chrome/browser/sync/syncable/syncable_id.h"
25
26 using syncable::SPECIFICS;
27 using sync_pb::AutofillProfileSpecifics;
28
29 namespace sync_api {
30
31 // Helper function to look up the int64 metahandle of an object given the ID
32 // string.
33 static int64 IdToMetahandle(syncable::BaseTransaction* trans,
34 const syncable::Id& id) {
35 syncable::Entry entry(trans, syncable::GET_BY_ID, id);
36 if (!entry.good())
37 return kInvalidId;
38 return entry.Get(syncable::META_HANDLE);
39 }
40
41 static bool EndsWithSpace(const std::string& string) {
42 return !string.empty() && *string.rbegin() == ' ';
43 }
44
45 // In the reverse direction, if a server name matches the pattern of a
46 // server-illegal name followed by one or more spaces, remove the trailing
47 // space.
48 static void ServerNameToSyncAPIName(const std::string& server_name,
49 std::string* out) {
50 CHECK(out);
51 int length_to_copy = server_name.length();
52 if (IsNameServerIllegalAfterTrimming(server_name) &&
53 EndsWithSpace(server_name)) {
54 --length_to_copy;
55 }
56 *out = std::string(server_name.c_str(), length_to_copy);
57 }
58
59 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {}
60
61 BaseNode::~BaseNode() {}
62
63 std::string BaseNode::GenerateSyncableHash(
64 syncable::ModelType model_type, const std::string& client_tag) {
65 // blank PB with just the extension in it has termination symbol,
66 // handy for delimiter
67 sync_pb::EntitySpecifics serialized_type;
68 syncable::AddDefaultExtensionValue(model_type, &serialized_type);
69 std::string hash_input;
70 serialized_type.AppendToString(&hash_input);
71 hash_input.append(client_tag);
72
73 std::string encode_output;
74 CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
75 return encode_output;
76 }
77
78 bool BaseNode::DecryptIfNecessary() {
79 if (!GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty())
80 return true; // Ignore unique folders.
81 const sync_pb::EntitySpecifics& specifics =
82 GetEntry()->Get(syncable::SPECIFICS);
83 if (specifics.HasExtension(sync_pb::password)) {
84 // Passwords have their own legacy encryption structure.
85 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
86 specifics, GetTransaction()->GetCryptographer()));
87 if (!data.get()) {
88 LOG(ERROR) << "Failed to decrypt password specifics.";
89 return false;
90 }
91 password_data_.swap(data);
92 return true;
93 }
94
95 // We assume any node with the encrypted field set has encrypted data.
96 if (!specifics.has_encrypted())
97 return true;
98
99 const sync_pb::EncryptedData& encrypted =
100 specifics.encrypted();
101 std::string plaintext_data = GetTransaction()->GetCryptographer()->
102 DecryptToString(encrypted);
103 if (plaintext_data.length() == 0 ||
104 !unencrypted_data_.ParseFromString(plaintext_data)) {
105 LOG(ERROR) << "Failed to decrypt encrypted node of type " <<
106 syncable::ModelTypeToString(GetModelType()) << ".";
107 return false;
108 }
109 VLOG(2) << "Decrypted specifics of type "
110 << syncable::ModelTypeToString(GetModelType())
111 << " with content: " << plaintext_data;
112 return true;
113 }
114
115 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
116 const syncable::Entry* entry) const {
117 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS);
118 if (specifics.has_encrypted()) {
119 DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) !=
120 syncable::UNSPECIFIED);
121 return unencrypted_data_;
122 } else {
123 DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) ==
124 syncable::UNSPECIFIED);
125 return specifics;
126 }
127 }
128
129 int64 BaseNode::GetParentId() const {
130 return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
131 GetEntry()->Get(syncable::PARENT_ID));
132 }
133
134 int64 BaseNode::GetId() const {
135 return GetEntry()->Get(syncable::META_HANDLE);
136 }
137
138 int64 BaseNode::GetModificationTime() const {
139 return GetEntry()->Get(syncable::MTIME);
140 }
141
142 bool BaseNode::GetIsFolder() const {
143 return GetEntry()->Get(syncable::IS_DIR);
144 }
145
146 std::string BaseNode::GetTitle() const {
147 std::string result;
148 // TODO(zea): refactor bookmarks to not need this functionality.
149 if (syncable::BOOKMARKS == GetModelType() &&
150 GetEntry()->Get(syncable::SPECIFICS).has_encrypted()) {
151 // Special case for legacy bookmarks dealing with encryption.
152 ServerNameToSyncAPIName(GetBookmarkSpecifics().title(), &result);
153 } else {
154 ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME),
155 &result);
156 }
157 return result;
158 }
159
160 GURL BaseNode::GetURL() const {
161 return GURL(GetBookmarkSpecifics().url());
162 }
163
164 int64 BaseNode::GetPredecessorId() const {
165 syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
166 if (id_string.IsRoot())
167 return kInvalidId;
168 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
169 }
170
171 int64 BaseNode::GetSuccessorId() const {
172 syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
173 if (id_string.IsRoot())
174 return kInvalidId;
175 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
176 }
177
178 int64 BaseNode::GetFirstChildId() const {
179 syncable::Directory* dir = GetTransaction()->GetLookup();
180 syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
181 syncable::Id id_string =
182 dir->GetFirstChildId(trans, GetEntry()->Get(syncable::ID));
183 if (id_string.IsRoot())
184 return kInvalidId;
185 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
186 }
187
188 DictionaryValue* BaseNode::GetSummaryAsValue() const {
189 DictionaryValue* node_info = new DictionaryValue();
190 node_info->SetString("id", base::Int64ToString(GetId()));
191 node_info->SetBoolean("isFolder", GetIsFolder());
192 node_info->SetString("title", GetTitle());
193 node_info->Set("type", ModelTypeToValue(GetModelType()));
194 return node_info;
195 }
196
197 DictionaryValue* BaseNode::GetDetailsAsValue() const {
198 DictionaryValue* node_info = GetSummaryAsValue();
199 // TODO(akalin): Return time in a better format.
200 node_info->SetString("modificationTime",
201 base::Int64ToString(GetModificationTime()));
202 node_info->SetString("parentId", base::Int64ToString(GetParentId()));
203 // Specifics are already in the Entry value, so no need to duplicate
204 // it here.
205 node_info->SetString("externalId",
206 base::Int64ToString(GetExternalId()));
207 node_info->SetString("predecessorId",
208 base::Int64ToString(GetPredecessorId()));
209 node_info->SetString("successorId",
210 base::Int64ToString(GetSuccessorId()));
211 node_info->SetString("firstChildId",
212 base::Int64ToString(GetFirstChildId()));
213 node_info->Set("entry", GetEntry()->ToValue());
214 return node_info;
215 }
216
217 void BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
218 if (!output)
219 return;
220 const std::string& favicon = GetBookmarkSpecifics().favicon();
221 output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
222 reinterpret_cast<const unsigned char*>(favicon.data() +
223 favicon.length()));
224 }
225
226 int64 BaseNode::GetExternalId() const {
227 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
228 }
229
230 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
231 DCHECK_EQ(syncable::APPS, GetModelType());
232 return GetEntitySpecifics().GetExtension(sync_pb::app);
233 }
234
235 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
236 DCHECK_EQ(syncable::AUTOFILL, GetModelType());
237 return GetEntitySpecifics().GetExtension(sync_pb::autofill);
238 }
239
240 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
241 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
242 return GetEntitySpecifics().GetExtension(sync_pb::autofill_profile);
243 }
244
245 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
246 DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
247 return GetEntitySpecifics().GetExtension(sync_pb::bookmark);
248 }
249
250 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
251 DCHECK_EQ(syncable::NIGORI, GetModelType());
252 return GetEntitySpecifics().GetExtension(sync_pb::nigori);
253 }
254
255 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
256 DCHECK_EQ(syncable::PASSWORDS, GetModelType());
257 return *password_data_;
258 }
259
260 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
261 DCHECK_EQ(syncable::THEMES, GetModelType());
262 return GetEntitySpecifics().GetExtension(sync_pb::theme);
263 }
264
265 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
266 DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
267 return GetEntitySpecifics().GetExtension(sync_pb::typed_url);
268 }
269
270 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
271 DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
272 return GetEntitySpecifics().GetExtension(sync_pb::extension);
273 }
274
275 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
276 DCHECK_EQ(syncable::SESSIONS, GetModelType());
277 return GetEntitySpecifics().GetExtension(sync_pb::session);
278 }
279
280 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const {
281 return GetUnencryptedSpecifics(GetEntry());
282 }
283
284 syncable::ModelType BaseNode::GetModelType() const {
285 return GetEntry()->GetModelType();
286 }
287
288 void BaseNode::SetUnencryptedSpecifics(
289 const sync_pb::EntitySpecifics& specifics) {
290 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(specifics);
291 DCHECK_NE(syncable::UNSPECIFIED, type);
292 if (GetModelType() != syncable::UNSPECIFIED) {
293 DCHECK_EQ(GetModelType(), type);
294 }
295 unencrypted_data_.CopyFrom(specifics);
296 }
297
298 } // 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