dfindexeddb 20241105__py3-none-any.whl → 20251109__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.
Files changed (33) hide show
  1. dfindexeddb/indexeddb/chromium/blink.py +116 -74
  2. dfindexeddb/indexeddb/chromium/definitions.py +148 -125
  3. dfindexeddb/indexeddb/chromium/record.py +426 -324
  4. dfindexeddb/indexeddb/chromium/v8.py +100 -78
  5. dfindexeddb/indexeddb/cli.py +122 -118
  6. dfindexeddb/indexeddb/firefox/definitions.py +7 -4
  7. dfindexeddb/indexeddb/firefox/gecko.py +98 -74
  8. dfindexeddb/indexeddb/firefox/record.py +66 -24
  9. dfindexeddb/indexeddb/safari/definitions.py +5 -3
  10. dfindexeddb/indexeddb/safari/record.py +68 -51
  11. dfindexeddb/indexeddb/safari/webkit.py +85 -71
  12. dfindexeddb/indexeddb/types.py +4 -1
  13. dfindexeddb/leveldb/cli.py +146 -138
  14. dfindexeddb/leveldb/definitions.py +6 -2
  15. dfindexeddb/leveldb/descriptor.py +70 -56
  16. dfindexeddb/leveldb/ldb.py +39 -33
  17. dfindexeddb/leveldb/log.py +41 -30
  18. dfindexeddb/leveldb/plugins/chrome_notifications.py +30 -18
  19. dfindexeddb/leveldb/plugins/interface.py +5 -6
  20. dfindexeddb/leveldb/plugins/manager.py +10 -9
  21. dfindexeddb/leveldb/record.py +71 -62
  22. dfindexeddb/leveldb/utils.py +21 -13
  23. dfindexeddb/utils.py +36 -31
  24. dfindexeddb/version.py +2 -2
  25. dfindexeddb-20251109.dist-info/METADATA +222 -0
  26. dfindexeddb-20251109.dist-info/RECORD +40 -0
  27. {dfindexeddb-20241105.dist-info → dfindexeddb-20251109.dist-info}/WHEEL +1 -1
  28. dfindexeddb-20241105.dist-info/AUTHORS +0 -12
  29. dfindexeddb-20241105.dist-info/METADATA +0 -424
  30. dfindexeddb-20241105.dist-info/RECORD +0 -41
  31. {dfindexeddb-20241105.dist-info → dfindexeddb-20251109.dist-info}/entry_points.txt +0 -0
  32. {dfindexeddb-20241105.dist-info → dfindexeddb-20251109.dist-info/licenses}/LICENSE +0 -0
  33. {dfindexeddb-20241105.dist-info → dfindexeddb-20251109.dist-info}/top_level.txt +0 -0
@@ -16,12 +16,12 @@
16
16
  import argparse
17
17
  import dataclasses
18
18
  import enum
19
- from datetime import datetime
20
19
  import json
21
20
  import pathlib
21
+ from datetime import datetime
22
+ from typing import Any
22
23
 
23
- from dfindexeddb import utils
24
- from dfindexeddb import version
24
+ from dfindexeddb import utils, version
25
25
  from dfindexeddb.indexeddb import types
26
26
  from dfindexeddb.indexeddb.chromium import blink
27
27
  from dfindexeddb.indexeddb.chromium import record as chromium_record
@@ -29,15 +29,16 @@ from dfindexeddb.indexeddb.firefox import gecko
29
29
  from dfindexeddb.indexeddb.firefox import record as firefox_record
30
30
  from dfindexeddb.indexeddb.safari import record as safari_record
31
31
 
32
-
33
32
  _VALID_PRINTABLE_CHARACTERS = (
34
- ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' +
35
- '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~.')
33
+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
34
+ + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~."
35
+ )
36
36
 
37
37
 
38
38
  class Encoder(json.JSONEncoder):
39
39
  """A JSON encoder class for dfindexeddb fields."""
40
- def default(self, o):
40
+
41
+ def default(self, o): # type: ignore[no-untyped-def]
41
42
  if dataclasses.is_dataclass(o):
42
43
  o_dict = utils.asdict(o)
43
44
  return o_dict
@@ -45,18 +46,18 @@ class Encoder(json.JSONEncoder):
45
46
  out = []
46
47
  for x in o:
47
48
  if chr(x) not in _VALID_PRINTABLE_CHARACTERS:
48
- out.append(f'\\x{x:02X}')
49
+ out.append(f"\\x{x:02X}")
49
50
  else:
50
51
  out.append(chr(x))
51
- return ''.join(out)
52
+ return "".join(out)
52
53
  if isinstance(o, datetime):
53
54
  return o.isoformat()
54
55
  if isinstance(o, types.Undefined):
