dfindexeddb 20241031__tar.gz → 20241105__tar.gz
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.
- {dfindexeddb-20241031/dfindexeddb.egg-info → dfindexeddb-20241105}/PKG-INFO +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/chromium/definitions.py +5 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/chromium/record.py +181 -95
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/chromium/v8.py +19 -70
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/cli.py +30 -23
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/firefox/gecko.py +8 -8
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/safari/definitions.py +7 -7
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/safari/webkit.py +31 -122
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/types.py +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/cli.py +18 -11
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/descriptor.py +22 -6
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/ldb.py +5 -2
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/log.py +11 -5
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/plugins/manager.py +2 -2
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/utils.py +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/version.py +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105/dfindexeddb.egg-info}/PKG-INFO +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105}/pyproject.toml +1 -1
- {dfindexeddb-20241031 → dfindexeddb-20241105}/AUTHORS +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/LICENSE +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/README.md +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/errors.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/chromium/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/chromium/blink.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/firefox/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/firefox/definitions.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/firefox/record.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/safari/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/safari/record.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/indexeddb/utils.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/definitions.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/plugins/__init__.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/plugins/chrome_notifications.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/plugins/interface.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/plugins/notification_database_data_pb2.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/record.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb/leveldb/utils.py +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb.egg-info/SOURCES.txt +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb.egg-info/dependency_links.txt +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb.egg-info/entry_points.txt +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb.egg-info/requires.txt +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/dfindexeddb.egg-info/top_level.txt +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/setup.cfg +0 -0
- {dfindexeddb-20241031 → dfindexeddb-20241105}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dfindexeddb
|
|
3
|
-
Version:
|
|
3
|
+
Version: 20241105
|
|
4
4
|
Summary: dfindexeddb is an experimental Python tool for performing digital forensic analysis of IndexedDB and leveldb files.
|
|
5
5
|
Author-email: Syd Pleno <sydp@google.com>
|
|
6
6
|
Maintainer-email: dfIndexeddb Developers <dfindexeddb-dev@googlegroups.com>
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
from enum import Enum, IntEnum, IntFlag
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
REQUIRES_PROCESSING_SSV_PSEUDO_VERSION = 0x11
|
|
20
|
+
REPLACE_WITH_BLOB = 0x01
|
|
21
|
+
COMPRESSED_WITH_SNAPPY = 0x02
|
|
22
|
+
|
|
23
|
+
|
|
19
24
|
class DatabaseMetaDataKeyType(IntEnum):
|
|
20
25
|
"""Database Metadata key types."""
|
|
21
26
|
ORIGIN_NAME = 0
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""Parses Chromium IndexedDb structures."""
|
|
16
16
|
from __future__ import annotations
|
|
17
|
+
|
|
17
18
|
from dataclasses import dataclass, field
|
|
18
19
|
from datetime import datetime
|
|
19
20
|
import io
|
|
@@ -23,6 +24,8 @@ import traceback
|
|
|
23
24
|
from typing import Any, BinaryIO, Generator, Optional, Tuple, Type, TypeVar, \
|
|
24
25
|
Union
|
|
25
26
|
|
|
27
|
+
import snappy
|
|
28
|
+
|
|
26
29
|
from dfindexeddb import errors
|
|
27
30
|
from dfindexeddb.indexeddb.chromium import blink
|
|
28
31
|
from dfindexeddb.indexeddb.chromium import definitions
|
|
@@ -50,7 +53,10 @@ class KeyPrefix(utils.FromDecoderMixin):
|
|
|
50
53
|
|
|
51
54
|
@classmethod
|
|
52
55
|
def FromDecoder(
|
|
53
|
-
cls,
|
|
56
|
+
cls,
|
|
57
|
+
decoder: utils.LevelDBDecoder,
|
|
58
|
+
base_offset: int = 0
|
|
59
|
+
) -> KeyPrefix:
|
|
54
60
|
"""Decodes a KeyPrefix from the current position of a LevelDBDecoder.
|
|
55
61
|
|
|
56
62
|
Args:
|
|
@@ -151,7 +157,8 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
151
157
|
|
|
152
158
|
def RecursiveParse(depth: int) -> Tuple[
|
|
153
159
|
int, definitions.IDBKeyType, Union[
|
|
154
|
-
list, bytes, str, float, datetime, None
|
|
160
|
+
list, bytes, str, float, datetime, None
|
|
161
|
+
]]:
|
|
155
162
|
"""Recursively parses IDBKeys.
|
|
156
163
|
|
|
157
164
|
Args:
|
|
@@ -215,8 +222,11 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
215
222
|
value: Union[str, list[str], None]
|
|
216
223
|
|
|
217
224
|
@classmethod
|
|
218
|
-
def FromDecoder(
|
|
219
|
-
|
|
225
|
+
def FromDecoder(
|
|
226
|
+
cls,
|
|
227
|
+
decoder: utils.LevelDBDecoder,
|
|
228
|
+
base_offset: int = 0
|
|
229
|
+
) -> IDBKeyPath:
|
|
220
230
|
"""Decodes an IDBKeyPath from the current position of a LevelDBDecoder.
|
|
221
231
|
|
|
222
232
|
Args:
|
|
@@ -228,7 +238,7 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
228
238
|
|
|
229
239
|
Raises:
|
|
230
240
|
ParserError: on insufficient bytes or invalid array length during
|
|
231
|
-
parsing.
|
|
241
|
+
parsing or unsupported key path type.
|
|
232
242
|
"""
|
|
233
243
|
buffer = decoder.stream.getvalue() #pytype: disable=attribute-error
|
|
234
244
|
if len(buffer) < 3:
|
|
@@ -255,6 +265,8 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
255
265
|
for _ in range(count):
|
|
256
266
|
_, entry = decoder.DecodeStringWithLength()
|
|
257
267
|
value.append(entry)
|
|
268
|
+
else:
|
|
269
|
+
raise errors.ParserError(f'Unsupported key_path_type {key_path_type}.')
|
|
258
270
|
return IDBKeyPath(base_offset + offset, key_path_type, value)
|
|
259
271
|
|
|
260
272
|
|
|
@@ -272,8 +284,11 @@ class BlobJournalEntry(utils.FromDecoderMixin):
|
|
|
272
284
|
blob_number: int
|
|
273
285
|
|
|
274
286
|
@classmethod
|
|
275
|
-
def FromDecoder(
|
|
276
|
-
|
|
287
|
+
def FromDecoder(
|
|
288
|
+
cls,
|
|
289
|
+
decoder: utils.LevelDBDecoder,
|
|
290
|
+
base_offset: int = 0
|
|
291
|
+
) -> BlobJournalEntry:
|
|
277
292
|
"""Decodes a BlobJournalEntry from the current position of a LevelDBDecoder.
|
|
278
293
|
|
|
279
294
|
Args:
|
|
@@ -301,8 +316,11 @@ class BlobJournal(utils.FromDecoderMixin):
|
|
|
301
316
|
entries: list[BlobJournalEntry]
|
|
302
317
|
|
|
303
318
|
@classmethod
|
|
304
|
-
def FromDecoder(
|
|
305
|
-
|
|
319
|
+
def FromDecoder(
|
|
320
|
+
cls,
|
|
321
|
+
decoder: utils.LevelDBDecoder,
|
|
322
|
+
base_offset: int = 0
|
|
323
|
+
) -> BlobJournal:
|
|
306
324
|
"""Decodes a BlobJournal from the current position of a LevelDBDecoder.
|
|
307
325
|
|
|
308
326
|
Blob journals are zero-or-more instances of BlobJournalEntry. There is no
|
|
@@ -395,8 +413,7 @@ class BaseIndexedDBKey:
|
|
|
395
413
|
raise NotImplementedError(f'{cls.__class__.__name__}.decode_key')
|
|
396
414
|
|
|
397
415
|
@classmethod
|
|
398
|
-
def FromStream(
|
|
399
|
-
cls: Type[T], stream: BinaryIO, base_offset: int = 0) -> T:
|
|
416
|
+
def FromStream(cls: Type[T], stream: BinaryIO, base_offset: int = 0) -> T:
|
|
400
417
|
"""Parses the key from the current position of the binary stream.
|
|
401
418
|
|
|
402
419
|
Args:
|
|
@@ -412,8 +429,7 @@ class BaseIndexedDBKey:
|
|
|
412
429
|
decoder=decoder, key_prefix=key_prefix, base_offset=base_offset)
|
|
413
430
|
|
|
414
431
|
@classmethod
|
|
415
|
-
def FromBytes(
|
|
416
|
-
cls: Type[T], raw_data: bytes, base_offset: int = 0) -> T:
|
|
432
|
+
def FromBytes(cls: Type[T], raw_data: bytes, base_offset: int = 0) -> T:
|
|
417
433
|
"""Parses the key from the raw key bytes.
|
|
418
434
|
|
|
419
435
|
Args:
|
|
@@ -433,11 +449,13 @@ class SchemaVersionKey(BaseIndexedDBKey):
|
|
|
433
449
|
|
|
434
450
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
435
451
|
"""Decodes the schema version value."""
|
|
436
|
-
return decoder.
|
|
452
|
+
return decoder.DecodeInt()[1]
|
|
437
453
|
|
|
438
454
|
@classmethod
|
|
439
455
|
def FromDecoder(
|
|
440
|
-
cls,
|
|
456
|
+
cls,
|
|
457
|
+
decoder: utils.LevelDBDecoder,
|
|
458
|
+
key_prefix: KeyPrefix,
|
|
441
459
|
base_offset: int = 0
|
|
442
460
|
) -> SchemaVersionKey:
|
|
443
461
|
"""Decodes the schema version key."""
|
|
@@ -453,11 +471,13 @@ class MaxDatabaseIdKey(BaseIndexedDBKey):
|
|
|
453
471
|
|
|
454
472
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
455
473
|
"""Decodes the maximum database value."""
|
|
456
|
-
return decoder.
|
|
474
|
+
return decoder.DecodeInt()[1]
|
|
457
475
|
|
|
458
476
|
@classmethod
|
|
459
477
|
def FromDecoder(
|
|
460
|
-
cls,
|
|
478
|
+
cls,
|
|
479
|
+
decoder: utils.LevelDBDecoder,
|
|
480
|
+
key_prefix: KeyPrefix,
|
|
461
481
|
base_offset: int = 0
|
|
462
482
|
) -> MaxDatabaseIdKey:
|
|
463
483
|
"""Decodes the maximum database key."""
|
|
@@ -473,11 +493,13 @@ class DataVersionKey(BaseIndexedDBKey):
|
|
|
473
493
|
|
|
474
494
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
475
495
|
"""Decodes the data version value."""
|
|
476
|
-
return decoder.
|
|
496
|
+
return decoder.DecodeInt()[1]
|
|
477
497
|
|
|
478
498
|
@classmethod
|
|
479
499
|
def FromDecoder(
|
|
480
|
-
cls,
|
|
500
|
+
cls,
|
|
501
|
+
decoder: utils.LevelDBDecoder,
|
|
502
|
+
key_prefix: KeyPrefix,
|
|
481
503
|
base_offset: int = 0
|
|
482
504
|
) -> DataVersionKey:
|
|
483
505
|
"""Decodes the data version key."""
|
|
@@ -497,7 +519,9 @@ class RecoveryBlobJournalKey(BaseIndexedDBKey):
|
|
|
497
519
|
|
|
498
520
|
@classmethod
|
|
499
521
|
def FromDecoder(
|
|
500
|
-
cls,
|
|
522
|
+
cls,
|
|
523
|
+
decoder: utils.LevelDBDecoder,
|
|
524
|
+
key_prefix: KeyPrefix,
|
|
501
525
|
base_offset: int = 0
|
|
502
526
|
) -> RecoveryBlobJournalKey:
|
|
503
527
|
"""Decodes the recovery blob journal key."""
|
|
@@ -517,7 +541,9 @@ class ActiveBlobJournalKey(BaseIndexedDBKey):
|
|
|
517
541
|
|
|
518
542
|
@classmethod
|
|
519
543
|
def FromDecoder(
|
|
520
|
-
cls,
|
|
544
|
+
cls,
|
|
545
|
+
decoder: utils.LevelDBDecoder,
|
|
546
|
+
key_prefix: KeyPrefix,
|
|
521
547
|
base_offset: int = 0
|
|
522
548
|
) -> ActiveBlobJournalKey:
|
|
523
549
|
"""Decodes the active blob journal value."""
|
|
@@ -538,7 +564,9 @@ class EarliestSweepKey(BaseIndexedDBKey):
|
|
|
538
564
|
|
|
539
565
|
@classmethod
|
|
540
566
|
def FromDecoder(
|
|
541
|
-
cls,
|
|
567
|
+
cls,
|
|
568
|
+
decoder: utils.LevelDBDecoder,
|
|
569
|
+
key_prefix: KeyPrefix,
|
|
542
570
|
base_offset: int = 0
|
|
543
571
|
) -> EarliestSweepKey:
|
|
544
572
|
"""Decodes the earliest sweep value."""
|
|
@@ -559,7 +587,9 @@ class EarliestCompactionTimeKey(BaseIndexedDBKey):
|
|
|
559
587
|
|
|
560
588
|
@classmethod
|
|
561
589
|
def FromDecoder(
|
|
562
|
-
cls,
|
|
590
|
+
cls,
|
|
591
|
+
decoder: utils.LevelDBDecoder,
|
|
592
|
+
key_prefix: KeyPrefix,
|
|
563
593
|
base_offset: int = 0
|
|
564
594
|
) -> EarliestCompactionTimeKey:
|
|
565
595
|
"""Decodes the earliest compaction time key."""
|
|
@@ -581,7 +611,9 @@ class ScopesPrefixKey(BaseIndexedDBKey):
|
|
|
581
611
|
|
|
582
612
|
@classmethod
|
|
583
613
|
def FromDecoder(
|
|
584
|
-
cls,
|
|
614
|
+
cls,
|
|
615
|
+
decoder: utils.LevelDBDecoder,
|
|
616
|
+
key_prefix: KeyPrefix,
|
|
585
617
|
base_offset: int = 0
|
|
586
618
|
) -> ScopesPrefixKey:
|
|
587
619
|
"""Decodes the scopes prefix key."""
|
|
@@ -606,7 +638,9 @@ class DatabaseFreeListKey(BaseIndexedDBKey):
|
|
|
606
638
|
|
|
607
639
|
@classmethod
|
|
608
640
|
def FromDecoder(
|
|
609
|
-
cls,
|
|
641
|
+
cls,
|
|
642
|
+
decoder: utils.LevelDBDecoder,
|
|
643
|
+
key_prefix: KeyPrefix,
|
|
610
644
|
base_offset: int = 0
|
|
611
645
|
) -> DatabaseFreeListKey:
|
|
612
646
|
"""Decodes the database free list key."""
|
|
@@ -635,11 +669,13 @@ class DatabaseNameKey(BaseIndexedDBKey):
|
|
|
635
669
|
|
|
636
670
|
The value is the corresponding database ID.
|
|
637
671
|
"""
|
|
638
|
-
return decoder.
|
|
672
|
+
return decoder.DecodeInt()[1]
|
|
639
673
|
|
|
640
674
|
@classmethod
|
|
641
675
|
def FromDecoder(
|
|
642
|
-
cls,
|
|
676
|
+
cls,
|
|
677
|
+
decoder: utils.LevelDBDecoder,
|
|
678
|
+
key_prefix: KeyPrefix,
|
|
643
679
|
base_offset: int = 0
|
|
644
680
|
) -> DatabaseNameKey:
|
|
645
681
|
"""Decodes the database name key."""
|
|
@@ -659,25 +695,26 @@ class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
|
659
695
|
|
|
660
696
|
METADATA_TYPE_TO_CLASS = {
|
|
661
697
|
definitions.GlobalMetadataKeyType
|
|
662
|
-
.
|
|
698
|
+
.ACTIVE_BLOB_JOURNAL: ActiveBlobJournalKey,
|
|
663
699
|
definitions.GlobalMetadataKeyType
|
|
664
|
-
|
|
700
|
+
.DATA_VERSION: DataVersionKey,
|
|
665
701
|
definitions.GlobalMetadataKeyType
|
|
666
|
-
.
|
|
702
|
+
.DATABASE_FREE_LIST: DatabaseFreeListKey,
|
|
667
703
|
definitions.GlobalMetadataKeyType
|
|
668
|
-
.
|
|
704
|
+
.DATABASE_NAME: DatabaseNameKey,
|
|
669
705
|
definitions.GlobalMetadataKeyType
|
|
670
|
-
.
|
|
706
|
+
.EARLIEST_COMPACTION_TIME: EarliestCompactionTimeKey,
|
|
671
707
|
definitions.GlobalMetadataKeyType
|
|
672
708
|
.EARLIEST_SWEEP: EarliestSweepKey,
|
|
673
709
|
definitions.GlobalMetadataKeyType
|
|
674
|
-
.
|
|
710
|
+
.MAX_DATABASE_ID: MaxDatabaseIdKey,
|
|
675
711
|
definitions.GlobalMetadataKeyType
|
|
676
|
-
.
|
|
712
|
+
.RECOVERY_BLOB_JOURNAL: RecoveryBlobJournalKey,
|
|
677
713
|
definitions.GlobalMetadataKeyType
|
|
678
|
-
.
|
|
714
|
+
.SCHEMA_VERSION: SchemaVersionKey,
|
|
679
715
|
definitions.GlobalMetadataKeyType
|
|
680
|
-
.
|
|
716
|
+
.SCOPES_PREFIX: ScopesPrefixKey,
|
|
717
|
+
}
|
|
681
718
|
|
|
682
719
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
683
720
|
"""Decodes the value from the current position of the LevelDBDecoder.
|
|
@@ -688,18 +725,20 @@ class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
|
688
725
|
|
|
689
726
|
@classmethod
|
|
690
727
|
def FromDecoder(
|
|
691
|
-
cls,
|
|
728
|
+
cls,
|
|
729
|
+
decoder: utils.LevelDBDecoder,
|
|
730
|
+
key_prefix: KeyPrefix,
|
|
692
731
|
base_offset: int = 0
|
|
693
|
-
) -> Union[
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
732
|
+
) -> Union[ActiveBlobJournalKey,
|
|
733
|
+
DataVersionKey,
|
|
734
|
+
DatabaseFreeListKey,
|
|
735
|
+
DatabaseNameKey,
|
|
736
|
+
EarliestSweepKey,
|
|
737
|
+
EarliestCompactionTimeKey,
|
|
738
|
+
MaxDatabaseIdKey,
|
|
739
|
+
RecoveryBlobJournalKey,
|
|
740
|
+
SchemaVersionKey,
|
|
741
|
+
ScopesPrefixKey]:
|
|
703
742
|
"""Decodes the global metadata key.
|
|
704
743
|
|
|
705
744
|
Raises:
|
|
@@ -712,7 +751,7 @@ class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
|
712
751
|
if not key_class:
|
|
713
752
|
raise errors.ParserError('Unknown metadata key type')
|
|
714
753
|
return key_class.FromDecoder(
|
|
715
|
-
decoder, key_prefix, base_offset)
|
|
754
|
+
decoder, key_prefix, base_offset)
|
|
716
755
|
|
|
717
756
|
|
|
718
757
|
@dataclass
|
|
@@ -730,7 +769,9 @@ class ObjectStoreFreeListKey(BaseIndexedDBKey):
|
|
|
730
769
|
|
|
731
770
|
@classmethod
|
|
732
771
|
def FromDecoder(
|
|
733
|
-
cls,
|
|
772
|
+
cls,
|
|
773
|
+
decoder: utils.LevelDBDecoder,
|
|
774
|
+
key_prefix: KeyPrefix,
|
|
734
775
|
base_offset: int = 0
|
|
735
776
|
) -> ObjectStoreFreeListKey:
|
|
736
777
|
"""Decodes the object store free list key."""
|
|
@@ -758,7 +799,9 @@ class IndexFreeListKey(BaseIndexedDBKey):
|
|
|
758
799
|
|
|
759
800
|
@classmethod
|
|
760
801
|
def FromDecoder(
|
|
761
|
-
cls,
|
|
802
|
+
cls,
|
|
803
|
+
decoder: utils.LevelDBDecoder,
|
|
804
|
+
key_prefix: KeyPrefix,
|
|
762
805
|
base_offset: int = 0
|
|
763
806
|
) -> IndexFreeListKey:
|
|
764
807
|
"""Decodes the index free list key."""
|
|
@@ -782,11 +825,14 @@ class ObjectStoreNamesKey(BaseIndexedDBKey):
|
|
|
782
825
|
|
|
783
826
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
784
827
|
"""Decodes the object store names value."""
|
|
785
|
-
return decoder.
|
|
828
|
+
return decoder.DecodeInt()[1]
|
|
786
829
|
|
|
787
830
|
@classmethod
|
|
788
|
-
def FromDecoder(
|
|
789
|
-
|
|
831
|
+
def FromDecoder(
|
|
832
|
+
cls, decoder: utils.LevelDBDecoder,
|
|
833
|
+
key_prefix: KeyPrefix,
|
|
834
|
+
base_offset: int = 0
|
|
835
|
+
) -> ObjectStoreNamesKey:
|
|
790
836
|
"""Decodes the object store names key."""
|
|
791
837
|
offset, key_type = decoder.DecodeUint8()
|
|
792
838
|
if key_type != definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES:
|
|
@@ -807,11 +853,15 @@ class IndexNamesKey(BaseIndexedDBKey):
|
|
|
807
853
|
|
|
808
854
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
809
855
|
"""Decodes the index names value."""
|
|
810
|
-
return decoder.
|
|
856
|
+
return decoder.DecodeInt()[1]
|
|
811
857
|
|
|
812
858
|
@classmethod
|
|
813
|
-
def FromDecoder(
|
|
814
|
-
|
|
859
|
+
def FromDecoder(
|
|
860
|
+
cls,
|
|
861
|
+
decoder: utils.LevelDBDecoder,
|
|
862
|
+
key_prefix: KeyPrefix,
|
|
863
|
+
base_offset: int = 0
|
|
864
|
+
) -> IndexNamesKey:
|
|
815
865
|
"""Decodes the index names key."""
|
|
816
866
|
offset, key_type = decoder.DecodeUint8()
|
|
817
867
|
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_NAMES:
|
|
@@ -844,7 +894,7 @@ class DatabaseMetaDataKey(BaseIndexedDBKey):
|
|
|
844
894
|
return decoder.DecodeString()[1]
|
|
845
895
|
if (self.metadata_type ==
|
|
846
896
|
definitions.DatabaseMetaDataKeyType.MAX_ALLOCATED_OBJECT_STORE_ID):
|
|
847
|
-
return decoder.
|
|
897
|
+
return decoder.DecodeInt()[1]
|
|
848
898
|
if (self.metadata_type ==
|
|
849
899
|
definitions.DatabaseMetaDataKeyType.IDB_INTEGER_VERSION):
|
|
850
900
|
return decoder.DecodeVarint()[1]
|
|
@@ -919,7 +969,9 @@ class ObjectStoreMetaDataKey(BaseIndexedDBKey):
|
|
|
919
969
|
metadata_type: definitions.ObjectStoreMetaDataKeyType
|
|
920
970
|
|
|
921
971
|
def DecodeValue(
|
|
922
|
-
self,
|
|
972
|
+
self,
|
|
973
|
+
decoder: utils.LevelDBDecoder
|
|
974
|
+
) -> Union[IDBKeyPath, str, bool, int]:
|
|
923
975
|
"""Decodes the object store metadata value."""
|
|
924
976
|
if (self.metadata_type ==
|
|
925
977
|
definitions.ObjectStoreMetaDataKeyType.OBJECT_STORE_NAME):
|
|
@@ -948,7 +1000,9 @@ class ObjectStoreMetaDataKey(BaseIndexedDBKey):
|
|
|
948
1000
|
|
|
949
1001
|
@classmethod
|
|
950
1002
|
def FromDecoder(
|
|
951
|
-
cls,
|
|
1003
|
+
cls,
|
|
1004
|
+
decoder: utils.LevelDBDecoder,
|
|
1005
|
+
key_prefix: KeyPrefix,
|
|
952
1006
|
base_offset: int = 0
|
|
953
1007
|
) -> ObjectStoreMetaDataKey:
|
|
954
1008
|
"""Decodes the object store metadata key."""
|
|
@@ -969,13 +1023,13 @@ class ObjectStoreDataValue:
|
|
|
969
1023
|
"""The parsed values from an ObjectStoreDataKey.
|
|
970
1024
|
|
|
971
1025
|
Attributes:
|
|
972
|
-
|
|
1026
|
+
version: the version prefix.
|
|
973
1027
|
is_wrapped: True if the value was wrapped.
|
|
974
1028
|
blob_size: the blob size, only valid if wrapped.
|
|
975
1029
|
blob_offset: the blob offset, only valid if wrapped.
|
|
976
1030
|
value: the blink serialized value, only valid if not wrapped.
|
|
977
1031
|
"""
|
|
978
|
-
|
|
1032
|
+
version: int
|
|
979
1033
|
is_wrapped: bool
|
|
980
1034
|
blob_size: Optional[int]
|
|
981
1035
|
blob_offset: Optional[int]
|
|
@@ -992,37 +1046,54 @@ class ObjectStoreDataKey(BaseIndexedDBKey):
|
|
|
992
1046
|
encoded_user_key: IDBKey
|
|
993
1047
|
|
|
994
1048
|
def DecodeValue(
|
|
995
|
-
self,
|
|
1049
|
+
self,
|
|
1050
|
+
decoder: utils.LevelDBDecoder
|
|
1051
|
+
) -> ObjectStoreDataValue:
|
|
996
1052
|
"""Decodes the object store data value."""
|
|
997
|
-
_,
|
|
1053
|
+
_, version = decoder.DecodeVarint()
|
|
998
1054
|
|
|
999
1055
|
_, wrapped_header_bytes = decoder.PeekBytes(3)
|
|
1000
1056
|
if len(wrapped_header_bytes) != 3:
|
|
1001
1057
|
raise errors.DecoderError('Insufficient bytes')
|
|
1002
1058
|
|
|
1003
|
-
if (wrapped_header_bytes[0] ==
|
|
1004
|
-
|
|
1005
|
-
wrapped_header_bytes[
|
|
1059
|
+
if (wrapped_header_bytes[0] ==
|
|
1060
|
+
definitions.BlinkSerializationTag.VERSION and
|
|
1061
|
+
wrapped_header_bytes[1] ==
|
|
1062
|
+
definitions.REQUIRES_PROCESSING_SSV_PSEUDO_VERSION and
|
|
1063
|
+
wrapped_header_bytes[2] == definitions.REPLACE_WITH_BLOB):
|
|
1064
|
+
_ = decoder.ReadBytes(3)
|
|
1006
1065
|
_, blob_size = decoder.DecodeVarint()
|
|
1007
1066
|
_, blob_offset = decoder.DecodeVarint()
|
|
1008
1067
|
return ObjectStoreDataValue(
|
|
1009
|
-
|
|
1068
|
+
version=version,
|
|
1010
1069
|
is_wrapped=True,
|
|
1011
1070
|
blob_size=blob_size,
|
|
1012
1071
|
blob_offset=blob_offset,
|
|
1013
1072
|
value=None)
|
|
1014
1073
|
_, blink_bytes = decoder.ReadBytes()
|
|
1074
|
+
is_wrapped = False
|
|
1075
|
+
if (
|
|
1076
|
+
wrapped_header_bytes[0] ==
|
|
1077
|
+
definitions.BlinkSerializationTag.VERSION and
|
|
1078
|
+
wrapped_header_bytes[1] ==
|
|
1079
|
+
definitions.REQUIRES_PROCESSING_SSV_PSEUDO_VERSION and
|
|
1080
|
+
wrapped_header_bytes[2] == definitions.COMPRESSED_WITH_SNAPPY):
|
|
1081
|
+
is_wrapped = True
|
|
1082
|
+
# ignore the wrapped header bytes when decompressing
|
|
1083
|
+
blink_bytes = snappy.decompress(blink_bytes[3:])
|
|
1015
1084
|
blink_value = blink.V8ScriptValueDecoder.FromBytes(blink_bytes)
|
|
1016
1085
|
return ObjectStoreDataValue(
|
|
1017
|
-
|
|
1018
|
-
is_wrapped=
|
|
1086
|
+
version=version,
|
|
1087
|
+
is_wrapped=is_wrapped,
|
|
1019
1088
|
blob_size=None,
|
|
1020
1089
|
blob_offset=None,
|
|
1021
1090
|
value=blink_value)
|
|
1022
1091
|
|
|
1023
1092
|
@classmethod
|
|
1024
1093
|
def FromDecoder(
|
|
1025
|
-
cls,
|
|
1094
|
+
cls,
|
|
1095
|
+
decoder: utils.LevelDBDecoder,
|
|
1096
|
+
key_prefix: KeyPrefix,
|
|
1026
1097
|
base_offset: int = 0
|
|
1027
1098
|
) -> ObjectStoreDataKey:
|
|
1028
1099
|
"""Decodes the object store data key."""
|
|
@@ -1052,13 +1123,14 @@ class ExistsEntryKey(BaseIndexedDBKey):
|
|
|
1052
1123
|
|
|
1053
1124
|
@classmethod
|
|
1054
1125
|
def FromDecoder(
|
|
1055
|
-
cls,
|
|
1126
|
+
cls,
|
|
1127
|
+
decoder: utils.LevelDBDecoder,
|
|
1128
|
+
key_prefix: KeyPrefix,
|
|
1056
1129
|
base_offset: int = 0
|
|
1057
1130
|
) -> ExistsEntryKey:
|
|
1058
1131
|
"""Decodes the exists entry key."""
|
|
1059
1132
|
offset = decoder.stream.tell()
|
|
1060
1133
|
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1061
|
-
|
|
1062
1134
|
return cls(
|
|
1063
1135
|
offset=base_offset + offset,
|
|
1064
1136
|
key_prefix=key_prefix, encoded_user_key=encoded_user_key)
|
|
@@ -1084,8 +1156,12 @@ class IndexDataKey(BaseIndexedDBKey):
|
|
|
1084
1156
|
return version, idb_key
|
|
1085
1157
|
|
|
1086
1158
|
@classmethod
|
|
1087
|
-
def FromDecoder(
|
|
1088
|
-
|
|
1159
|
+
def FromDecoder(
|
|
1160
|
+
cls,
|
|
1161
|
+
decoder: utils.LevelDBDecoder,
|
|
1162
|
+
key_prefix: KeyPrefix,
|
|
1163
|
+
base_offset: int = 0
|
|
1164
|
+
) -> IndexDataKey:
|
|
1089
1165
|
"""Decodes the index data key."""
|
|
1090
1166
|
offset = decoder.stream.tell()
|
|
1091
1167
|
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
@@ -1120,13 +1196,17 @@ class BlobEntryKey(BaseIndexedDBKey):
|
|
|
1120
1196
|
user_key: IDBKey
|
|
1121
1197
|
|
|
1122
1198
|
def DecodeValue(
|
|
1123
|
-
self,
|
|
1199
|
+
self,
|
|
1200
|
+
decoder: utils.LevelDBDecoder
|
|
1201
|
+
) -> IndexedDBExternalObject:
|
|
1124
1202
|
"""Decodes the blob entry value."""
|
|
1125
1203
|
return IndexedDBExternalObject.FromDecoder(decoder)
|
|
1126
1204
|
|
|
1127
1205
|
@classmethod
|
|
1128
1206
|
def FromDecoder(
|
|
1129
|
-
cls,
|
|
1207
|
+
cls,
|
|
1208
|
+
decoder: utils.LevelDBDecoder,
|
|
1209
|
+
key_prefix: KeyPrefix,
|
|
1130
1210
|
base_offset: int = 0
|
|
1131
1211
|
) -> BlobEntryKey:
|
|
1132
1212
|
"""Decodes the blob entry key."""
|
|
@@ -1145,13 +1225,13 @@ class IndexedDbKey(BaseIndexedDBKey):
|
|
|
1145
1225
|
"""
|
|
1146
1226
|
|
|
1147
1227
|
METADATA_TYPE_TO_CLASS = {
|
|
1148
|
-
definitions.KeyPrefixType.
|
|
1228
|
+
definitions.KeyPrefixType.BLOB_ENTRY: BlobEntryKey,
|
|
1149
1229
|
definitions.KeyPrefixType.DATABASE_METADATA: DatabaseMetaDataKey,
|
|
1150
|
-
definitions.KeyPrefixType.OBJECT_STORE_DATA: ObjectStoreDataKey,
|
|
1151
1230
|
definitions.KeyPrefixType.EXISTS_ENTRY: ExistsEntryKey,
|
|
1231
|
+
definitions.KeyPrefixType.GLOBAL_METADATA: GlobalMetaDataKey,
|
|
1232
|
+
definitions.KeyPrefixType.INVALID_TYPE: None,
|
|
1152
1233
|
definitions.KeyPrefixType.INDEX_DATA: IndexDataKey,
|
|
1153
|
-
definitions.KeyPrefixType.
|
|
1154
|
-
definitions.KeyPrefixType.INVALID_TYPE: None
|
|
1234
|
+
definitions.KeyPrefixType.OBJECT_STORE_DATA: ObjectStoreDataKey,
|
|
1155
1235
|
}
|
|
1156
1236
|
|
|
1157
1237
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
@@ -1167,9 +1247,13 @@ class IndexedDbKey(BaseIndexedDBKey):
|
|
|
1167
1247
|
decoder: utils.LevelDBDecoder,
|
|
1168
1248
|
key_prefix: KeyPrefix,
|
|
1169
1249
|
base_offset: int = 0
|
|
1170
|
-
) -> Union[
|
|
1171
|
-
|
|
1172
|
-
|
|
1250
|
+
) -> Union[
|
|
1251
|
+
BlobEntryKey,
|
|
1252
|
+
DatabaseMetaDataKey,
|
|
1253
|
+
ExistsEntryKey,
|
|
1254
|
+
GlobalMetaDataKey,
|
|
1255
|
+
IndexDataKey,
|
|
1256
|
+
ObjectStoreDataKey]:
|
|
1173
1257
|
"""Decodes the IndexedDB key."""
|
|
1174
1258
|
key_type = key_prefix.GetKeyPrefixType()
|
|
1175
1259
|
key_class = cls.METADATA_TYPE_TO_CLASS.get(key_type)
|
|
@@ -1195,7 +1279,9 @@ class IndexMetaDataKey(BaseIndexedDBKey):
|
|
|
1195
1279
|
metadata_type: definitions.IndexMetaDataKeyType
|
|
1196
1280
|
|
|
1197
1281
|
def DecodeValue(
|
|
1198
|
-
self,
|
|
1282
|
+
self,
|
|
1283
|
+
decoder: utils.LevelDBDecoder
|
|
1284
|
+
) -> Union[bool, IDBKeyPath, str]:
|
|
1199
1285
|
"""Decodes the index metadata value."""
|
|
1200
1286
|
if self.metadata_type == definitions.IndexMetaDataKeyType.INDEX_NAME:
|
|
1201
1287
|
return decoder.DecodeString()[1]
|
|
@@ -1213,7 +1299,8 @@ class IndexMetaDataKey(BaseIndexedDBKey):
|
|
|
1213
1299
|
def FromDecoder(
|
|
1214
1300
|
cls,
|
|
1215
1301
|
decoder: utils.LevelDBDecoder,
|
|
1216
|
-
key_prefix: KeyPrefix,
|
|
1302
|
+
key_prefix: KeyPrefix,
|
|
1303
|
+
base_offset: int = 0
|
|
1217
1304
|
) -> IndexMetaDataKey:
|
|
1218
1305
|
"""Decodes the index metadata key."""
|
|
1219
1306
|
offset, key_type = decoder.DecodeUint8()
|
|
@@ -1402,21 +1489,21 @@ class FolderReader:
|
|
|
1402
1489
|
"""A IndexedDB folder reader for Chrome/Chromium.
|
|
1403
1490
|
|
|
1404
1491
|
Attributes:
|
|
1405
|
-
|
|
1492
|
+
folder_name (str): the source LevelDB folder.
|
|
1406
1493
|
"""
|
|
1407
1494
|
|
|
1408
|
-
def __init__(self,
|
|
1495
|
+
def __init__(self, folder_name: pathlib.Path):
|
|
1409
1496
|
"""Initializes the FileReader.
|
|
1410
1497
|
|
|
1411
1498
|
Args:
|
|
1412
|
-
|
|
1499
|
+
folder_name: the source IndexedDB folder.
|
|
1413
1500
|
|
|
1414
1501
|
Raises:
|
|
1415
|
-
ValueError: if
|
|
1502
|
+
ValueError: if folder_name is None or not a directory.
|
|
1416
1503
|
"""
|
|
1417
|
-
if not
|
|
1418
|
-
raise ValueError(f'{
|
|
1419
|
-
self.
|
|
1504
|
+
if not folder_name or not folder_name.is_dir():
|
|
1505
|
+
raise ValueError(f'{folder_name} is None or not a directory')
|
|
1506
|
+
self.folder_name = folder_name
|
|
1420
1507
|
|
|
1421
1508
|
def GetRecords(
|
|
1422
1509
|
self,
|
|
@@ -1432,13 +1519,12 @@ class FolderReader:
|
|
|
1432
1519
|
Yields:
|
|
1433
1520
|
IndexedDBRecord.
|
|
1434
1521
|
"""
|
|
1435
|
-
leveldb_folder_reader = record.FolderReader(self.
|
|
1522
|
+
leveldb_folder_reader = record.FolderReader(self.folder_name)
|
|
1436
1523
|
for leveldb_record in leveldb_folder_reader.GetRecords(
|
|
1437
1524
|
use_manifest=use_manifest,
|
|
1438
1525
|
use_sequence_number=use_sequence_number):
|
|
1439
1526
|
try:
|
|
1440
|
-
yield IndexedDBRecord.FromLevelDBRecord(
|
|
1441
|
-
leveldb_record)
|
|
1527
|
+
yield IndexedDBRecord.FromLevelDBRecord(leveldb_record)
|
|
1442
1528
|
except(
|
|
1443
1529
|
errors.ParserError,
|
|
1444
1530
|
errors.DecoderError,
|