1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SYNC_INTERNAL_API_PUBLIC_BASE_NODE_H_
#define SYNC_INTERNAL_API_PUBLIC_BASE_NODE_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/protocol/sync.pb.h"
// Forward declarations of internal class types so that sync API objects
// may have opaque pointers to these types.
namespace base {
class DictionaryValue;
}
namespace sync_pb {
class AppSpecifics;
class AutofillSpecifics;
class AutofillProfileSpecifics;
class BookmarkSpecifics;
class EntitySpecifics;
class ExtensionSpecifics;
class SessionSpecifics;
class NigoriSpecifics;
class PreferenceSpecifics;
class PasswordSpecificsData;
class ThemeSpecifics;
class TypedUrlSpecifics;
}
namespace syncer {
class BaseTransaction;
namespace syncable {
class BaseTransaction;
class Entry;
}
// A valid BaseNode will never have an ID of zero.
static const int64 kInvalidId = 0;
// BaseNode wraps syncable::Entry, and corresponds to a single object's state.
// This, like syncable::Entry, is intended for use on the stack. A valid
// transaction is necessary to create a BaseNode or any of its children.
// Unlike syncable::Entry, a sync API BaseNode is identified primarily by its
// int64 metahandle, which we call an ID here.
class BaseNode {
public:
// Enumerates the possible outcomes of trying to initialize a sync node.
enum InitByLookupResult {
INIT_OK,
// Could not find an entry matching the lookup criteria.
INIT_FAILED_ENTRY_NOT_GOOD,
// Found an entry, but it is already deleted.
INIT_FAILED_ENTRY_IS_DEL,
// Found an entry, but was unable to decrypt.
INIT_FAILED_DECRYPT_IF_NECESSARY,
// A precondition was not met for calling init, such as legal input
// arguments.
INIT_FAILED_PRECONDITION,
};
// All subclasses of BaseNode must provide a way to initialize themselves by
// doing an ID lookup. Returns false on failure. An invalid or deleted
// ID will result in failure.
virtual InitByLookupResult InitByIdLookup(int64 id) = 0;
// All subclasses of BaseNode must also provide a way to initialize themselves
// by doing a client tag lookup. Returns false on failure. A deleted node
// will return FALSE.
virtual InitByLookupResult InitByClientTagLookup(
ModelType model_type,
const std::string& tag) = 0;
// Each object is identified by a 64-bit id (internally, the syncable
// metahandle). These ids are strictly local handles. They will persist
// on this client, but the same object on a different client may have a
// different ID value.
virtual int64 GetId() const;
// Returns the modification time of the object.
base::Time GetModificationTime() const;
// Nodes are hierarchically arranged into a single-rooted tree.
// InitByRootLookup on ReadNode allows access to the root. GetParentId is
// how you find a node's parent.
int64 GetParentId() const;
// Nodes are either folders or not. This corresponds to the IS_DIR property
// of syncable::Entry.
bool GetIsFolder() const;
// Returns the title of the object.
// Uniqueness of the title is not enforced on siblings -- it is not an error
// for two children to share a title.
std::string GetTitle() const;
// Returns the model type of this object. The model type is set at node
// creation time and is expected never to change.
ModelType GetModelType() const;
// Getter specific to the BOOKMARK datatype. Returns protobuf
// data. Can only be called if GetModelType() == BOOKMARK.
const sync_pb::BookmarkSpecifics& GetBookmarkSpecifics() const;
// Legacy, bookmark-specific getter that wraps GetBookmarkSpecifics() above.
// Returns the URL of a bookmark object.
// TODO(ncarter): Remove this datatype-specific accessor.
GURL GetURL() const;
// Legacy, bookmark-specific getter that wraps GetBookmarkSpecifics() above.
// Fill in a vector with the byte data of this node's favicon. Assumes
// that the node is a bookmark.
// Favicons are expected to be PNG images, and though no verification is
// done on the syncapi client of this, the server may reject favicon updates
// that are invalid for whatever reason.
// TODO(ncarter): Remove this datatype-specific accessor.
void GetFaviconBytes(std::vector<unsigned char>* output) const;
// Getter specific to the APPS datatype. Returns protobuf
// data. Can only be called if GetModelType() == APPS.
const sync_pb::AppSpecifics& GetAppSpecifics() const;
// Getter specific to the AUTOFILL datatype. Returns protobuf
// data. Can only be called if GetModelType() == AUTOFILL.
const sync_pb::AutofillSpecifics& GetAutofillSpecifics() const;
virtual const sync_pb::AutofillProfileSpecifics&
GetAutofillProfileSpecifics() const;
// Getter specific to the NIGORI datatype. Returns protobuf
// data. Can only be called if GetModelType() == NIGORI.
const sync_pb::NigoriSpecifics& GetNigoriSpecifics() const;
// Getter specific to the PASSWORD datatype. Returns protobuf
// data. Can only be called if GetModelType() == PASSWORD.
const sync_pb::PasswordSpecificsData& GetPasswordSpecifics() const;
// Getter specific to the PREFERENCE datatype. Returns protobuf
// data. Can only be called if GetModelType() == PREFERENCE.
const sync_pb::PreferenceSpecifics& GetPreferenceSpecifics() const;
// Getter specific to the THEME datatype. Returns protobuf
// data. Can only be called if GetModelType() == THEME.
const sync_pb::ThemeSpecifics& GetThemeSpecifics() const;
// Getter specific to the TYPED_URLS datatype. Returns protobuf
// data. Can only be called if GetModelType() == TYPED_URLS.
const sync_pb::TypedUrlSpecifics& GetTypedUrlSpecifics() const;
// Getter specific to the EXTENSIONS datatype. Returns protobuf
// data. Can only be called if GetModelType() == EXTENSIONS.
const sync_pb::ExtensionSpecifics& GetExtensionSpecifics() const;
// Getter specific to the SESSIONS datatype. Returns protobuf
// data. Can only be called if GetModelType() == SESSIONS.
const sync_pb::SessionSpecifics& GetSessionSpecifics() const;
const sync_pb::EntitySpecifics& GetEntitySpecifics() const;
// Returns the local external ID associated with the node.
int64 GetExternalId() const;
// Returns true iff this node has children.
bool HasChildren() const;
// Return the ID of the node immediately before this in the sibling order.
// For the first node in the ordering, return 0.
int64 GetPredecessorId() const;
// Return the ID of the node immediately after this in the sibling order.
// For the last node in the ordering, return 0.
int64 GetSuccessorId() const;
// Return the ID of the first child of this node. If this node has no
// children, return 0.
int64 GetFirstChildId() const;
// These virtual accessors provide access to data members of derived classes.
virtual const syncable::Entry* GetEntry() const = 0;
virtual const BaseTransaction* GetTransaction() const = 0;
// Dumps a summary of node info into a DictionaryValue and returns it.
// Transfers ownership of the DictionaryValue to the caller.
base::DictionaryValue* GetSummaryAsValue() const;
// Dumps all node details into a DictionaryValue and returns it.
// Transfers ownership of the DictionaryValue to the caller.
base::DictionaryValue* GetDetailsAsValue() const;
protected:
BaseNode();
virtual ~BaseNode();
// The server has a size limit on client tags, so we generate a fixed length
// hash locally. This also ensures that ModelTypes have unique namespaces.
static std::string GenerateSyncableHash(
ModelType model_type,
const std::string& client_tag);
// Determines whether part of the entry is encrypted, and if so attempts to
// decrypt it. Unless decryption is necessary and fails, this will always
// return |true|. If the contents are encrypted, the decrypted data will be
// stored in |unencrypted_data_|.
// This method is invoked once when the BaseNode is initialized.
bool DecryptIfNecessary();
// Returns the unencrypted specifics associated with |entry|. If |entry| was
// not encrypted, it directly returns |entry|'s EntitySpecifics. Otherwise,
// returns |unencrypted_data_|.
const sync_pb::EntitySpecifics& GetUnencryptedSpecifics(
const syncable::Entry* entry) const;
// Copy |specifics| into |unencrypted_data_|.
void SetUnencryptedSpecifics(const sync_pb::EntitySpecifics& specifics);
private:
// Have to friend the test class as well to allow member functions to access
// protected/private BaseNode methods.
friend class SyncManagerTest;
FRIEND_TEST_ALL_PREFIXES(SyncApiTest, GenerateSyncableHash);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, UpdateEntryWithEncryption);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest,
UpdatePasswordSetEntitySpecificsNoChange);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, UpdatePasswordSetPasswordSpecifics);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, UpdatePasswordNewPassphrase);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, UpdatePasswordReencryptEverything);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, SetBookmarkTitle);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, SetBookmarkTitleWithEncryption);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, SetNonBookmarkTitle);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, SetNonBookmarkTitleWithEncryption);
FRIEND_TEST_ALL_PREFIXES(SyncManagerTest, SetPreviouslyEncryptedSpecifics);
void* operator new(size_t size); // Node is meant for stack use only.
// A holder for the unencrypted data stored in an encrypted node.
sync_pb::EntitySpecifics unencrypted_data_;
// Same as |unencrypted_data_|, but for legacy password encryption.
scoped_ptr<sync_pb::PasswordSpecificsData> password_data_;
DISALLOW_COPY_AND_ASSIGN(BaseNode);
};
} // namespace syncer
#endif // SYNC_INTERNAL_API_PUBLIC_BASE_NODE_H_
|