55
- return '<undefined>'
56
+ return "<undefined>"
56
57
  if isinstance(o, types.JSArray):
57
58
  return o.__dict__
58
59
  if isinstance(o, types.Null):
59
- return '<null>'
60
+ return "<null>"
60
61
  if isinstance(o, set):
61
62
  return list(o)
62
63
  if isinstance(o, types.RegExp):
@@ -66,189 +67,192 @@ class Encoder(json.JSONEncoder):
66
67
  return json.JSONEncoder.default(self, o)
67
68
 
68
69
 
69
- def _Output(structure, output):
70
+ def _Output(structure: Any, output: str) -> None:
70
71
  """Helper method to output parsed structure to stdout."""
71
- if output == 'json':
72
+ if output == "json":
72
73
  print(json.dumps(structure, indent=2, cls=Encoder))
73
- elif output == 'jsonl':
74
+ elif output == "jsonl":
74
75
  print(json.dumps(structure, cls=Encoder))
75
- elif output == 'repr':
76
+ elif output == "repr":
76
77
  print(structure)
77
78
 
78
79
 
79
- def BlinkCommand(args):
80
+ def BlinkCommand(args: argparse.Namespace) -> None:
80
81
  """The CLI for processing a file as a blink-encoded value."""
81
- with open(args.source, 'rb') as fd:
82
+ with open(args.source, "rb") as fd:
82
83
  buffer = fd.read()
83
84
  blink_value = blink.V8ScriptValueDecoder.FromBytes(buffer)
84
85
  _Output(blink_value, output=args.output)
85
86
 
86
87
 
87
- def GeckoCommand(args):
88
+ def GeckoCommand(args: argparse.Namespace) -> None:
88
89
  """The CLI for processing a file as a gecko-encoded value."""
89
- with open(args.source, 'rb') as fd:
90
+ with open(args.source, "rb") as fd:
90
91
  buffer = fd.read()
91
92
  blink_value = gecko.JSStructuredCloneDecoder.FromBytes(buffer)
92
93
  _Output(blink_value, output=args.output)
93
94
 
94
95
 
95
- def DbCommand(args):
96
+ def DbCommand(args: argparse.Namespace) -> None:
96
97
  """The CLI for processing a directory as IndexedDB."""
97
- if args.format in ('chrome', 'chromium'):
98
- for db_record in chromium_record.FolderReader(
99
- args.source).GetRecords(
100
- use_manifest=args.use_manifest,
101
- use_sequence_number=args.use_sequence_number):
102
- _Output(db_record, output=args.output)
103
- elif args.format == 'firefox':
104
- for db_record in firefox_record.FileReader(args.source).Records():
105
- _Output(db_record, output=args.output)
106
- elif args.format == 'safari':
107
- for db_record in safari_record.FileReader(args.source).Records():
108
- _Output(db_record, output=args.output)
109
-
110
-
111
- def LdbCommand(args):
98
+ if args.format in ("chrome", "chromium"):
99
+ for chromium_db_record in chromium_record.FolderReader(
100
+ args.source
101
+ ).GetRecords(
102
+ use_manifest=args.use_manifest,
103
+ use_sequence_number=args.use_sequence_number,
104
+ ):
105
+ _Output(chromium_db_record, output=args.output)
106
+ elif args.format == "firefox":
107
+ for firefox_db_record in firefox_record.FileReader(args.source).Records():
108
+ _Output(firefox_db_record, output=args.output)
109
+ elif args.format == "safari":
110
+ for safari_db_record in safari_record.FileReader(args.source).Records():
111
+ _Output(safari_db_record, output=args.output)
112
+
113
+
114
+ def LdbCommand(args: argparse.Namespace) -> None:
112
115
  """The CLI for processing a LevelDB table (.ldb) file as IndexedDB."""
113
116
  for db_record in chromium_record.IndexedDBRecord.FromFile(args.source):
114
117
  _Output(db_record, output=args.output)
115
118
 
116
119
 
117
- def LogCommand(args):
120
+ def LogCommand(args: argparse.Namespace) -> None:
118
121
  """The CLI for processing a LevelDB log file as IndexedDB."""
119
122
  for db_record in chromium_record.IndexedDBRecord.FromFile(args.source):
120
123
  _Output(db_record, output=args.output)
121
124
 
122
125
 
123
- def App():
126
+ def App() -> None:
124
127
  """The CLI app entrypoint for dfindexeddb."""
125
128
  parser = argparse.ArgumentParser(
126
- prog='dfindexeddb',
127
- description='A cli tool for parsing IndexedDB files',
128
- epilog=f'Version {version.GetVersion()}')
129
+ prog="dfindexeddb",
130
+ description="A cli tool for parsing IndexedDB files",
131
+ epilog=f"Version {version.GetVersion()}",
132
+ )
129
133
 
