dfindexeddb 20240417__py3-none-any.whl → 20240519__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,11 +19,13 @@ from datetime import datetime
19
19
  import json
20
20
  import pathlib
21
21
 
22
+ from dfindexeddb import utils
22
23
  from dfindexeddb import version
23
24
  from dfindexeddb.leveldb import descriptor
24
25
  from dfindexeddb.leveldb import ldb
25
26
  from dfindexeddb.leveldb import log
26
27
  from dfindexeddb.leveldb import record
28
+ from dfindexeddb.leveldb.plugins import manager
27
29
 
28
30
 
29
31
  _VALID_PRINTABLE_CHARACTERS = (
@@ -37,7 +39,7 @@ class Encoder(json.JSONEncoder):
37
39
  def default(self, o):
38
40
  """Returns a serializable object for o."""
39
41
  if dataclasses.is_dataclass(o):
40
- o_dict = dataclasses.asdict(o)
42
+ o_dict = utils.asdict(o)
41
43
  return o_dict
42
44
  if isinstance(o, bytes):
43
45
  out = []
@@ -66,16 +68,39 @@ def _Output(structure, output):
66
68
 
67
69
  def DbCommand(args):
68
70
  """The CLI for processing leveldb folders."""
69
- if args.use_manifest:
70
- for rec in record.LevelDBRecord.FromManifest(args.source):
71
- _Output(rec, output=args.output)
71
+ if args.plugin and args.plugin == 'list':
72
+ for plugin, _ in manager.LeveldbPluginManager.GetPlugins():
73
+ print(plugin)
74
+ return
75
+
76
+ if args.plugin:
77
+ plugin_class = manager.LeveldbPluginManager.GetPlugin(args.plugin)
72
78
  else:
73
- for rec in record.LevelDBRecord.FromDir(args.source):
74
- _Output(rec, output=args.output)
79
+ plugin_class = None
80
+
81
+ for leveldb_record in record.FolderReader(
82
+ args.source).GetRecords(
83
+ use_manifest=args.use_manifest,
84
+ use_sequence_number=args.use_sequence_number):
85
+ if plugin_class:
86
+ plugin_record = plugin_class.FromLevelDBRecord(leveldb_record)
87
+ _Output(plugin_record, output=args.output)
88
+ else:
89
+ _Output(leveldb_record, output=args.output)
75
90
 
76
91
 
77
92
  def LdbCommand(args):
78
93
  """The CLI for processing ldb files."""
94
+ if args.plugin and args.plugin == 'list':
95
+ for plugin, _ in manager.LeveldbPluginManager.GetPlugins():
96
+ print(plugin)
97
+ return
98
+
99
+ if args.plugin:
100
+ plugin_class = manager.LeveldbPluginManager.GetPlugin(args.plugin)
101
+ else:
102
+ plugin_class = None
103
+
79
104
  ldb_file = ldb.FileReader(args.source)
80
105
 
81
106
  if args.structure_type == 'blocks':
@@ -86,7 +111,11 @@ def LdbCommand(args):
86
111
  elif args.structure_type == 'records' or not args.structure_type:
87
112
  # Prints key value record information.
88
113
  for key_value_record in ldb_file.GetKeyValueRecords():
89
- _Output(key_value_record, output=args.output)
114
+ if plugin_class:
115
+ plugin_record = plugin_class.FromKeyValueRecord(key_value_record)
116
+ _Output(plugin_record, output=args.output)
117
+ else:
118
+ _Output(key_value_record, output=args.output)
90
119
 
91
120
  else:
92
121
  print(f'{args.structure_type} is not supported for ldb files.')
@@ -94,6 +123,16 @@ def LdbCommand(args):
94
123
 
95
124
  def LogCommand(args):
96
125
  """The CLI for processing log files."""
126
+ if args.plugin and args.plugin == 'list':
127
+ for plugin, _ in manager.LeveldbPluginManager.GetPlugins():
128
+ print(plugin)
129
+ return
130
+
131
+ if args.plugin:
132
+ plugin_class = manager.LeveldbPluginManager.GetPlugin(args.plugin)
133
+ else:
134
+ plugin_class = None
135
+
97
136
  log_file = log.FileReader(args.source)
98
137
 
99
138
  if args.structure_type == 'blocks':
@@ -115,7 +154,11 @@ def LogCommand(args):
115
154
  or not args.structure_type):
116
155
  # Prints key value record information.
117
156
  for internal_key_record in log_file.GetParsedInternalKeys():
