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 """An implementation of the server side of the Chromium sync protocol. | 5 """An implementation of the server side of the Chromium sync protocol. |
6 | 6 |
7 The details of the protocol are described mostly by comments in the protocol | 7 The details of the protocol are described mostly by comments in the protocol |
8 buffer definition at chrome/browser/sync/protocol/sync.proto. | 8 buffer definition at chrome/browser/sync/protocol/sync.proto. |
9 """ | 9 """ |
10 | 10 |
11 import cgi | 11 import cgi |
12 import copy | 12 import copy |
13 import operator | 13 import operator |
14 import pickle | 14 import pickle |
15 import random | 15 import random |
16 import string | |
16 import sys | 17 import sys |
17 import threading | 18 import threading |
18 import time | 19 import time |
19 import urlparse | 20 import urlparse |
20 | 21 |
21 import app_notification_specifics_pb2 | 22 import app_notification_specifics_pb2 |
22 import app_setting_specifics_pb2 | 23 import app_setting_specifics_pb2 |
23 import app_specifics_pb2 | 24 import app_specifics_pb2 |
24 import autofill_specifics_pb2 | 25 import autofill_specifics_pb2 |
25 import bookmark_specifics_pb2 | 26 import bookmark_specifics_pb2 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
90 TYPED_URL: SYNC_TYPE_FIELDS['typed_url'], | 91 TYPED_URL: SYNC_TYPE_FIELDS['typed_url'], |
91 } | 92 } |
92 | 93 |
93 # The parent ID used to indicate a top-level node. | 94 # The parent ID used to indicate a top-level node. |
94 ROOT_ID = '0' | 95 ROOT_ID = '0' |
95 | 96 |
96 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday | 97 # Unix time epoch in struct_time format. The tuple corresponds to UTC Wednesday |
97 # Jan 1 1970, 00:00:00, non-dst. | 98 # Jan 1 1970, 00:00:00, non-dst. |
98 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) | 99 UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0) |
99 | 100 |
101 # The number of characters in the server-generated encryption key. | |
102 KEYSTORE_KEY_LENGTH = 16 | |
103 | |
100 class Error(Exception): | 104 class Error(Exception): |
101 """Error class for this module.""" | 105 """Error class for this module.""" |
102 | 106 |
103 | 107 |
104 class ProtobufDataTypeFieldNotUnique(Error): | 108 class ProtobufDataTypeFieldNotUnique(Error): |
105 """An entry should not have more than one data type present.""" | 109 """An entry should not have more than one data type present.""" |
106 | 110 |
107 | 111 |
108 class DataTypeIdNotRecognized(Error): | 112 class DataTypeIdNotRecognized(Error): |
109 """The requested data type is not recognized.""" | 113 """The requested data type is not recognized.""" |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 self._entries = {} | 465 self._entries = {} |
462 | 466 |
463 self.ResetStoreBirthday() | 467 self.ResetStoreBirthday() |
464 | 468 |
465 self.migration_history = MigrationHistory() | 469 self.migration_history = MigrationHistory() |
466 | 470 |
467 self.induced_error = sync_pb2.ClientToServerResponse.Error() | 471 self.induced_error = sync_pb2.ClientToServerResponse.Error() |
468 self.induced_error_frequency = 0 | 472 self.induced_error_frequency = 0 |
469 self.sync_count_before_errors = 0 | 473 self.sync_count_before_errors = 0 |
470 | 474 |
475 self._key = ''.join(random.choice( | |
476 string.ascii_uppercase + string.digits) for x in range( | |
akalin
2012/07/31 00:56:56
xrange
akalin
2012/07/31 00:56:56
can you indent so that "for x in range(...)" isn't
Nicolas Zea
2012/07/31 17:27:07
Done.
Nicolas Zea
2012/07/31 17:27:07
Done.
| |
477 KEYSTORE_KEY_LENGTH)) | |
478 | |
471 def _SaveEntry(self, entry): | 479 def _SaveEntry(self, entry): |
472 """Insert or update an entry in the change log, and give it a new version. | 480 """Insert or update an entry in the change log, and give it a new version. |
473 | 481 |
474 The ID fields of this entry are assumed to be valid server IDs. This | 482 The ID fields of this entry are assumed to be valid server IDs. This |
475 entry will be updated with a new version number and sync_timestamp. | 483 entry will be updated with a new version number and sync_timestamp. |
476 | 484 |
477 Args: | 485 Args: |
478 entry: The entry to be added or updated. | 486 entry: The entry to be added or updated. |
479 """ | 487 """ |
480 self._version += 1 | 488 self._version += 1 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
657 | 665 |
658 # Restrict batch to requested types. Tombstones are untyped | 666 # Restrict batch to requested types. Tombstones are untyped |
659 # and will always get included. | 667 # and will always get included. |
660 filtered = [copy.deepcopy(item) for item in batch | 668 filtered = [copy.deepcopy(item) for item in batch |
661 if item.deleted or sieve.ClientWantsItem(item)] | 669 if item.deleted or sieve.ClientWantsItem(item)] |
662 | 670 |
663 # The new client timestamp is the timestamp of the last item in the | 671 # The new client timestamp is the timestamp of the last item in the |
664 # batch, even if that item was filtered out. | 672 # batch, even if that item was filtered out. |
665 return (batch[-1].version, filtered, len(new_changes) - len(batch)) | 673 return (batch[-1].version, filtered, len(new_changes) - len(batch)) |
666 | 674 |
675 def GetKey(self): | |
676 """Returns the encryption key for this account.""" | |
677 print "Returning encryption key: %s" % self._key | |
678 return self._key | |
679 | |
667 def _CopyOverImmutableFields(self, entry): | 680 def _CopyOverImmutableFields(self, entry): |
668 """Preserve immutable fields by copying pre-commit state. | 681 """Preserve immutable fields by copying pre-commit state. |
669 | 682 |
670 Args: | 683 Args: |
671 entry: A sync entity from the client. | 684 entry: A sync entity from the client. |
672 """ | 685 """ |
673 if entry.id_string in self._entries: | 686 if entry.id_string in self._entries: |
674 if self._entries[entry.id_string].HasField( | 687 if self._entries[entry.id_string].HasField( |
675 'server_defined_unique_tag'): | 688 'server_defined_unique_tag'): |
676 entry.server_defined_unique_tag = ( | 689 entry.server_defined_unique_tag = ( |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1036 response = 'Could not interpret datatype name' | 1049 response = 'Could not interpret datatype name' |
1037 code = 400 | 1050 code = 400 |
1038 finally: | 1051 finally: |
1039 self.account_lock.release() | 1052 self.account_lock.release() |
1040 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % | 1053 return (code, '<html><title>Migration: %d</title><H1>%d %s</H1></html>' % |
1041 (code, code, response)) | 1054 (code, code, response)) |
1042 | 1055 |
1043 def HandleSetInducedError(self, path): | 1056 def HandleSetInducedError(self, path): |
1044 query = urlparse.urlparse(path)[4] | 1057 query = urlparse.urlparse(path)[4] |
1045 self.account_lock.acquire() | 1058 self.account_lock.acquire() |
1046 code = 200; | 1059 code = 200 |
1047 response = 'Success' | 1060 response = 'Success' |
1048 error = sync_pb2.ClientToServerResponse.Error() | 1061 error = sync_pb2.ClientToServerResponse.Error() |
1049 try: | 1062 try: |
1050 error_type = urlparse.parse_qs(query)['error'] | 1063 error_type = urlparse.parse_qs(query)['error'] |
1051 action = urlparse.parse_qs(query)['action'] | 1064 action = urlparse.parse_qs(query)['action'] |
1052 error.error_type = int(error_type[0]) | 1065 error.error_type = int(error_type[0]) |
1053 error.action = int(action[0]) | 1066 error.action = int(action[0]) |
1054 try: | 1067 try: |
1055 error.url = (urlparse.parse_qs(query)['url'])[0] | 1068 error.url = (urlparse.parse_qs(query)['url'])[0] |
1056 except KeyError: | 1069 except KeyError: |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1125 | 1138 |
1126 try: | 1139 try: |
1127 request = sync_pb2.ClientToServerMessage() | 1140 request = sync_pb2.ClientToServerMessage() |
1128 request.MergeFromString(raw_request) | 1141 request.MergeFromString(raw_request) |
1129 contents = request.message_contents | 1142 contents = request.message_contents |
1130 | 1143 |
1131 response = sync_pb2.ClientToServerResponse() | 1144 response = sync_pb2.ClientToServerResponse() |
1132 response.error_code = sync_enums_pb2.SyncEnums.SUCCESS | 1145 response.error_code = sync_enums_pb2.SyncEnums.SUCCESS |
1133 self.CheckStoreBirthday(request) | 1146 self.CheckStoreBirthday(request) |
1134 response.store_birthday = self.account.store_birthday | 1147 response.store_birthday = self.account.store_birthday |
1135 self.CheckTransientError(); | 1148 self.CheckTransientError() |
1136 self.CheckSendError(); | 1149 self.CheckSendError() |
1137 | 1150 |
1138 print_context('->') | 1151 print_context('->') |
1139 | 1152 |
1140 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: | 1153 if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE: |
1141 print 'Authenticate' | 1154 print 'Authenticate' |
1142 # We accept any authentication token, and support only one account. | 1155 # We accept any authentication token, and support only one account. |
1143 # TODO(nick): Mock out the GAIA authentication as well; hook up here. | 1156 # TODO(nick): Mock out the GAIA authentication as well; hook up here. |
1144 response.authenticate.user.email = 'syncjuser@chromium' | 1157 response.authenticate.user.email = 'syncjuser@chromium' |
1145 response.authenticate.user.display_name = 'Sync J User' | 1158 response.authenticate.user.display_name = 'Sync J User' |
1146 elif contents == sync_pb2.ClientToServerMessage.COMMIT: | 1159 elif contents == sync_pb2.ClientToServerMessage.COMMIT: |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1255 | 1268 |
1256 update_sieve.CheckMigrationState() | 1269 update_sieve.CheckMigrationState() |
1257 | 1270 |
1258 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) | 1271 new_timestamp, entries, remaining = self.account.GetChanges(update_sieve) |
1259 | 1272 |
1260 update_response.changes_remaining = remaining | 1273 update_response.changes_remaining = remaining |
1261 for entry in entries: | 1274 for entry in entries: |
1262 reply = update_response.entries.add() | 1275 reply = update_response.entries.add() |
1263 reply.CopyFrom(entry) | 1276 reply.CopyFrom(entry) |
1264 update_sieve.SaveProgress(new_timestamp, update_response) | 1277 update_sieve.SaveProgress(new_timestamp, update_response) |
1278 | |
1279 if update_request.need_encryption_key: | |
1280 update_response.encryption_key = self.account.GetKey() | |
OLD | NEW |