130
134
  subparsers = parser.add_subparsers()
131
135
 
132
136
  parser_blink = subparsers.add_parser(
133
- 'blink', help='Parse a file as a blink-encoded value.')
137
+ "blink", help="Parse a file as a blink-encoded value."
138
+ )
134
139
  parser_blink.add_argument(
135
- '-s',
136
- '--source',
140
+ "-s",
141
+ "--source",
137
142
  required=True,
138
143
  type=pathlib.Path,
139
- help='The source file.')
144
+ help="The source file.",
145
+ )
140
146
  parser_blink.add_argument(
141
- '-o',
142
- '--output',
143
- choices=[
144
- 'json',
145
- 'jsonl',
146
- 'repr'],
147
- default='json',
148
- help='Output format. Default is json.')
147
+ "-o",
148
+ "--output",
149
+ choices=["json", "jsonl", "repr"],
150
+ default="json",
151
+ help="Output format. Default is json.",
152
+ )
149
153
  parser_blink.set_defaults(func=BlinkCommand)
150
154
 
151
155
  parser_gecko = subparsers.add_parser(
152
- 'gecko', help='Parse a file as a gecko-encoded value.')
156
+ "gecko", help="Parse a file as a gecko-encoded value."
157
+ )
153
158
  parser_gecko.add_argument(
154
- '-s',
155
- '--source',
159
+ "-s",
160
+ "--source",
156
161
  required=True,
157
162
  type=pathlib.Path,
158
- help='The source file.')
163
+ help="The source file.",
164
+ )
159
165
  parser_gecko.add_argument(
160
- '-o',
161
- '--output',
162
- choices=[
163
- 'json',
164
- 'jsonl',
165
- 'repr'],
166
- default='json',
167
- help='Output format. Default is json.')
166
+ "-o",
167
+ "--output",
168
+ choices=["json", "jsonl", "repr"],
169
+ default="json",
170
+ help="Output format. Default is json.",
171
+ )
168
172
  parser_gecko.set_defaults(func=GeckoCommand)
169
173
 
170
174
  parser_db = subparsers.add_parser(
171
- 'db', help='Parse a directory/file as IndexedDB.')
175
+ "db", help="Parse a directory/file as IndexedDB."
176
+ )
172
177
  parser_db.add_argument(
173
- '-s',
174
- '--source',
178
+ "-s",
179
+ "--source",
175
180
  required=True,
176
181
  type=pathlib.Path,
177
182
  help=(
178
- 'The source IndexedDB folder (for chrome/chromium) '
179
- 'or sqlite3 file (for firefox/safari).'))
183
+ "The source IndexedDB folder (for chrome/chromium) "
184
+ "or sqlite3 file (for firefox/safari)."
185
+ ),
186
+ )
180
187
  recover_group = parser_db.add_mutually_exclusive_group()
181
188
  recover_group.add_argument(
182
- '--use_manifest',
183
- action='store_true',
184
- help='Use manifest file to determine active/deleted records.')
189
+ "--use_manifest",
190
+ action="store_true",
191
+ help="Use manifest file to determine active/deleted records.",
192
+ )
185
193
  recover_group.add_argument(
186
- '--use_sequence_number',
187
- action='store_true',
194
+ "--use_sequence_number",
195
+ action="store_true",
188
196
  help=(
189
- 'Use sequence number and file offset to determine active/deleted '
190
- 'records.'))
197
+ "Use sequence number and file offset to determine active/deleted "
198
+ "records."
199
+ ),
200
+ )
191
201
  parser_db.add_argument(
192
- '--format',
202
+ "--format",
193
203
  required=True,
194
- choices=[
195
- 'chromium',
196
- 'chrome',
197
- 'firefox',
198
- 'safari'],
199
- help='The type of IndexedDB to parse.')
204
+ choices=["chromium", "chrome", "firefox", "safari"],
205
+ help="The type of IndexedDB to parse.",
206
+ )
200
207
  parser_db.add_argument(
201
- '-o',
202
- '--output',
203
- choices=[
204
- 'json',
205
- 'jsonl',
206
- 'repr'],
207
- default='json',
208
- help='Output format. Default is json.')
208
+ "-o",
209
+ "--output",
210
+ choices=["json", "jsonl", "repr"],
211
+ default="json",
212
+ help="Output format. Default is json.",
213
+ )
209
214
  parser_db.set_defaults(func=DbCommand)
210
215
 
