| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sync/internal_api/public/base_node.h" | 5 #include "sync/internal_api/public/base_node.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/sha1.h" | 8 #include "base/sha1.h" |
| 9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 --length_to_copy; | 57 --length_to_copy; |
| 58 } | 58 } |
| 59 *out = std::string(server_name.c_str(), length_to_copy); | 59 *out = std::string(server_name.c_str(), length_to_copy); |
| 60 } | 60 } |
| 61 | 61 |
| 62 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {} | 62 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {} |
| 63 | 63 |
| 64 BaseNode::~BaseNode() {} | 64 BaseNode::~BaseNode() {} |
| 65 | 65 |
| 66 std::string BaseNode::GenerateSyncableHash( | 66 std::string BaseNode::GenerateSyncableHash( |
| 67 syncable::ModelType model_type, const std::string& client_tag) { | 67 syncer::ModelType model_type, const std::string& client_tag) { |
| 68 // Blank PB with just the field in it has termination symbol, | 68 // Blank PB with just the field in it has termination symbol, |
| 69 // handy for delimiter. | 69 // handy for delimiter. |
| 70 sync_pb::EntitySpecifics serialized_type; | 70 sync_pb::EntitySpecifics serialized_type; |
| 71 syncable::AddDefaultFieldValue(model_type, &serialized_type); | 71 syncer::AddDefaultFieldValue(model_type, &serialized_type); |
| 72 std::string hash_input; | 72 std::string hash_input; |
| 73 serialized_type.AppendToString(&hash_input); | 73 serialized_type.AppendToString(&hash_input); |
| 74 hash_input.append(client_tag); | 74 hash_input.append(client_tag); |
| 75 | 75 |
| 76 std::string encode_output; | 76 std::string encode_output; |
| 77 CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output)); | 77 CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output)); |
| 78 return encode_output; | 78 return encode_output; |
| 79 } | 79 } |
| 80 | 80 |
| 81 bool BaseNode::DecryptIfNecessary() { | 81 bool BaseNode::DecryptIfNecessary() { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 94 password_data_.swap(data); | 94 password_data_.swap(data); |
| 95 return true; | 95 return true; |
| 96 } | 96 } |
| 97 | 97 |
| 98 // We assume any node with the encrypted field set has encrypted data and if | 98 // We assume any node with the encrypted field set has encrypted data and if |
| 99 // not we have no work to do, with the exception of bookmarks. For bookmarks | 99 // not we have no work to do, with the exception of bookmarks. For bookmarks |
| 100 // we must make sure the bookmarks data has the title field supplied. If not, | 100 // we must make sure the bookmarks data has the title field supplied. If not, |
| 101 // we fill the unencrypted_data_ with a copy of the bookmark specifics that | 101 // we fill the unencrypted_data_ with a copy of the bookmark specifics that |
| 102 // follows the new bookmarks format. | 102 // follows the new bookmarks format. |
| 103 if (!specifics.has_encrypted()) { | 103 if (!specifics.has_encrypted()) { |
| 104 if (GetModelType() == syncable::BOOKMARKS && | 104 if (GetModelType() == syncer::BOOKMARKS && |
| 105 !specifics.bookmark().has_title() && | 105 !specifics.bookmark().has_title() && |
| 106 !GetTitle().empty()) { // Last check ensures this isn't a new node. | 106 !GetTitle().empty()) { // Last check ensures this isn't a new node. |
| 107 // We need to fill in the title. | 107 // We need to fill in the title. |
| 108 std::string title = GetTitle(); | 108 std::string title = GetTitle(); |
| 109 std::string server_legal_title; | 109 std::string server_legal_title; |
| 110 SyncAPINameToServerName(title, &server_legal_title); | 110 SyncAPINameToServerName(title, &server_legal_title); |
| 111 DVLOG(1) << "Reading from legacy bookmark, manually returning title " | 111 DVLOG(1) << "Reading from legacy bookmark, manually returning title " |
| 112 << title; | 112 << title; |
| 113 unencrypted_data_.CopyFrom(specifics); | 113 unencrypted_data_.CopyFrom(specifics); |
| 114 unencrypted_data_.mutable_bookmark()->set_title( | 114 unencrypted_data_.mutable_bookmark()->set_title( |
| 115 server_legal_title); | 115 server_legal_title); |
| 116 } | 116 } |
| 117 return true; | 117 return true; |
| 118 } | 118 } |
| 119 | 119 |
| 120 const sync_pb::EncryptedData& encrypted = specifics.encrypted(); | 120 const sync_pb::EncryptedData& encrypted = specifics.encrypted(); |
| 121 std::string plaintext_data = GetTransaction()->GetCryptographer()-> | 121 std::string plaintext_data = GetTransaction()->GetCryptographer()-> |
| 122 DecryptToString(encrypted); | 122 DecryptToString(encrypted); |
| 123 if (plaintext_data.length() == 0) { | 123 if (plaintext_data.length() == 0) { |
| 124 LOG(ERROR) << "Failed to decrypt encrypted node of type " << | 124 LOG(ERROR) << "Failed to decrypt encrypted node of type " << |
| 125 syncable::ModelTypeToString(GetModelType()) << "."; | 125 syncer::ModelTypeToString(GetModelType()) << "."; |
| 126 // Debugging for crbug.com/123223. We failed to decrypt the data, which | 126 // Debugging for crbug.com/123223. We failed to decrypt the data, which |
| 127 // means we applied an update without having the key or lost the key at a | 127 // means we applied an update without having the key or lost the key at a |
| 128 // later point. | 128 // later point. |
| 129 CHECK(false); | 129 CHECK(false); |
| 130 return false; | 130 return false; |
| 131 } else if (!unencrypted_data_.ParseFromString(plaintext_data)) { | 131 } else if (!unencrypted_data_.ParseFromString(plaintext_data)) { |
| 132 // Debugging for crbug.com/123223. We should never succeed in decrypting | 132 // Debugging for crbug.com/123223. We should never succeed in decrypting |
| 133 // but fail to parse into a protobuf. | 133 // but fail to parse into a protobuf. |
| 134 CHECK(false); | 134 CHECK(false); |
| 135 return false; | 135 return false; |
| 136 } | 136 } |
| 137 DVLOG(2) << "Decrypted specifics of type " | 137 DVLOG(2) << "Decrypted specifics of type " |
| 138 << syncable::ModelTypeToString(GetModelType()) | 138 << syncer::ModelTypeToString(GetModelType()) |
| 139 << " with content: " << plaintext_data; | 139 << " with content: " << plaintext_data; |
| 140 return true; | 140 return true; |
| 141 } | 141 } |
| 142 | 142 |
| 143 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( | 143 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( |
| 144 const syncable::Entry* entry) const { | 144 const syncable::Entry* entry) const { |
| 145 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); | 145 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); |
| 146 if (specifics.has_encrypted()) { | 146 if (specifics.has_encrypted()) { |
| 147 DCHECK_NE(syncable::GetModelTypeFromSpecifics(unencrypted_data_), | 147 DCHECK_NE(syncer::GetModelTypeFromSpecifics(unencrypted_data_), |
| 148 syncable::UNSPECIFIED); | 148 syncer::UNSPECIFIED); |
| 149 return unencrypted_data_; | 149 return unencrypted_data_; |
| 150 } else { | 150 } else { |
| 151 // Due to the change in bookmarks format, we need to check to see if this is | 151 // Due to the change in bookmarks format, we need to check to see if this is |
| 152 // a legacy bookmarks (and has no title field in the proto). If it is, we | 152 // a legacy bookmarks (and has no title field in the proto). If it is, we |
| 153 // return the unencrypted_data_, which was filled in with the title by | 153 // return the unencrypted_data_, which was filled in with the title by |
| 154 // DecryptIfNecessary(). | 154 // DecryptIfNecessary(). |
| 155 if (GetModelType() == syncable::BOOKMARKS) { | 155 if (GetModelType() == syncer::BOOKMARKS) { |
| 156 const sync_pb::BookmarkSpecifics& bookmark_specifics = | 156 const sync_pb::BookmarkSpecifics& bookmark_specifics = |
| 157 specifics.bookmark(); | 157 specifics.bookmark(); |
| 158 if (bookmark_specifics.has_title() || | 158 if (bookmark_specifics.has_title() || |
| 159 GetTitle().empty() || // For the empty node case | 159 GetTitle().empty() || // For the empty node case |
| 160 !GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { | 160 !GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) { |
| 161 // It's possible we previously had to convert and set | 161 // It's possible we previously had to convert and set |
| 162 // |unencrypted_data_| but then wrote our own data, so we allow | 162 // |unencrypted_data_| but then wrote our own data, so we allow |
| 163 // |unencrypted_data_| to be non-empty. | 163 // |unencrypted_data_| to be non-empty. |
| 164 return specifics; | 164 return specifics; |
| 165 } else { | 165 } else { |
| 166 DCHECK_EQ(syncable::GetModelTypeFromSpecifics(unencrypted_data_), | 166 DCHECK_EQ(syncer::GetModelTypeFromSpecifics(unencrypted_data_), |
| 167 syncable::BOOKMARKS); | 167 syncer::BOOKMARKS); |
| 168 return unencrypted_data_; | 168 return unencrypted_data_; |
| 169 } | 169 } |
| 170 } else { | 170 } else { |
| 171 DCHECK_EQ(syncable::GetModelTypeFromSpecifics(unencrypted_data_), | 171 DCHECK_EQ(syncer::GetModelTypeFromSpecifics(unencrypted_data_), |
| 172 syncable::UNSPECIFIED); | 172 syncer::UNSPECIFIED); |
| 173 return specifics; | 173 return specifics; |
| 174 } | 174 } |
| 175 } | 175 } |
| 176 } | 176 } |
| 177 | 177 |
| 178 int64 BaseNode::GetParentId() const { | 178 int64 BaseNode::GetParentId() const { |
| 179 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), | 179 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), |
| 180 GetEntry()->Get(syncable::PARENT_ID)); | 180 GetEntry()->Get(syncable::PARENT_ID)); |
| 181 } | 181 } |
| 182 | 182 |
| 183 int64 BaseNode::GetId() const { | 183 int64 BaseNode::GetId() const { |
| 184 return GetEntry()->Get(syncable::META_HANDLE); | 184 return GetEntry()->Get(syncable::META_HANDLE); |
| 185 } | 185 } |
| 186 | 186 |
| 187 const base::Time& BaseNode::GetModificationTime() const { | 187 const base::Time& BaseNode::GetModificationTime() const { |
| 188 return GetEntry()->Get(syncable::MTIME); | 188 return GetEntry()->Get(syncable::MTIME); |
| 189 } | 189 } |
| 190 | 190 |
| 191 bool BaseNode::GetIsFolder() const { | 191 bool BaseNode::GetIsFolder() const { |
| 192 return GetEntry()->Get(syncable::IS_DIR); | 192 return GetEntry()->Get(syncable::IS_DIR); |
| 193 } | 193 } |
| 194 | 194 |
| 195 std::string BaseNode::GetTitle() const { | 195 std::string BaseNode::GetTitle() const { |
| 196 std::string result; | 196 std::string result; |
| 197 // TODO(zea): refactor bookmarks to not need this functionality. | 197 // TODO(zea): refactor bookmarks to not need this functionality. |
| 198 if (syncable::BOOKMARKS == GetModelType() && | 198 if (syncer::BOOKMARKS == GetModelType() && |
| 199 GetEntry()->Get(syncable::SPECIFICS).has_encrypted()) { | 199 GetEntry()->Get(syncable::SPECIFICS).has_encrypted()) { |
| 200 // Special case for legacy bookmarks dealing with encryption. | 200 // Special case for legacy bookmarks dealing with encryption. |
| 201 ServerNameToSyncAPIName(GetBookmarkSpecifics().title(), &result); | 201 ServerNameToSyncAPIName(GetBookmarkSpecifics().title(), &result); |
| 202 } else { | 202 } else { |
| 203 ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), | 203 ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), |
| 204 &result); | 204 &result); |
| 205 } | 205 } |
| 206 return result; | 206 return result; |
| 207 } | 207 } |
| 208 | 208 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 output->assign(reinterpret_cast<const unsigned char*>(favicon.data()), | 279 output->assign(reinterpret_cast<const unsigned char*>(favicon.data()), |
| 280 reinterpret_cast<const unsigned char*>(favicon.data() + | 280 reinterpret_cast<const unsigned char*>(favicon.data() + |
| 281 favicon.length())); | 281 favicon.length())); |
| 282 } | 282 } |
| 283 | 283 |
| 284 int64 BaseNode::GetExternalId() const { | 284 int64 BaseNode::GetExternalId() const { |
| 285 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID); | 285 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID); |
| 286 } | 286 } |
| 287 | 287 |
| 288 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const { | 288 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const { |
| 289 DCHECK_EQ(syncable::APPS, GetModelType()); | 289 DCHECK_EQ(syncer::APPS, GetModelType()); |
| 290 return GetEntitySpecifics().app(); | 290 return GetEntitySpecifics().app(); |
| 291 } | 291 } |
| 292 | 292 |
| 293 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const { | 293 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const { |
| 294 DCHECK_EQ(syncable::AUTOFILL, GetModelType()); | 294 DCHECK_EQ(syncer::AUTOFILL, GetModelType()); |
| 295 return GetEntitySpecifics().autofill(); | 295 return GetEntitySpecifics().autofill(); |
| 296 } | 296 } |
| 297 | 297 |
| 298 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const { | 298 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const { |
| 299 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); | 299 DCHECK_EQ(GetModelType(), syncer::AUTOFILL_PROFILE); |
| 300 return GetEntitySpecifics().autofill_profile(); | 300 return GetEntitySpecifics().autofill_profile(); |
| 301 } | 301 } |
| 302 | 302 |
| 303 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const { | 303 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const { |
| 304 DCHECK_EQ(syncable::BOOKMARKS, GetModelType()); | 304 DCHECK_EQ(syncer::BOOKMARKS, GetModelType()); |
| 305 return GetEntitySpecifics().bookmark(); | 305 return GetEntitySpecifics().bookmark(); |
| 306 } | 306 } |
| 307 | 307 |
| 308 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { | 308 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { |
| 309 DCHECK_EQ(syncable::NIGORI, GetModelType()); | 309 DCHECK_EQ(syncer::NIGORI, GetModelType()); |
| 310 return GetEntitySpecifics().nigori(); | 310 return GetEntitySpecifics().nigori(); |
| 311 } | 311 } |
| 312 | 312 |
| 313 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { | 313 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { |
| 314 DCHECK_EQ(syncable::PASSWORDS, GetModelType()); | 314 DCHECK_EQ(syncer::PASSWORDS, GetModelType()); |
| 315 return *password_data_; | 315 return *password_data_; |
| 316 } | 316 } |
| 317 | 317 |
| 318 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { | 318 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { |
| 319 DCHECK_EQ(syncable::THEMES, GetModelType()); | 319 DCHECK_EQ(syncer::THEMES, GetModelType()); |
| 320 return GetEntitySpecifics().theme(); | 320 return GetEntitySpecifics().theme(); |
| 321 } | 321 } |
| 322 | 322 |
| 323 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { | 323 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { |
| 324 DCHECK_EQ(syncable::TYPED_URLS, GetModelType()); | 324 DCHECK_EQ(syncer::TYPED_URLS, GetModelType()); |
| 325 return GetEntitySpecifics().typed_url(); | 325 return GetEntitySpecifics().typed_url(); |
| 326 } | 326 } |
| 327 | 327 |
| 328 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const { | 328 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const { |
| 329 DCHECK_EQ(syncable::EXTENSIONS, GetModelType()); | 329 DCHECK_EQ(syncer::EXTENSIONS, GetModelType()); |
| 330 return GetEntitySpecifics().extension(); | 330 return GetEntitySpecifics().extension(); |
| 331 } | 331 } |
| 332 | 332 |
| 333 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const { | 333 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const { |
| 334 DCHECK_EQ(syncable::SESSIONS, GetModelType()); | 334 DCHECK_EQ(syncer::SESSIONS, GetModelType()); |
| 335 return GetEntitySpecifics().session(); | 335 return GetEntitySpecifics().session(); |
| 336 } | 336 } |
| 337 | 337 |
| 338 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const { | 338 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const { |
| 339 return GetUnencryptedSpecifics(GetEntry()); | 339 return GetUnencryptedSpecifics(GetEntry()); |
| 340 } | 340 } |
| 341 | 341 |
| 342 syncable::ModelType BaseNode::GetModelType() const { | 342 syncer::ModelType BaseNode::GetModelType() const { |
| 343 return GetEntry()->GetModelType(); | 343 return GetEntry()->GetModelType(); |
| 344 } | 344 } |
| 345 | 345 |
| 346 void BaseNode::SetUnencryptedSpecifics( | 346 void BaseNode::SetUnencryptedSpecifics( |
| 347 const sync_pb::EntitySpecifics& specifics) { | 347 const sync_pb::EntitySpecifics& specifics) { |
| 348 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(specifics); | 348 syncer::ModelType type = syncer::GetModelTypeFromSpecifics(specifics); |
| 349 DCHECK_NE(syncable::UNSPECIFIED, type); | 349 DCHECK_NE(syncer::UNSPECIFIED, type); |
| 350 if (GetModelType() != syncable::UNSPECIFIED) { | 350 if (GetModelType() != syncer::UNSPECIFIED) { |
| 351 DCHECK_EQ(GetModelType(), type); | 351 DCHECK_EQ(GetModelType(), type); |
| 352 } | 352 } |
| 353 unencrypted_data_.CopyFrom(specifics); | 353 unencrypted_data_.CopyFrom(specifics); |
| 354 } | 354 } |
| 355 | 355 |
| 356 } // namespace syncer | 356 } // namespace syncer |
| OLD | NEW |