Roll src/third_party/WebKit 96fb88b:6bbd108 (svn 201045:201047)
[chromium-blink-merge.git] / sync / internal_api / base_node.cc
blob9ecbf19af70bf2dfeb139f3495aa3ae4757784b6
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.
5 #include "sync/internal_api/public/base_node.h"
7 #include <stack>
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "sync/internal_api/public/base_transaction.h"
12 #include "sync/internal_api/syncapi_internal.h"
13 #include "sync/protocol/app_specifics.pb.h"
14 #include "sync/protocol/autofill_specifics.pb.h"
15 #include "sync/protocol/bookmark_specifics.pb.h"
16 #include "sync/protocol/extension_specifics.pb.h"
17 #include "sync/protocol/nigori_specifics.pb.h"
18 #include "sync/protocol/password_specifics.pb.h"
19 #include "sync/protocol/session_specifics.pb.h"
20 #include "sync/protocol/theme_specifics.pb.h"
21 #include "sync/protocol/typed_url_specifics.pb.h"
22 #include "sync/syncable/directory.h"
23 #include "sync/syncable/entry.h"
24 #include "sync/syncable/syncable_base_transaction.h"
25 #include "sync/syncable/syncable_id.h"
26 #include "sync/util/time.h"
28 using sync_pb::AutofillProfileSpecifics;
30 namespace syncer {
32 using syncable::SPECIFICS;
34 // Helper function to look up the int64 metahandle of an object given the ID
35 // string.
36 static int64 IdToMetahandle(syncable::BaseTransaction* trans,
37 const syncable::Id& id) {
38 if (id.IsNull())
39 return kInvalidId;
40 syncable::Entry entry(trans, syncable::GET_BY_ID, id);
41 if (!entry.good())
42 return kInvalidId;
43 return entry.GetMetahandle();
46 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {}
48 BaseNode::~BaseNode() {}
50 bool BaseNode::DecryptIfNecessary() {
51 if (!GetEntry()->GetUniqueServerTag().empty())
52 return true; // Ignore unique folders.
53 const sync_pb::EntitySpecifics& specifics =
54 GetEntry()->GetSpecifics();
55 if (specifics.has_password()) {
56 // Passwords have their own legacy encryption structure.
57 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
58 specifics, GetTransaction()->GetCryptographer()));
59 if (!data) {
60 GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
61 FROM_HERE, std::string("Failed to decrypt encrypted node of type ") +
62 ModelTypeToString(GetModelType()));
63 return false;
65 password_data_.swap(data);
66 return true;
69 // We assume any node with the encrypted field set has encrypted data and if
70 // not we have no work to do, with the exception of bookmarks. For bookmarks
71 // we must make sure the bookmarks data has the title field supplied. If not,
72 // we fill the unencrypted_data_ with a copy of the bookmark specifics that
73 // follows the new bookmarks format.
74 if (!specifics.has_encrypted()) {
75 if (GetModelType() == BOOKMARKS &&
76 !specifics.bookmark().has_title() &&
77 !GetTitle().empty()) { // Last check ensures this isn't a new node.
78 // We need to fill in the title.
79 std::string title = GetTitle();
80 std::string server_legal_title;
81 SyncAPINameToServerName(title, &server_legal_title);
82 DVLOG(1) << "Reading from legacy bookmark, manually returning title "
83 << title;
84 unencrypted_data_.CopyFrom(specifics);
85 unencrypted_data_.mutable_bookmark()->set_title(
86 server_legal_title);
88 return true;
91 const sync_pb::EncryptedData& encrypted = specifics.encrypted();
92 std::string plaintext_data = GetTransaction()->GetCryptographer()->
93 DecryptToString(encrypted);
94 if (plaintext_data.length() == 0) {
95 GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
96 FROM_HERE, std::string("Failed to decrypt encrypted node of type ") +
97 ModelTypeToString(GetModelType()));
98 return false;
99 } else if (!unencrypted_data_.ParseFromString(plaintext_data)) {
100 GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
101 FROM_HERE, std::string("Failed to parse encrypted node of type ") +
102 ModelTypeToString(GetModelType()));
103 return false;
105 DVLOG(2) << "Decrypted specifics of type "
106 << ModelTypeToString(GetModelType())
107 << " with content: " << plaintext_data;
108 return true;
111 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
112 const syncable::Entry* entry) const {
113 const sync_pb::EntitySpecifics& specifics = entry->GetSpecifics();
114 if (specifics.has_encrypted()) {
115 DCHECK_NE(GetModelTypeFromSpecifics(unencrypted_data_), UNSPECIFIED);
116 return unencrypted_data_;
117 } else {
118 // Due to the change in bookmarks format, we need to check to see if this is
119 // a legacy bookmarks (and has no title field in the proto). If it is, we
120 // return the unencrypted_data_, which was filled in with the title by
121 // DecryptIfNecessary().
122 if (GetModelType() == BOOKMARKS) {
123 const sync_pb::BookmarkSpecifics& bookmark_specifics =
124 specifics.bookmark();
125 if (bookmark_specifics.has_title() ||
126 GetTitle().empty() || // For the empty node case
127 !GetEntry()->GetUniqueServerTag().empty()) {
128 // It's possible we previously had to convert and set
129 // |unencrypted_data_| but then wrote our own data, so we allow
130 // |unencrypted_data_| to be non-empty.
131 return specifics;
132 } else {
133 DCHECK_EQ(GetModelTypeFromSpecifics(unencrypted_data_), BOOKMARKS);
134 return unencrypted_data_;
136 } else {
137 DCHECK_EQ(GetModelTypeFromSpecifics(unencrypted_data_), UNSPECIFIED);
138 return specifics;
143 int64 BaseNode::GetParentId() const {
144 return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
145 GetEntry()->GetParentId());
148 int64 BaseNode::GetId() const {
149 return GetEntry()->GetMetahandle();
152 base::Time BaseNode::GetModificationTime() const {
153 return GetEntry()->GetMtime();
156 bool BaseNode::GetIsFolder() const {
157 return GetEntry()->GetIsDir();
160 std::string BaseNode::GetTitle() const {
161 std::string result;
162 // TODO(zea): refactor bookmarks to not need this functionality.
163 if (BOOKMARKS == GetModelType() &&
164 GetEntry()->GetSpecifics().has_encrypted()) {
165 // Special case for legacy bookmarks dealing with encryption.
166 ServerNameToSyncAPIName(GetBookmarkSpecifics().title(), &result);
167 } else {
168 ServerNameToSyncAPIName(GetEntry()->GetNonUniqueName(),
169 &result);
171 return result;
174 bool BaseNode::HasChildren() const {
175 syncable::Directory* dir = GetTransaction()->GetDirectory();
176 syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
177 return dir->HasChildren(trans, GetEntry()->GetId());
180 int64 BaseNode::GetPredecessorId() const {
181 syncable::Id id_string = GetEntry()->GetPredecessorId();
182 if (id_string.IsNull())
183 return kInvalidId;
184 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
187 int64 BaseNode::GetSuccessorId() const {
188 syncable::Id id_string = GetEntry()->GetSuccessorId();
189 if (id_string.IsNull())
190 return kInvalidId;
191 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
194 int64 BaseNode::GetFirstChildId() const {
195 syncable::Id id_string = GetEntry()->GetFirstChildId();
196 if (id_string.IsNull())
197 return kInvalidId;
198 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
201 void BaseNode::GetChildIds(std::vector<int64>* result) const {
202 GetEntry()->GetChildHandles(result);
205 int BaseNode::GetTotalNodeCount() const {
206 return GetEntry()->GetTotalNodeCount();
209 int BaseNode::GetPositionIndex() const {
210 return GetEntry()->GetPositionIndex();
213 base::DictionaryValue* BaseNode::ToValue() const {
214 return GetEntry()->ToValue(GetTransaction()->GetCryptographer());
217 int64 BaseNode::GetExternalId() const {
218 return GetEntry()->GetLocalExternalId();
221 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
222 DCHECK_EQ(GetModelType(), BOOKMARKS);
223 return GetEntitySpecifics().bookmark();
226 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
227 DCHECK_EQ(GetModelType(), NIGORI);
228 return GetEntitySpecifics().nigori();
231 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
232 DCHECK_EQ(GetModelType(), PASSWORDS);
233 return *password_data_;
236 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
237 DCHECK_EQ(GetModelType(), TYPED_URLS);
238 return GetEntitySpecifics().typed_url();
241 const sync_pb::ExperimentsSpecifics& BaseNode::GetExperimentsSpecifics() const {
242 DCHECK_EQ(GetModelType(), EXPERIMENTS);
243 return GetEntitySpecifics().experiments();
246 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const {
247 return GetUnencryptedSpecifics(GetEntry());
250 ModelType BaseNode::GetModelType() const {
251 return GetEntry()->GetModelType();
254 const syncer::AttachmentIdList BaseNode::GetAttachmentIds() const {
255 AttachmentIdList result;
256 const sync_pb::AttachmentMetadata& metadata =
257 GetEntry()->GetAttachmentMetadata();
258 for (int i = 0; i < metadata.record_size(); ++i) {
259 result.push_back(AttachmentId::CreateFromProto(metadata.record(i).id()));
261 return result;
264 void BaseNode::SetUnencryptedSpecifics(
265 const sync_pb::EntitySpecifics& specifics) {
266 ModelType type = GetModelTypeFromSpecifics(specifics);
267 DCHECK_NE(UNSPECIFIED, type);
268 if (GetModelType() != UNSPECIFIED) {
269 DCHECK_EQ(GetModelType(), type);
271 unencrypted_data_.CopyFrom(specifics);
274 } // namespace syncer