dfindexeddb 20241105__py3-none-any.whl → 20260205__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.
- dfindexeddb/indexeddb/chromium/blink.py +116 -74
- dfindexeddb/indexeddb/chromium/definitions.py +240 -125
- dfindexeddb/indexeddb/chromium/record.py +651 -346
- dfindexeddb/indexeddb/chromium/sqlite.py +362 -0
- dfindexeddb/indexeddb/chromium/v8.py +100 -78
- dfindexeddb/indexeddb/cli.py +282 -121
- dfindexeddb/indexeddb/firefox/definitions.py +7 -4
- dfindexeddb/indexeddb/firefox/gecko.py +98 -74
- dfindexeddb/indexeddb/firefox/record.py +78 -26
- dfindexeddb/indexeddb/safari/definitions.py +5 -3
- dfindexeddb/indexeddb/safari/record.py +86 -53
- dfindexeddb/indexeddb/safari/webkit.py +85 -71
- dfindexeddb/indexeddb/types.py +4 -1
- dfindexeddb/leveldb/cli.py +146 -138
- dfindexeddb/leveldb/definitions.py +6 -2
- dfindexeddb/leveldb/descriptor.py +70 -56
- dfindexeddb/leveldb/ldb.py +39 -33
- dfindexeddb/leveldb/log.py +41 -30
- dfindexeddb/leveldb/plugins/chrome_notifications.py +30 -18
- dfindexeddb/leveldb/plugins/interface.py +5 -6
- dfindexeddb/leveldb/plugins/manager.py +10 -9
- dfindexeddb/leveldb/record.py +71 -62
- dfindexeddb/leveldb/utils.py +105 -13
- dfindexeddb/utils.py +36 -31
- dfindexeddb/version.py +2 -2
- dfindexeddb-20260205.dist-info/METADATA +171 -0
- dfindexeddb-20260205.dist-info/RECORD +41 -0
- {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info}/WHEEL +1 -1
- dfindexeddb-20241105.dist-info/AUTHORS +0 -12
- dfindexeddb-20241105.dist-info/METADATA +0 -424
- dfindexeddb-20241105.dist-info/RECORD +0 -41
- {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info}/entry_points.txt +0 -0
- {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info/licenses}/LICENSE +0 -0
- {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info}/top_level.txt +0 -0
dfindexeddb/indexeddb/cli.py
CHANGED
|
@@ -16,28 +16,30 @@
|
|
|
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
|
+
from dfindexeddb.indexeddb.chromium import sqlite
|
|
27
28
|
from dfindexeddb.indexeddb.chromium import record as chromium_record
|
|
28
29
|
from dfindexeddb.indexeddb.firefox import gecko
|
|
29
30
|
from dfindexeddb.indexeddb.firefox import record as firefox_record
|
|
30
31
|
from dfindexeddb.indexeddb.safari import record as safari_record
|
|
31
32
|
|
|
32
|
-
|
|
33
33
|
_VALID_PRINTABLE_CHARACTERS = (
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
35
|
+
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~."
|
|
36
|
+
)
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
class Encoder(json.JSONEncoder):
|
|
39
40
|
"""A JSON encoder class for dfindexeddb fields."""
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
def default(self, o): # type: ignore[no-untyped-def]
|
|
41
43
|
if dataclasses.is_dataclass(o):
|
|
42
44
|
o_dict = utils.asdict(o)
|
|
43
45
|
return o_dict
|
|
@@ -45,18 +47,18 @@ class Encoder(json.JSONEncoder):
|
|
|
45
47
|
out = []
|
|
46
48
|
for x in o:
|
|
47
49
|
if chr(x) not in _VALID_PRINTABLE_CHARACTERS:
|
|
48
|
-
out.append(f
|
|
50
|
+
out.append(f"\\x{x:02X}")
|
|
49
51
|
else:
|
|
50
52
|
out.append(chr(x))
|
|
51
|
-
return
|
|
53
|
+
return "".join(out)
|
|
52
54
|
if isinstance(o, datetime):
|
|
53
55
|
return o.isoformat()
|
|
54
56
|
if isinstance(o, types.Undefined):
|
|
55
|
-
return
|
|
57
|
+
return "<undefined>"
|
|
56
58
|
if isinstance(o, types.JSArray):
|
|
57
59
|
return o.__dict__
|
|
58
60
|
if isinstance(o, types.Null):
|
|
59
|
-
return
|
|
61
|
+
return "<null>"
|
|
60
62
|
if isinstance(o, set):
|
|
61
63
|
return list(o)
|
|
62
64
|
if isinstance(o, types.RegExp):
|
|
@@ -66,189 +68,348 @@ class Encoder(json.JSONEncoder):
|
|
|
66
68
|
return json.JSONEncoder.default(self, o)
|
|
67
69
|
|
|
68
70
|
|
|
69
|
-
def _Output(structure, output):
|
|
70
|
-
"""Helper method to output parsed structure to stdout.
|
|
71
|
-
|
|
71
|
+
def _Output(structure: Any, output: str) -> None:
|
|
72
|
+
"""Helper method to output parsed structure to stdout.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
structure: The structure to output.
|
|
76
|
+
output: The output format.
|
|
77
|
+
"""
|
|
78
|
+
if output == "json":
|
|
72
79
|
print(json.dumps(structure, indent=2, cls=Encoder))
|
|
73
|
-
elif output ==
|
|
80
|
+
elif output == "jsonl":
|
|
74
81
|
print(json.dumps(structure, cls=Encoder))
|
|
75
|
-
elif output ==
|
|
82
|
+
elif output == "repr":
|
|
76
83
|
print(structure)
|
|
77
84
|
|
|
78
85
|
|
|
79
|
-
def BlinkCommand(args):
|
|
86
|
+
def BlinkCommand(args: argparse.Namespace) -> None:
|
|
80
87
|
"""The CLI for processing a file as a blink-encoded value."""
|
|
81
|
-
with open(args.source,
|
|
88
|
+
with open(args.source, "rb") as fd:
|
|
82
89
|
buffer = fd.read()
|
|
83
90
|
blink_value = blink.V8ScriptValueDecoder.FromBytes(buffer)
|
|
84
91
|
_Output(blink_value, output=args.output)
|
|
85
92
|
|
|
86
93
|
|
|
87
|
-
def GeckoCommand(args):
|
|
94
|
+
def GeckoCommand(args: argparse.Namespace) -> None:
|
|
88
95
|
"""The CLI for processing a file as a gecko-encoded value."""
|
|
89
|
-
with open(args.source,
|
|
96
|
+
with open(args.source, "rb") as fd:
|
|
90
97
|
buffer = fd.read()
|
|
91
98
|
blink_value = gecko.JSStructuredCloneDecoder.FromBytes(buffer)
|
|
92
99
|
_Output(blink_value, output=args.output)
|
|
93
100
|
|
|
94
101
|
|
|
95
|
-
def DbCommand(args):
|
|
102
|
+
def DbCommand(args: argparse.Namespace) -> None:
|
|
96
103
|
"""The CLI for processing a directory as IndexedDB."""
|
|
97
|
-
if args.format in (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
if args.format in ("chrome", "chromium"):
|
|
105
|
+
if args.source.is_file():
|
|
106
|
+
if args.object_store_id is not None:
|
|
107
|
+
records = sqlite.DatabaseReader(
|
|
108
|
+
str(args.source)
|
|
109
|
+
).RecordsByObjectStoreId(
|
|
110
|
+
args.object_store_id, include_raw_data=args.include_raw_data
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
records = sqlite.DatabaseReader(str(args.source)).Records(
|
|
114
|
+
include_raw_data=args.include_raw_data
|
|
115
|
+
)
|
|
116
|
+
for chromium_db_record in records:
|
|
117
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
118
|
+
chromium_db_record.value
|
|
119
|
+
):
|
|
120
|
+
continue
|
|
121
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
122
|
+
chromium_db_record.key.value
|
|
123
|
+
):
|
|
124
|
+
continue
|
|
125
|
+
_Output(chromium_db_record, output=args.output)
|
|
126
|
+
else:
|
|
127
|
+
for chromium_leveldb_record in chromium_record.FolderReader(
|
|
128
|
+
args.source
|
|
129
|
+
).GetRecords(
|
|
130
|
+
use_manifest=args.use_manifest,
|
|
131
|
+
use_sequence_number=args.use_sequence_number,
|
|
132
|
+
):
|
|
133
|
+
if (
|
|
134
|
+
args.object_store_id is not None
|
|
135
|
+
and chromium_leveldb_record.object_store_id != args.object_store_id
|
|
136
|
+
):
|
|
137
|
+
continue
|
|
138
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
139
|
+
chromium_leveldb_record.value
|
|
140
|
+
):
|
|
141
|
+
continue
|
|
142
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
143
|
+
chromium_leveldb_record.key.value
|
|
144
|
+
):
|
|
145
|
+
continue
|
|
146
|
+
_Output(chromium_leveldb_record, output=args.output)
|
|
147
|
+
elif args.format == "firefox":
|
|
148
|
+
if args.object_store_id is not None:
|
|
149
|
+
firefox_db_records = firefox_record.FileReader(
|
|
150
|
+
str(args.source)
|
|
151
|
+
).RecordsByObjectStoreId(
|
|
152
|
+
args.object_store_id, include_raw_data=args.include_raw_data
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
firefox_db_records = firefox_record.FileReader(str(args.source)).Records(
|
|
156
|
+
include_raw_data=args.include_raw_data
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
for firefox_db_record in firefox_db_records:
|
|
160
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
161
|
+
firefox_db_record.value
|
|
162
|
+
):
|
|
163
|
+
continue
|
|
164
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
165
|
+
firefox_db_record.key.value
|
|
166
|
+
):
|
|
167
|
+
continue
|
|
168
|
+
_Output(firefox_db_record, output=args.output)
|
|
169
|
+
elif args.format == "safari":
|
|
170
|
+
if args.object_store_id is not None:
|
|
171
|
+
safari_db_records = safari_record.FileReader(
|
|
172
|
+
str(args.source)
|
|
173
|
+
).RecordsByObjectStoreId(
|
|
174
|
+
args.object_store_id, include_raw_data=args.include_raw_data
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
safari_db_records = safari_record.FileReader(str(args.source)).Records(
|
|
178
|
+
include_raw_data=args.include_raw_data
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
for safari_db_record in safari_db_records:
|
|
182
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
183
|
+
safari_db_record.value
|
|
184
|
+
):
|
|
185
|
+
continue
|
|
186
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
187
|
+
safari_db_record.key
|
|
188
|
+
):
|
|
189
|
+
continue
|
|
190
|
+
_Output(safari_db_record, output=args.output)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def LdbCommand(args: argparse.Namespace) -> None:
|
|
112
194
|
"""The CLI for processing a LevelDB table (.ldb) file as IndexedDB."""
|
|
113
|
-
for db_record in chromium_record.
|
|
195
|
+
for db_record in chromium_record.ChromiumIndexedDBRecord.FromFile(
|
|
196
|
+
args.source
|
|
197
|
+
):
|
|
198
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
199
|
+
db_record.value
|
|
200
|
+
):
|
|
201
|
+
continue
|
|
202
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
203
|
+
db_record.key
|
|
204
|
+
):
|
|
205
|
+
continue
|
|
114
206
|
_Output(db_record, output=args.output)
|
|
115
207
|
|
|
116
208
|
|
|
117
|
-
def LogCommand(args):
|
|
209
|
+
def LogCommand(args: argparse.Namespace) -> None:
|
|
118
210
|
"""The CLI for processing a LevelDB log file as IndexedDB."""
|
|
119
|
-
for db_record in chromium_record.
|
|
211
|
+
for db_record in chromium_record.ChromiumIndexedDBRecord.FromFile(
|
|
212
|
+
args.source
|
|
213
|
+
):
|
|
214
|
+
if args.filter_value is not None and args.filter_value not in str(
|
|
215
|
+
db_record.value
|
|
216
|
+
):
|
|
217
|
+
continue
|
|
218
|
+
if args.filter_key is not None and args.filter_key not in str(
|
|
219
|
+
db_record.key
|
|
220
|
+
):
|
|
221
|
+
continue
|
|
120
222
|
_Output(db_record, output=args.output)
|
|
121
223
|
|
|
122
224
|
|
|
123
|
-
def App():
|
|
225
|
+
def App() -> None:
|
|
124
226
|
"""The CLI app entrypoint for dfindexeddb."""
|
|
125
227
|
parser = argparse.ArgumentParser(
|
|
126
|
-
prog=
|
|
127
|
-
description=
|
|
128
|
-
epilog=f
|
|
228
|
+
prog="dfindexeddb",
|
|
229
|
+
description="A cli tool for parsing IndexedDB files",
|
|
230
|
+
epilog=f"Version {version.GetVersion()}",
|
|
231
|
+
)
|
|
129
232
|
|
|
130
233
|
subparsers = parser.add_subparsers()
|
|
131
234
|
|
|
132
235
|
parser_blink = subparsers.add_parser(
|
|
133
|
-
|
|
236
|
+
"blink", help="Parse a file as a blink-encoded value."
|
|
237
|
+
)
|
|
134
238
|
parser_blink.add_argument(
|
|
135
|
-
|
|
136
|
-
|
|
239
|
+
"-s",
|
|
240
|
+
"--source",
|
|
137
241
|
required=True,
|
|
138
242
|
type=pathlib.Path,
|
|
139
|
-
help=
|
|
243
|
+
help="The source file.",
|
|
244
|
+
)
|
|
140
245
|
parser_blink.add_argument(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
choices=[
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
default='json',
|
|
148
|
-
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
|
+
)
|
|
149
252
|
parser_blink.set_defaults(func=BlinkCommand)
|
|
150
253
|
|
|
151
254
|
parser_gecko = subparsers.add_parser(
|
|
152
|
-
|
|
255
|
+
"gecko", help="Parse a file as a gecko-encoded value."
|
|
256
|
+
)
|
|
153
257
|
parser_gecko.add_argument(
|
|
154
|
-
|
|
155
|
-
|
|
258
|
+
"-s",
|
|
259
|
+
"--source",
|
|
156
260
|
required=True,
|
|
157
261
|
type=pathlib.Path,
|
|
158
|
-
help=
|
|
262
|
+
help="The source file.",
|
|
263
|
+
)
|
|
159
264
|
parser_gecko.add_argument(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
choices=[
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
default='json',
|
|
167
|
-
help='Output format. Default is json.')
|
|
265
|
+
"-o",
|
|
266
|
+
"--output",
|
|
267
|
+
choices=["json", "jsonl", "repr"],
|
|
268
|
+
default="json",
|
|
269
|
+
help="Output format. Default is json.",
|
|
270
|
+
)
|
|
168
271
|
parser_gecko.set_defaults(func=GeckoCommand)
|
|
169
272
|
|
|
170
273
|
parser_db = subparsers.add_parser(
|
|
171
|
-
|
|
274
|
+
"db", help="Parse a directory/file as IndexedDB."
|
|
275
|
+
)
|
|
172
276
|
parser_db.add_argument(
|
|
173
|
-
|
|
174
|
-
|
|
277
|
+
"-s",
|
|
278
|
+
"--source",
|
|
175
279
|
required=True,
|
|
176
280
|
type=pathlib.Path,
|
|
177
281
|
help=(
|
|
178
|
-
|
|
179
|
-
|
|
282
|
+
"The source IndexedDB folder (for chrome/chromium) "
|
|
283
|
+
"or sqlite3 file (for firefox/safari)."
|
|
284
|
+
),
|
|
285
|
+
)
|
|
180
286
|
recover_group = parser_db.add_mutually_exclusive_group()
|
|
181
287
|
recover_group.add_argument(
|
|
182
|
-
|
|
183
|
-
action=
|
|
184
|
-
help=
|
|
288
|
+
"--use_manifest",
|
|
289
|
+
action="store_true",
|
|
290
|
+
help="Use manifest file to determine active/deleted records.",
|
|
291
|
+
)
|
|
185
292
|
recover_group.add_argument(
|
|
186
|
-
|
|
187
|
-
action=
|
|
293
|
+
"--use_sequence_number",
|
|
294
|
+
action="store_true",
|
|
188
295
|
help=(
|
|
189
|
-
|
|
190
|
-
|
|
296
|
+
"Use sequence number and file offset to determine active/deleted "
|
|
297
|
+
"records."
|
|
298
|
+
),
|
|
299
|
+
)
|
|
191
300
|
parser_db.add_argument(
|
|
192
|
-
|
|
301
|
+
"--format",
|
|
193
302
|
required=True,
|
|
194
|
-
choices=[
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
303
|
+
choices=["chromium", "chrome", "firefox", "safari"],
|
|
304
|
+
help="The type of IndexedDB to parse.",
|
|
305
|
+
)
|
|
306
|
+
parser_db.add_argument(
|
|
307
|
+
"--object_store_id",
|
|
308
|
+
type=int,
|
|
309
|
+
help="The object store ID to filter by.",
|
|
310
|
+
)
|
|
311
|
+
parser_db.add_argument(
|
|
312
|
+
"--include_raw_data",
|
|
313
|
+
action="store_true",
|
|
314
|
+
help="Include raw key and value in the output.",
|
|
315
|
+
)
|
|
316
|
+
parser_db.add_argument(
|
|
317
|
+
"-o",
|
|
318
|
+
"--output",
|
|
319
|
+
choices=["json", "jsonl", "repr"],
|
|
320
|
+
default="json",
|
|
321
|
+
help="Output format. Default is json.",
|
|
322
|
+
)
|
|
200
323
|
parser_db.add_argument(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
324
|
+
"--filter_value",
|
|
325
|
+
type=str,
|
|
326
|
+
help=(
|
|
327
|
+
"Only output records where the value contains this string. "
|
|
328
|
+
"Values are normalized to strings before comparison."
|
|
329
|
+
),
|
|
330
|
+
)
|
|
331
|
+
parser_db.add_argument(
|
|
332
|
+
"--filter_key",
|
|
333
|
+
type=str,
|
|
334
|
+
help=(
|
|
335
|
+
"Only output records where the key contains this string. "
|
|
336
|
+
"Keys are normalized to strings before comparison."
|
|
337
|
+
),
|
|
338
|
+
)
|
|
209
339
|
parser_db.set_defaults(func=DbCommand)
|
|
210
340
|
|
|
211
341
|
parser_ldb = subparsers.add_parser(
|
|
212
|
-
|
|
213
|
-
|
|
342
|
+
"ldb", help="Parse a ldb file as IndexedDB."
|
|
343
|
+
)
|
|
214
344
|
parser_ldb.add_argument(
|
|
215
|
-
|
|
216
|
-
|
|
345
|
+
"-s",
|
|
346
|
+
"--source",
|
|
217
347
|
required=True,
|
|
218
348
|
type=pathlib.Path,
|
|
219
|
-
help=
|
|
349
|
+
help="The source .ldb file.",
|
|
350
|
+
)
|
|
351
|
+
parser_ldb.add_argument(
|
|
352
|
+
"-o",
|
|
353
|
+
"--output",
|
|
354
|
+
choices=["json", "jsonl", "repr"],
|
|
355
|
+
default="json",
|
|
356
|
+
help="Output format. Default is json.",
|
|
357
|
+
)
|
|
358
|
+
parser_ldb.add_argument(
|
|
359
|
+
"--filter_value",
|
|
360
|
+
type=str,
|
|
361
|
+
help=(
|
|
362
|
+
"Only output records where the value contains this string. "
|
|
363
|
+
"Values are normalized to strings before comparison."
|
|
364
|
+
),
|
|
365
|
+
)
|
|
220
366
|
parser_ldb.add_argument(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
help='Output format. Default is json.')
|
|
367
|
+
"--filter_key",
|
|
368
|
+
type=str,
|
|
369
|
+
help=(
|
|
370
|
+
"Only output records where the key contains this string. "
|
|
371
|
+
"Keys are normalized to strings before comparison."
|
|
372
|
+
),
|
|
373
|
+
)
|
|
229
374
|
parser_ldb.set_defaults(func=LdbCommand)
|
|
230
375
|
|
|
231
376
|
parser_log = subparsers.add_parser(
|
|
232
|
-
|
|
233
|
-
|
|
377
|
+
"log", help="Parse a log file as IndexedDB."
|
|
378
|
+
)
|
|
234
379
|
parser_log.add_argument(
|
|
235
|
-
|
|
380
|
+
"-s",
|
|
381
|
+
"--source",
|
|
236
382
|
required=True,
|
|
237
383
|
type=pathlib.Path,
|
|
238
|
-
help=
|
|
384
|
+
help="The source .log file.",
|
|
385
|
+
)
|
|
386
|
+
parser_log.add_argument(
|
|
387
|
+
"-o",
|
|
388
|
+
"--output",
|
|
389
|
+
choices=["json", "jsonl", "repr"],
|
|
390
|
+
default="json",
|
|
391
|
+
help="Output format. Default is json.",
|
|
392
|
+
)
|
|
239
393
|
parser_log.add_argument(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
394
|
+
"--filter_value",
|
|
395
|
+
type=str,
|
|
396
|
+
help=(
|
|
397
|
+
"Only output records where the value contains this string. "
|
|
398
|
+
"Values are normalized to strings before comparison."
|
|
399
|
+
),
|
|
400
|
+
)
|
|
401
|
+
parser_log.add_argument(
|
|
402
|
+
"--filter_key",
|
|
403
|
+
type=str,
|
|
404
|
+
help=(
|
|
405
|
+
"Only output records where the key contains this string. "
|
|
406
|
+
"Keys are normalized to strings before comparison."
|
|
407
|
+
),
|
|
408
|
+
)
|
|
248
409
|
parser_log.set_defaults(func=LogCommand)
|
|
249
410
|
|
|
250
|
-
args = parser.parse_args()
|
|
251
|
-
if hasattr(args,
|
|
411
|
+
args: argparse.Namespace = parser.parse_args()
|
|
412
|
+
if hasattr(args, "func"):
|
|
252
413
|
args.func(args)
|
|
253
414
|
else:
|
|
254
415
|
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
|
|
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
|
|
57
|
-
DO_NOT_USE_1
|
|
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
|
|
146
|
+
FRAME_HEADER = b"\xff\x06\x00\x00sNaPpY"
|