118
- _Output(internal_key_record, output=args.output)
157
+ if plugin_class:
158
+ plugin_record = plugin_class.FromKeyValueRecord(internal_key_record)
159
+ _Output(plugin_record, output=args.output)
160
+ else:
161
+ _Output(internal_key_record, output=args.output)
119
162
 
120
163
  else:
121
164
  print(f'{args.structure_type} is not supported for log files.')
@@ -147,6 +190,7 @@ def DescriptorCommand(args):
147
190
  else:
148
191
  print(f'{args.structure_type} is not supported for descriptor files.')
149
192
 
193
+
150
194
  def App():
151
195
  """The CLI app entrypoint for parsing leveldb files."""
152
196
  parser = argparse.ArgumentParser(
@@ -163,10 +207,17 @@ def App():
163
207
  required=True,
164
208
  type=pathlib.Path,
165
209
  help='The source leveldb directory')
166
- parser_db.add_argument(
210
+ recover_group = parser_db.add_mutually_exclusive_group()
211
+ recover_group.add_argument(
167
212
  '--use_manifest',
168
213
  action='store_true',
169
214
  help='Use manifest file to determine active/deleted records.')
215
+ recover_group.add_argument(
216
+ '--use_sequence_number',
217
+ action='store_true',
218
+ help=(
219
+ 'Use sequence number and file offset to determine active/deleted '
220
+ 'records.'))
170
221
  parser_db.add_argument(
171
222
  '-o',
172
223
  '--output',
@@ -176,6 +227,9 @@ def App():
176
227
  'repr'],
177
228
  default='json',
178
229
  help='Output format. Default is json')
230
+ parser_db.add_argument(
231
+ '--plugin',
232
+ help='Use plugin to parse records.')
179
233
  parser_db.set_defaults(func=DbCommand)
180
234
 
181
235
  parser_log = subparsers.add_parser(
@@ -194,6 +248,9 @@ def App():
194
248
  'repr'],
195
249
  default='json',
196
250
  help='Output format. Default is json')
251
+ parser_log.add_argument(
252
+ '--plugin',
253
+ help='Use plugin to parse records.')
197
254
  parser_log.add_argument(
198
255
  '-t',
199
256
  '--structure_type',
@@ -221,6 +278,9 @@ def App():
221
278
  'repr'],
222
279
  default='json',
223
280
  help='Output format. Default is json')
281
+ parser_ldb.add_argument(
282
+ '--plugin',
283
+ help='Use plugin to parse records.')
224
284
  parser_ldb.add_argument(
225
285
  '-t',
226
286
  '--structure_type',
@@ -257,8 +317,7 @@ def App():
257
317
  '-v',
258
318
  '--version_history',
259
319
  action='store_true',
260
- help='Parses the leveldb version history.'
261
- )
320
+ help='Parses the leveldb version history.')
262
321
  parser_descriptor.set_defaults(func=DescriptorCommand)
263
322
 
264
323
  args = parser.parse_args()
@@ -152,7 +152,7 @@ class PhysicalRecord(utils.FromDecoderMixin):
152
152
  @classmethod
153
153
  def FromDecoder(
154
154
  cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
155
- ) -> PhysicalRecord:
155
+ ) -> Optional[PhysicalRecord]:
156
156
  """Decodes a PhysicalRecord from the current position of a LevelDBDecoder.
157
157
 
158
158
  Args:
@@ -161,11 +161,13 @@ class PhysicalRecord(utils.FromDecoderMixin):
161
161
  read from.
162
162
 
163
163
  Returns:
164
- A PhysicalRecord.
164
+ A PhysicalRecord or None if the parsed header is 0.
165
165
  """
166
166
  offset, checksum = decoder.DecodeUint32()
167
167
  _, length = decoder.DecodeUint16()
168
168
  _, record_type_byte = decoder.DecodeUint8()
169
+ if checksum == 0 or length == 0 or record_type_byte == 0:
170
+ return None
169
171
  try:
170
172
  record_type = definitions.LogFilePhysicalRecordType(record_type_byte)
171
173
  except ValueError as error:
@@ -206,7 +208,11 @@ class Block:
206
208
  buffer_length = len(self.data)
207
209
 
208
210
  while buffer.tell() + PhysicalRecord.PHYSICAL_HEADER_LENGTH < buffer_length:
209
- yield PhysicalRecord.FromStream(buffer, base_offset=self.offset)
211
+ record = PhysicalRecord.FromStream(buffer, base_offset=self.offset)
212
+ if record:
213
+ yield record
214
+ else:
215
+ return
210
216
 