211
216
  parser_ldb = subparsers.add_parser(
212
- 'ldb',
213
- help='Parse a ldb file as IndexedDB.')
217
+ "ldb", help="Parse a ldb file as IndexedDB."
218
+ )
214
219
  parser_ldb.add_argument(
215
- '-s',
216
- '--source',
220
+ "-s",
221
+ "--source",
217
222
  required=True,
218
223
  type=pathlib.Path,
219
- help='The source .ldb file.')
224
+ help="The source .ldb file.",
225
+ )
220
226
  parser_ldb.add_argument(
221
- '-o',
222
- '--output',
223
- choices=[
224
- 'json',
225
- 'jsonl',
226
- 'repr'],
227
- default='json',
228
- help='Output format. Default is json.')
227
+ "-o",
228
+ "--output",
229
+ choices=["json", "jsonl", "repr"],
230
+ default="json",
231
+ help="Output format. Default is json.",
232
+ )
229
233
  parser_ldb.set_defaults(func=LdbCommand)
230
234
 
231
235
  parser_log = subparsers.add_parser(
232
- 'log',
233
- help='Parse a log file as IndexedDB.')
236
+ "log", help="Parse a log file as IndexedDB."
237
+ )
234
238
  parser_log.add_argument(
235
- '-s', '--source',
239
+ "-s",
240
+ "--source",
236
241
  required=True,
237
242
  type=pathlib.Path,
238
- help='The source .log file.')
243
+ help="The source .log file.",
244
+ )
239
245
  parser_log.add_argument(
240
- '-o',
241
- '--output',
242
- choices=[
243
- 'json',
244
- 'jsonl',
245
- 'repr'],
246
- default='json',
247
- help='Output format. Default is json.')
246
+ "-o",
247
+ "--output",
248
+ choices=["json", "jsonl", "repr"],
249
+ default="json",
250
+ help="Output format. Default is json.",
251
+ )
248
252
  parser_log.set_defaults(func=LogCommand)
249
253
 
250
- args = parser.parse_args()
251
- if hasattr(args, 'func'):
254
+ args: argparse.Namespace = parser.parse_args()
255
+ if hasattr(args, "func"):
252
256
  args.func(args)
253
257
  else:
254
258
  parser.print_help()
@@ -18,6 +18,7 @@ from enum import IntEnum
18
18
 
19
19
  class IndexedDBKeyType(IntEnum):
20
20
  """IndexedDB Key Types."""
21
+
21
22
  TERMINATOR = 0
22
23
  FLOAT = 0x10
23
24
  DATE = 0x20
@@ -38,6 +39,7 @@ THREE_BYTE_SHIFT = 6
38
39
 
39
40
  class StructuredDataType(IntEnum):
40
41
  """Structured Data Types."""
42
+
41
43
  FLOAT_MAX = 0xFFF00000
42
44
  HEADER = 0xFFF10000
43
45
  NULL = 0xFFFF0000
@@ -45,7 +47,7 @@ class StructuredDataType(IntEnum):
45
47
  BOOLEAN = 0xFFFF0002
46
48
  INT32 = 0xFFFF0003
47
49
  STRING = 0xFFFF0004
48
- DATE_OBJECT = 0xFFFF0005
50
+ DATE_OBJECT = 0xFFFF0005
49
51
  REGEXP_OBJECT = 0xFFFF0006
50
52
  ARRAY_OBJECT = 0xFFFF0007
51
53
  OBJECT_OBJECT = 0xFFFF0008
@@ -53,8 +55,8 @@ class StructuredDataType(IntEnum):
53
55
  BOOLEAN_OBJECT = 0xFFFF000A
54
56
  STRING_OBJECT = 0xFFFF000B
55
57
  NUMBER_OBJECT = 0xFFFF000C
56
- BACK_REFERENCE_OBJECT = 0xFFFF000D
57
- DO_NOT_USE_1 = 0xFFFF000E
58
+ BACK_REFERENCE_OBJECT = 0xFFFF000D
59
+ DO_NOT_USE_1 = 0xFFFF000E
58
60
  DO_NOT_USE_2 = 0xFFFF000F
59
61
  TYPED_ARRAY_OBJECT_V2 = 0xFFFF0010
60
62
  MAP_OBJECT = 0xFFFF0011
@@ -95,6 +97,7 @@ class StructuredDataType(IntEnum):
95
97
 
96
98
  class StructuredCloneTags(IntEnum):
97
99
  """Structured Clone Tags."""
100
+
98
101
  BLOB = 0xFFFF8001
99
102
  FILE_WITHOUT_LASTMODIFIEDDATE = 0xFFFF8002
100
103
  FILELIST = 0xFFFF8003
@@ -140,4 +143,4 @@ class StructuredCloneTags(IntEnum):
140
143
  ENCODEDAUDIOCHUNK = 0xFFFF8031
141
144
 
142
145
 
143
- FRAME_HEADER = b'\xff\x06\x00\x00sNaPpY'
146
+ FRAME_HEADER = b"\xff\x06\x00\x00sNaPpY"