| 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/write_node.h" | 5 #include "components/sync/core/write_node.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "sync/internal_api/public/base_transaction.h" | 12 #include "components/sync/base/cryptographer.h" |
| 13 #include "sync/internal_api/public/write_transaction.h" | 13 #include "components/sync/core/base_transaction.h" |
| 14 #include "sync/internal_api/syncapi_internal.h" | 14 #include "components/sync/core/write_transaction.h" |
| 15 #include "sync/protocol/bookmark_specifics.pb.h" | 15 #include "components/sync/core_impl/syncapi_internal.h" |
| 16 #include "sync/protocol/typed_url_specifics.pb.h" | 16 #include "components/sync/protocol/bookmark_specifics.pb.h" |
| 17 #include "sync/syncable/mutable_entry.h" | 17 #include "components/sync/protocol/typed_url_specifics.pb.h" |
| 18 #include "sync/syncable/nigori_util.h" | 18 #include "components/sync/syncable/mutable_entry.h" |
| 19 #include "sync/syncable/syncable_util.h" | 19 #include "components/sync/syncable/nigori_util.h" |
| 20 #include "sync/util/cryptographer.h" | 20 #include "components/sync/syncable/syncable_util.h" |
| 21 | 21 |
| 22 using std::string; | 22 using std::string; |
| 23 using std::vector; | 23 using std::vector; |
| 24 | 24 |
| 25 namespace syncer { | 25 namespace syncer { |
| 26 | 26 |
| 27 using syncable::kEncryptedString; | 27 using syncable::kEncryptedString; |
| 28 using syncable::SPECIFICS; | 28 using syncable::SPECIFICS; |
| 29 | 29 |
| 30 static const char kDefaultNameForNewNodes[] = " "; | 30 static const char kDefaultNameForNewNodes[] = " "; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 52 std::string new_legal_title; | 52 std::string new_legal_title; |
| 53 if (type != BOOKMARKS && needs_encryption) { | 53 if (type != BOOKMARKS && needs_encryption) { |
| 54 new_legal_title = kEncryptedString; | 54 new_legal_title = kEncryptedString; |
| 55 } else { | 55 } else { |
| 56 DCHECK(base::IsStringUTF8(title)); | 56 DCHECK(base::IsStringUTF8(title)); |
| 57 SyncAPINameToServerName(title, &new_legal_title); | 57 SyncAPINameToServerName(title, &new_legal_title); |
| 58 base::TruncateUTF8ToByteSize(new_legal_title, 255, &new_legal_title); | 58 base::TruncateUTF8ToByteSize(new_legal_title, 255, &new_legal_title); |
| 59 } | 59 } |
| 60 | 60 |
| 61 std::string current_legal_title; | 61 std::string current_legal_title; |
| 62 if (BOOKMARKS == type && | 62 if (BOOKMARKS == type && entry_->GetSpecifics().has_encrypted()) { |
| 63 entry_->GetSpecifics().has_encrypted()) { | |
| 64 // Encrypted bookmarks only have their title in the unencrypted specifics. | 63 // Encrypted bookmarks only have their title in the unencrypted specifics. |
| 65 current_legal_title = GetBookmarkSpecifics().title(); | 64 current_legal_title = GetBookmarkSpecifics().title(); |
| 66 } else { | 65 } else { |
| 67 // Non-bookmarks and legacy bookmarks (those with no title in their | 66 // Non-bookmarks and legacy bookmarks (those with no title in their |
| 68 // specifics) store their title in NON_UNIQUE_NAME. Non-legacy bookmarks | 67 // specifics) store their title in NON_UNIQUE_NAME. Non-legacy bookmarks |
| 69 // store their title in specifics as well as NON_UNIQUE_NAME. | 68 // store their title in specifics as well as NON_UNIQUE_NAME. |
| 70 current_legal_title = entry_->GetNonUniqueName(); | 69 current_legal_title = entry_->GetNonUniqueName(); |
| 71 } | 70 } |
| 72 | 71 |
| 73 bool title_matches = (current_legal_title == new_legal_title); | 72 bool title_matches = (current_legal_title == new_legal_title); |
| 74 bool encrypted_without_overwriting_name = (needs_encryption && | 73 bool encrypted_without_overwriting_name = |
| 75 entry_->GetNonUniqueName() != kEncryptedString); | 74 (needs_encryption && entry_->GetNonUniqueName() != kEncryptedString); |
| 76 | 75 |
| 77 // For bookmarks, we also set the title field in the specifics. | 76 // For bookmarks, we also set the title field in the specifics. |
| 78 // TODO(zea): refactor bookmarks to not need this functionality. | 77 // TODO(zea): refactor bookmarks to not need this functionality. |
| 79 sync_pb::EntitySpecifics specifics = GetEntitySpecifics(); | 78 sync_pb::EntitySpecifics specifics = GetEntitySpecifics(); |
| 80 if (GetModelType() == BOOKMARKS && | 79 if (GetModelType() == BOOKMARKS && |
| 81 specifics.bookmark().title() != new_legal_title) { | 80 specifics.bookmark().title() != new_legal_title) { |
| 82 specifics.mutable_bookmark()->set_title(new_legal_title); | 81 specifics.mutable_bookmark()->set_title(new_legal_title); |
| 83 SetEntitySpecifics(specifics); // Does it's own encryption checking. | 82 SetEntitySpecifics(specifics); // Does it's own encryption checking. |
| 84 title_matches = false; | 83 title_matches = false; |
| 85 } | 84 } |
| 86 | 85 |
| 87 // If the title matches and the NON_UNIQUE_NAME is properly overwritten as | 86 // If the title matches and the NON_UNIQUE_NAME is properly overwritten as |
| 88 // necessary, nothing needs to change. | 87 // necessary, nothing needs to change. |
| 89 if (title_matches && !encrypted_without_overwriting_name) { | 88 if (title_matches && !encrypted_without_overwriting_name) { |
| 90 DVLOG(2) << "Title matches, dropping change."; | 89 DVLOG(2) << "Title matches, dropping change."; |
| 91 return; | 90 return; |
| 92 } | 91 } |
| 93 | 92 |
| 94 // For bookmarks, this has to happen after we set the title in the specifics, | 93 // For bookmarks, this has to happen after we set the title in the specifics, |
| 95 // because the presence of a title in the NON_UNIQUE_NAME is what controls | 94 // because the presence of a title in the NON_UNIQUE_NAME is what controls |
| 96 // the logic deciding whether this is an empty node or a legacy bookmark. | 95 // the logic deciding whether this is an empty node or a legacy bookmark. |
| 97 // See BaseNode::GetUnencryptedSpecific(..). | 96 // See BaseNode::GetUnencryptedSpecific(..). |
| 98 if (needs_encryption) | 97 if (needs_encryption) |
| 99 entry_->PutNonUniqueName(kEncryptedString); | 98 entry_->PutNonUniqueName(kEncryptedString); |
| 100 else | 99 else |
| 101 entry_->PutNonUniqueName(new_legal_title); | 100 entry_->PutNonUniqueName(new_legal_title); |
| 102 | 101 |
| 103 DVLOG(1) << "Overwriting title of type " | 102 DVLOG(1) << "Overwriting title of type " << ModelTypeToString(type) |
| 104 << ModelTypeToString(type) | |
| 105 << " and marking for syncing."; | 103 << " and marking for syncing."; |
| 106 MarkForSyncing(); | 104 MarkForSyncing(); |
| 107 } | 105 } |
| 108 | 106 |
| 109 void WriteNode::SetBookmarkSpecifics( | 107 void WriteNode::SetBookmarkSpecifics( |
| 110 const sync_pb::BookmarkSpecifics& new_value) { | 108 const sync_pb::BookmarkSpecifics& new_value) { |
| 111 sync_pb::EntitySpecifics entity_specifics; | 109 sync_pb::EntitySpecifics entity_specifics; |
| 112 entity_specifics.mutable_bookmark()->CopyFrom(new_value); | 110 entity_specifics.mutable_bookmark()->CopyFrom(new_value); |
| 113 SetEntitySpecifics(entity_specifics); | 111 SetEntitySpecifics(entity_specifics); |
| 114 } | 112 } |
| 115 | 113 |
| 116 void WriteNode::SetNigoriSpecifics( | 114 void WriteNode::SetNigoriSpecifics(const sync_pb::NigoriSpecifics& new_value) { |
| 117 const sync_pb::NigoriSpecifics& new_value) { | |
| 118 sync_pb::EntitySpecifics entity_specifics; | 115 sync_pb::EntitySpecifics entity_specifics; |
| 119 entity_specifics.mutable_nigori()->CopyFrom(new_value); | 116 entity_specifics.mutable_nigori()->CopyFrom(new_value); |
| 120 SetEntitySpecifics(entity_specifics); | 117 SetEntitySpecifics(entity_specifics); |
| 121 } | 118 } |
| 122 | 119 |
| 123 void WriteNode::SetPasswordSpecifics( | 120 void WriteNode::SetPasswordSpecifics( |
| 124 const sync_pb::PasswordSpecificsData& data) { | 121 const sync_pb::PasswordSpecificsData& data) { |
| 125 DCHECK_EQ(GetModelType(), PASSWORDS); | 122 DCHECK_EQ(GetModelType(), PASSWORDS); |
| 126 | 123 |
| 127 Cryptographer* cryptographer = GetTransaction()->GetCryptographer(); | 124 Cryptographer* cryptographer = GetTransaction()->GetCryptographer(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 142 // This will only update password_specifics if the underlying unencrypted blob | 139 // This will only update password_specifics if the underlying unencrypted blob |
| 143 // was different from |data| or was not encrypted with the proper passphrase. | 140 // was different from |data| or was not encrypted with the proper passphrase. |
| 144 if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) { | 141 if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) { |
| 145 LOG(ERROR) << "Failed to encrypt password, possibly due to sync node " | 142 LOG(ERROR) << "Failed to encrypt password, possibly due to sync node " |
| 146 << "corruption"; | 143 << "corruption"; |
| 147 return; | 144 return; |
| 148 } | 145 } |
| 149 SetEntitySpecifics(entity_specifics); | 146 SetEntitySpecifics(entity_specifics); |
| 150 } | 147 } |
| 151 | 148 |
| 152 void WriteNode::SetEntitySpecifics( | 149 void WriteNode::SetEntitySpecifics(const sync_pb::EntitySpecifics& new_value) { |
| 153 const sync_pb::EntitySpecifics& new_value) { | 150 ModelType new_specifics_type = GetModelTypeFromSpecifics(new_value); |
| 154 ModelType new_specifics_type = | |
| 155 GetModelTypeFromSpecifics(new_value); | |
| 156 CHECK(!new_value.password().has_client_only_encrypted_data()); | 151 CHECK(!new_value.password().has_client_only_encrypted_data()); |
| 157 DCHECK_NE(new_specifics_type, UNSPECIFIED); | 152 DCHECK_NE(new_specifics_type, UNSPECIFIED); |
| 158 DVLOG(1) << "Writing entity specifics of type " | 153 DVLOG(1) << "Writing entity specifics of type " |
| 159 << ModelTypeToString(new_specifics_type); | 154 << ModelTypeToString(new_specifics_type); |
| 160 DCHECK_EQ(new_specifics_type, GetModelType()); | 155 DCHECK_EQ(new_specifics_type, GetModelType()); |
| 161 | 156 |
| 162 // Preserve unknown fields. | 157 // Preserve unknown fields. |
| 163 const sync_pb::EntitySpecifics& old_specifics = entry_->GetSpecifics(); | 158 const sync_pb::EntitySpecifics& old_specifics = entry_->GetSpecifics(); |
| 164 sync_pb::EntitySpecifics new_specifics; | 159 sync_pb::EntitySpecifics new_specifics; |
| 165 new_specifics.CopyFrom(new_value); | 160 new_specifics.CopyFrom(new_value); |
| 166 new_specifics.mutable_unknown_fields() | 161 new_specifics.mutable_unknown_fields()->append( |
| 167 ->append(old_specifics.unknown_fields()); | 162 old_specifics.unknown_fields()); |
| 168 | 163 |
| 169 // Will update the entry if encryption was necessary. | 164 // Will update the entry if encryption was necessary. |
| 170 if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(), | 165 if (!UpdateEntryWithEncryption(GetTransaction()->GetWrappedTrans(), |
| 171 new_specifics, | 166 new_specifics, entry_)) { |
| 172 entry_)) { | |
| 173 return; | 167 return; |
| 174 } | 168 } |
| 175 if (entry_->GetSpecifics().has_encrypted()) { | 169 if (entry_->GetSpecifics().has_encrypted()) { |
| 176 // EncryptIfNecessary already updated the entry for us and marked for | 170 // EncryptIfNecessary already updated the entry for us and marked for |
| 177 // syncing if it was needed. Now we just make a copy of the unencrypted | 171 // syncing if it was needed. Now we just make a copy of the unencrypted |
| 178 // specifics so that if this node is updated, we do not have to decrypt the | 172 // specifics so that if this node is updated, we do not have to decrypt the |
| 179 // old data. Note that this only modifies the node's local data, not the | 173 // old data. Note that this only modifies the node's local data, not the |
| 180 // entry itself. | 174 // entry itself. |
| 181 SetUnencryptedSpecifics(new_value); | 175 SetUnencryptedSpecifics(new_value); |
| 182 } | 176 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 return false; | 264 return false; |
| 271 } | 265 } |
| 272 | 266 |
| 273 syncable::Id parent_id = parent.GetSyncId(); | 267 syncable::Id parent_id = parent.GetSyncId(); |
| 274 DCHECK(!parent_id.IsNull()); | 268 DCHECK(!parent_id.IsNull()); |
| 275 | 269 |
| 276 // Start out with a dummy name. We expect | 270 // Start out with a dummy name. We expect |
| 277 // the caller to set a meaningful name after creation. | 271 // the caller to set a meaningful name after creation. |
| 278 string dummy(kDefaultNameForNewNodes); | 272 string dummy(kDefaultNameForNewNodes); |
| 279 | 273 |
| 280 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), | 274 entry_ = |
| 281 syncable::CREATE, BOOKMARKS, | 275 new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), |
| 282 parent_id, dummy); | 276 syncable::CREATE, BOOKMARKS, parent_id, dummy); |
| 283 | 277 |
| 284 if (!entry_->good()) | 278 if (!entry_->good()) |
| 285 return false; | 279 return false; |
| 286 | 280 |
| 287 // Entries are untitled folders by default. | 281 // Entries are untitled folders by default. |
| 288 entry_->PutIsDir(true); | 282 entry_->PutIsDir(true); |
| 289 | 283 |
| 290 if (!PutPredecessor(predecessor)) { | 284 if (!PutPredecessor(predecessor)) { |
| 291 return false; | 285 return false; |
| 292 } | 286 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 } // Else just reuse the existing entry. | 371 } // Else just reuse the existing entry. |
| 378 entry_ = existing_entry.release(); | 372 entry_ = existing_entry.release(); |
| 379 // If entry is undeleted, its specifics are reset to default, unencrypted | 373 // If entry is undeleted, its specifics are reset to default, unencrypted |
| 380 // value, and therefore no decryption is necessary. Moreover trying to | 374 // value, and therefore no decryption is necessary. Moreover trying to |
| 381 // decrypt the password entry will fail because passwords are expected to be | 375 // decrypt the password entry will fail because passwords are expected to be |
| 382 // encrypted. | 376 // encrypted. |
| 383 if (!entry_undeleted && !DecryptIfNecessary()) | 377 if (!entry_undeleted && !DecryptIfNecessary()) |
| 384 return INIT_FAILED_DECRYPT_EXISTING_ENTRY; | 378 return INIT_FAILED_DECRYPT_EXISTING_ENTRY; |
| 385 } else { | 379 } else { |
| 386 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), | 380 entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(), |
| 387 syncable::CREATE, | 381 syncable::CREATE, model_type, parent_id, |
| 388 model_type, parent_id, dummy); | 382 dummy); |
| 389 } | 383 } |
| 390 | 384 |
| 391 if (!entry_->good()) | 385 if (!entry_->good()) |
| 392 return INIT_FAILED_COULD_NOT_CREATE_ENTRY; | 386 return INIT_FAILED_COULD_NOT_CREATE_ENTRY; |
| 393 | 387 |
| 394 // Has no impact if the client tag is already set. | 388 // Has no impact if the client tag is already set. |
| 395 entry_->PutUniqueClientTag(hash); | 389 entry_->PutUniqueClientTag(hash); |
| 396 | 390 |
| 397 // We don't support directory and tag combinations. | 391 // We don't support directory and tag combinations. |
| 398 entry_->PutIsDir(false); | 392 entry_->PutIsDir(false); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 syncable::Id predecessor_id = | 469 syncable::Id predecessor_id = |
| 476 predecessor ? predecessor->GetSyncId() : syncable::Id(); | 470 predecessor ? predecessor->GetSyncId() : syncable::Id(); |
| 477 return entry_->PutPredecessor(predecessor_id); | 471 return entry_->PutPredecessor(predecessor_id); |
| 478 } | 472 } |
| 479 | 473 |
| 480 void WriteNode::MarkForSyncing() { | 474 void WriteNode::MarkForSyncing() { |
| 481 syncable::MarkForSyncing(entry_); | 475 syncable::MarkForSyncing(entry_); |
| 482 } | 476 } |
| 483 | 477 |
| 484 } // namespace syncer | 478 } // namespace syncer |
| OLD | NEW |