211
217
  @classmethod
212
218
  def FromStream(cls, stream: BinaryIO) -> Optional[Block]:
@@ -0,0 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2024 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Leveldb Plugin module."""
16
+
17
+ from dfindexeddb.leveldb.plugins import chrome_notifications
@@ -0,0 +1,135 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2024 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Parser plugin for Chrome Notifications."""
16
+ from __future__ import annotations
17
+
18
+ import dataclasses
19
+ import logging
20
+
21
+ from typing import Optional
22
+
23
+ try:
24
+ # pytype: disable=import-error
25
+ from dfdatetime import webkit_time
26
+ from dfindexeddb.leveldb.plugins import notification_database_data_pb2 as \
27
+ notification_pb2
28
+ # pytype: enable=import-error
29
+ _has_import_dependencies = True
30
+ except ImportError as err:
31
+ _has_import_dependencies = False
32
+ logging.warning((
33
+ 'Could not import dependencies for '
34
+ 'leveldb.plugins.chrome_notifications: %s'), err)
35
+
36
+ from dfindexeddb.indexeddb.chromium import blink
37
+ from dfindexeddb.leveldb.plugins import interface
38
+ from dfindexeddb.leveldb.plugins import manager
39
+
40
+
41
+ @dataclasses.dataclass
42
+ class ChromeNotificationRecord(interface.LeveldbPlugin):
43
+ """Chrome notification record."""
44
+ src_file: Optional[str] = None
45
+ offset: Optional[int] = None
46
+ key: Optional[str] = None
47
+ sequence_number: Optional[int] = None
48
+ type: Optional[int] = None
49
+ origin: Optional[str] = None
50
+ service_worker_registration_id: Optional[int] = None
51
+ notification_title: Optional[str] = None
52
+ notification_direction: Optional[str] = None
53
+ notification_lang: Optional[str] = None
54
+ notification_body: Optional[str] = None
55
+ notification_tag: Optional[str] = None
56
+ notification_icon: Optional[str] = None
57
+ notification_silent: Optional[bool] = None
58
+ notification_data: Optional[str] = None
59
+ notification_require_interaction: Optional[bool] = None
60
+ notification_time: Optional[str] = None
61
+ notification_renotify: Optional[bool] = None
62
+ notification_badge: Optional[str] = None
63
+ notification_image: Optional[str] = None
64
+ notification_id: Optional[str] = None
65
+ replaced_existing_notification: Optional[bool] = None
66
+ num_clicks: Optional[int] = None
67
+ num_action_button_clicks: Optional[int] = None
68
+ creation_time: Optional[str] = None
69
+ closed_reason: Optional[str] = None
70
+ has_triggered: Optional[bool] = None
71
+
72
+ @classmethod
73
+ def FromKeyValueRecord(
74
+ cls,
75
+ ldb_record
76
+ ) -> ChromeNotificationRecord:
77
+ record = cls()
78
+ record.offset = ldb_record.offset
79
+ record.key = ldb_record.key.decode()
80
+ record.sequence_number = ldb_record.sequence_number
81
+ record.type = ldb_record.record_type
82
+
83
+ if not ldb_record.value:
84
+ return record
85
+
86
+ # pylint: disable-next=no-member,line-too-long
87
+ notification_proto = notification_pb2.NotificationDatabaseDataProto() # pytype: disable=module-attr
88
+ notification_proto.ParseFromString(ldb_record.value)
89
+
90
+ record.origin = notification_proto.origin
91
+ record.service_worker_registration_id = (
92
+ notification_proto.service_worker_registration_id)
93
+ record.notification_title = notification_proto.notification_data.title
94
+ record.notification_direction = (
95
+ notification_proto.notification_data.direction)
96
+ record.notification_lang = notification_proto.notification_data.lang
97
+ record.notification_body = notification_proto.notification_data.body
98
+ record.notification_tag = notification_proto.notification_data.tag
99
+ record.notification_icon = notification_proto.notification_data.icon
100
+ record.notification_silent = notification_proto.notification_data.silent
101
+ record.notification_data = notification_proto.notification_data.data
102
+ record.notification_require_interaction = (
103
+ notification_proto.notification_data.require_interaction)
104
+ record.notification_time = webkit_time.WebKitTime(
105
+ timestamp=notification_proto.notification_data.timestamp
106
+ ).CopyToDateTimeString()
107
+ record.notification_renotify = notification_proto.notification_data.renotify
108
+ record.notification_badge = notification_proto.notification_data.badge
109
+ record.notification_image = notification_proto.notification_data.image
110
+ record.notification_id = notification_proto.notification_id
111
+ record.replaced_existing_notification = (
112
+ notification_proto.replaced_existing_notification)
113
+ record.num_clicks = notification_proto.num_clicks
114
+ record.num_action_button_clicks = (
115
+ notification_proto.num_action_button_clicks)
116
+ record.creation_time = webkit_time.WebKitTime(
117
+ timestamp=notification_proto.creation_time_millis
118
+ ).CopyToDateTimeString()
119
+ record.closed_reason = notification_proto.closed_reason
120
+ record.has_triggered = notification_proto.has_triggered
121
+
122
+ if not notification_proto.notification_data.data:
123
+ return record
124
+
125
+ notification_data = blink.V8ScriptValueDecoder(
126
+ raw_data=notification_proto.notification_data.data).Deserialize()
127
+ record.notification_data = notification_data
128
+
129
+ return record
130
+
131
+
132
+ # check if dependencies are in existence..
133
+
134
+ if _has_import_dependencies:
135
+ manager.PluginManager.RegisterPlugin(ChromeNotificationRecord)
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2024 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Interface for leveldb plugins."""
16
+ from typing import Any, Union
17
+
18
+ from dfindexeddb.leveldb import record
19
+ from dfindexeddb.leveldb import ldb
20
+ from dfindexeddb.leveldb import log
21
+
22
+ class LeveldbPlugin:
23
+ """The base leveldb plugin class."""
24
+
25
+ @classmethod
26
+ def FromLevelDBRecord(cls,
27
+ ldb_record: record.LevelDBRecord) -> Any:
28
+ """Parses a leveldb record."""
29
+ parsed_record = cls.FromKeyValueRecord(ldb_record.record)
30
+ ldb_record.record = parsed_record
31
+ return ldb_record
32
+
33
+ @classmethod
34
+ def FromKeyValueRecord(
35
+ cls, ldb_record: Union[ldb.KeyValueRecord, log.ParsedInternalKey]) -> Any:
36
+ """Parses a leveldb key value record."""
@@ -0,0 +1,75 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2024 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Leveldb plugin manager."""
16
+ from typing import Type
17
+
18
+ from dfindexeddb.leveldb.plugins import interface
19
+
20
+
21
+ class LeveldbPluginManager:
22
+ """The leveldb plugin manager."""
23
+
24
+ _class_registry = {}
25
+
26
+ @classmethod
27
+ def GetPlugins(cls):
28
+ """Retrieves the registered leveldb plugins.
29
+
30
+ Yields:
31
+ tuple: containing:
32
+ str: the name of the leveldb plugin.
33
+ class: the plugin class.
34
+ """
35
+ yield from cls._class_registry.items()
36
+
37
+ @classmethod
38
+ def GetPlugin(cls, plugin_name: str) -> interface.LeveldbPlugin:
39
+ """Retrieves a class object of a specific plugin.
40
+
41
+ Args:
42
+ plugin_name: name of the plugin.
43
+
44
+ Returns:
45
+ the LeveldbPlugin class.
46
+
47
+ Raises:
48
+ KeyError: if the plugin is not found/registered in the manager.
49
+ """
50
+ try:
51
+ return cls._class_registry[plugin_name]
52
+ except KeyError:
53
+ raise KeyError(f'Plugin not found: {plugin_name}')
54
+
55
+ @classmethod
56
+ def RegisterPlugin(cls, plugin_class: Type[interface.LeveldbPlugin]):
57
+ """Registers a leveldb plugin.
58
+
59
+ Args:
60
+ plugin_class (class): the plugin class to register.
61
+
62
+ Raises:
63
+ KeyError: if class is already set for the corresponding name.
64
+ """
65
+ plugin_name = plugin_class.__name__
66
+ if plugin_name in cls._class_registry:
67
+ raise KeyError(f'Plugin already registered {plugin_name}')
68
+ cls._class_registry[plugin_name] = plugin_class
69
+
70
+ @classmethod
71
+ def ClearPlugins(cls):
72
+ """Clears all plugin registrations."""
73
+ cls._class_registry = {}
74
+
75
+ PluginManager = LeveldbPluginManager()
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: notification_database_data.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+ # pylint: skip-file
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n notification_database_data.proto\"\xff\t\n\x1dNotificationDatabaseDataProto\x12\"\n\x1apersistent_notification_id\x18\x01 \x01(\x03\x12\x17\n\x0fnotification_id\x18\x05 \x01(\t\x12\x0e\n\x06origin\x18\x02 \x01(\t\x12&\n\x1eservice_worker_registration_id\x18\x03 \x01(\x03\x12&\n\x1ereplaced_existing_notification\x18\x06 \x01(\x08\x12\x12\n\nnum_clicks\x18\x07 \x01(\x05\x12 \n\x18num_action_button_clicks\x18\x08 \x01(\x05\x12\x1c\n\x14\x63reation_time_millis\x18\t \x01(\x03\x12%\n\x1dtime_until_first_click_millis\x18\n \x01(\x03\x12$\n\x1ctime_until_last_click_millis\x18\x0b \x01(\x03\x12\x1f\n\x17time_until_close_millis\x18\x0c \x01(\x03\x12\x42\n\rclosed_reason\x18\r \x01(\x0e\x32+.NotificationDatabaseDataProto.ClosedReason\x12J\n\x11notification_data\x18\x04 \x01(\x0b\x32/.NotificationDatabaseDataProto.NotificationData\x12\x15\n\rhas_triggered\x18\x0e \x01(\x08\x1a\xba\x01\n\x12NotificationAction\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0c\n\x04icon\x18\x03 \x01(\t\x12\x44\n\x04type\x18\x04 \x01(\x0e\x32\x36.NotificationDatabaseDataProto.NotificationAction.Type\x12\x13\n\x0bplaceholder\x18\x05 \x01(\t\"\x1c\n\x04Type\x12\n\n\x06\x42UTTON\x10\x00\x12\x08\n\x04TEXT\x10\x01\x1a\xe4\x03\n\x10NotificationData\x12\r\n\x05title\x18\x01 \x01(\t\x12L\n\tdirection\x18\x02 \x01(\x0e\x32\x39.NotificationDatabaseDataProto.NotificationData.Direction\x12\x0c\n\x04lang\x18\x03 \x01(\t\x12\x0c\n\x04\x62ody\x18\x04 \x01(\t\x12\x0b\n\x03tag\x18\x05 \x01(\t\x12\r\n\x05image\x18\x0f \x01(\t\x12\x0c\n\x04icon\x18\x06 \x01(\t\x12\r\n\x05\x62\x61\x64ge\x18\x0e \x01(\t\x12\x1d\n\x11vibration_pattern\x18\t \x03(\x05\x42\x02\x10\x01\x12\x11\n\ttimestamp\x18\x0c \x01(\x03\x12\x10\n\x08renotify\x18\r \x01(\x08\x12\x0e\n\x06silent\x18\x07 \x01(\x08\x12\x1b\n\x13require_interaction\x18\x0b \x01(\x08\x12\x0c\n\x04\x64\x61ta\x18\x08 \x01(\x0c\x12\x42\n\x07\x61\x63tions\x18\n \x03(\x0b\x32\x31.NotificationDatabaseDataProto.NotificationAction\x12\x1e\n\x16show_trigger_timestamp\x18\x10 \x01(\x03\";\n\tDirection\x12\x11\n\rLEFT_TO_RIGHT\x10\x00\x12\x11\n\rRIGHT_TO_LEFT\x10\x01\x12\x08\n\x04\x41UTO\x10\x02\"4\n\x0c\x43losedReason\x12\x08\n\x04USER\x10\x00\x12\r\n\tDEVELOPER\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'notification_database_data_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ DESCRIPTOR._options = None
24
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA'].fields_by_name['vibration_pattern']._options = None
25
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA'].fields_by_name['vibration_pattern']._serialized_options = b'\020\001'
26
+ _globals['_NOTIFICATIONDATABASEDATAPROTO']._serialized_start=37
27
+ _globals['_NOTIFICATIONDATABASEDATAPROTO']._serialized_end=1316
28
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONACTION']._serialized_start=589
29
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONACTION']._serialized_end=775
30
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONACTION_TYPE']._serialized_start=747
31
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONACTION_TYPE']._serialized_end=775
32
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA']._serialized_start=778
33
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA']._serialized_end=1262
34
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA_DIRECTION']._serialized_start=1203
35
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_NOTIFICATIONDATA_DIRECTION']._serialized_end=1262
36
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_CLOSEDREASON']._serialized_start=1264
37
+ _globals['_NOTIFICATIONDATABASEDATAPROTO_CLOSEDREASON']._serialized_end=1316
38
+ # @@protoc_insertion_point(module_scope)