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
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""Safari IndexedDB records."""
|
|
16
|
-
from dataclasses import dataclass
|
|
17
16
|
import plistlib
|
|
18
17
|
import sqlite3
|
|
19
18
|
import sys
|
|
20
19
|
import traceback
|
|
20
|
+
from dataclasses import dataclass
|
|
21
21
|
from typing import Any, Generator, Optional
|
|
22
22
|
|
|
23
23
|
from dfindexeddb import errors
|
|
@@ -35,6 +35,7 @@ class ObjectStoreInfo:
|
|
|
35
35
|
auto_inc: True if the object store uses auto incrementing IDs.
|
|
36
36
|
database_name: the database name from the IDBDatabaseInfo table.
|
|
37
37
|
"""
|
|
38
|
+
|
|
38
39
|
id: int
|
|
39
40
|
name: str
|
|
40
41
|
key_path: str
|
|
@@ -53,13 +54,18 @@ class IndexedDBRecord:
|
|
|
53
54
|
object_store_name: the object store name from the ObjectStoreInfo table.
|
|
54
55
|
database_name: the IndexedDB database name from the IDBDatabaseInfo table.
|
|
55
56
|
record_id: the record ID from the Record table.
|
|
57
|
+
raw_key: the raw key.
|
|
58
|
+
raw_value: the raw value.
|
|
56
59
|
"""
|
|
60
|
+
|
|
57
61
|
key: Any
|
|
58
62
|
value: Any
|
|
59
63
|
object_store_id: int
|
|
60
64
|
object_store_name: str
|
|
61
65
|
database_name: str
|
|
62
66
|
record_id: int
|
|
67
|
+
raw_key: Optional[bytes] = None
|
|
68
|
+
raw_value: Optional[bytes] = None
|
|
63
69
|
|
|
64
70
|
|
|
65
71
|
class FileReader:
|
|
@@ -80,24 +86,28 @@ class FileReader:
|
|
|
80
86
|
"""
|
|
81
87
|
self.filename = filename
|
|
82
88
|
|
|
83
|
-
with sqlite3.connect(f
|
|
89
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
84
90
|
cursor = conn.execute(
|
|
85
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseVersion"'
|
|
91
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseVersion"'
|
|
92
|
+
)
|
|
86
93
|
result = cursor.fetchone()
|
|
87
94
|
self.database_version = result[0]
|
|
88
95
|
|
|
89
96
|
cursor = conn.execute(
|
|
90
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "MetadataVersion"'
|
|
97
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "MetadataVersion"'
|
|
98
|
+
)
|
|
91
99
|
result = cursor.fetchone()
|
|
92
100
|
self.metadata_version = result[0]
|
|
93
101
|
|
|
94
102
|
cursor = conn.execute(
|
|
95
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseName"'
|
|
103
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseName"'
|
|
104
|
+
)
|
|
96
105
|
result = cursor.fetchone()
|
|
97
106
|
self.database_name = result[0]
|
|
98
107
|
|
|
99
108
|
cursor = conn.execute(
|
|
100
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "MaxObjectStoreID"'
|
|
109
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "MaxObjectStoreID"'
|
|
110
|
+
)
|
|
101
111
|
result = cursor.fetchone()
|
|
102
112
|
self.max_object_store_id = result[0]
|
|
103
113
|
|
|
@@ -107,9 +117,10 @@ class FileReader:
|
|
|
107
117
|
Yields:
|
|
108
118
|
ObjectStoreInfo instances.
|
|
109
119
|
"""
|
|
110
|
-
with sqlite3.connect(f
|
|
120
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
111
121
|
cursor = conn.execute(
|
|
112
|
-
|
|
122
|
+
"SELECT id, name, keypath, autoinc FROM ObjectStoreInfo"
|
|
123
|
+
)
|
|
113
124
|
results = cursor.fetchall()
|
|
114
125
|
for result in results:
|
|
115
126
|
key_path = plistlib.loads(result[2])
|
|
@@ -118,22 +129,27 @@ class FileReader:
|
|
|
118
129
|
name=result[1],
|
|
119
130
|
key_path=key_path,
|
|
120
131
|
auto_inc=result[3],
|
|
121
|
-
database_name=self.database_name
|
|
132
|
+
database_name=self.database_name,
|
|
133
|
+
)
|
|
122
134
|
|
|
123
|
-
def RecordById(
|
|
135
|
+
def RecordById(
|
|
136
|
+
self, record_id: int, include_raw_data: bool = False
|
|
137
|
+
) -> Optional[IndexedDBRecord]:
|
|
124
138
|
"""Returns an IndexedDBRecord for the given record_id.
|
|
125
139
|
|
|
126
140
|
Returns:
|
|
127
|
-
the IndexedDBRecord or None if the record_id does not exist in the
|
|
141
|
+
the IndexedDBRecord or None if the record_id does not exist in the
|
|
128
142
|
database.
|
|
129
143
|
"""
|
|
130
|
-
with sqlite3.connect(f
|
|
144
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
131
145
|
conn.text_factory = bytes
|
|
132
146
|
cursor = conn.execute(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
147
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM "
|
|
148
|
+
"Records r "
|
|
149
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
150
|
+
"WHERE r.recordID = ?",
|
|
151
|
+
(record_id,),
|
|
152
|
+
)
|
|
137
153
|
row = cursor.fetchone()
|
|
138
154
|
if not row:
|
|
139
155
|
return None
|
|
@@ -143,52 +159,60 @@ class FileReader:
|
|
|
143
159
|
key=key,
|
|
144
160
|
value=value,
|
|
145
161
|
object_store_id=row[2],
|
|
146
|
-
object_store_name=row[3].decode(
|
|
162
|
+
object_store_name=row[3].decode("utf-8"),
|
|
147
163
|
database_name=self.database_name,
|
|
148
|
-
record_id=row[4]
|
|
164
|
+
record_id=row[4],
|
|
165
|
+
raw_key=row[0] if include_raw_data else None,
|
|
166
|
+
raw_value=row[1] if include_raw_data else None,
|
|
167
|
+
)
|
|
149
168
|
|
|
150
169
|
def RecordsByObjectStoreName(
|
|
151
|
-
self,
|
|
152
|
-
name: str
|
|
170
|
+
self, name: str, include_raw_data: bool = False
|
|
153
171
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
154
172
|
"""Returns IndexedDBRecords for the given ObjectStore name.
|
|
155
173
|
|
|
156
174
|
Yields:
|
|
157
175
|
IndexedDBRecord instances.
|
|
158
176
|
"""
|
|
159
|
-
with sqlite3.connect(f
|
|
177
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
160
178
|
conn.text_factory = bytes
|
|
161
179
|
for row in conn.execute(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM "
|
|
181
|
+
"Records r "
|
|
182
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
183
|
+
"WHERE o.name = ?",
|
|
184
|
+
(name,),
|
|
185
|
+
):
|
|
166
186
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
167
187
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
168
188
|
yield IndexedDBRecord(
|
|
169
189
|
key=key,
|
|
170
190
|
value=value,
|
|
171
191
|
object_store_id=row[2],
|
|
172
|
-
object_store_name=row[3].decode(
|
|
192
|
+
object_store_name=row[3].decode("utf-8"),
|
|
173
193
|
database_name=self.database_name,
|
|
174
|
-
record_id=row[4]
|
|
194
|
+
record_id=row[4],
|
|
195
|
+
raw_key=row[0] if include_raw_data else None,
|
|
196
|
+
raw_value=row[1] if include_raw_data else None,
|
|
197
|
+
)
|
|
175
198
|
|
|
176
199
|
def RecordsByObjectStoreId(
|
|
177
|
-
self,
|
|
178
|
-
object_store_id: int
|
|
200
|
+
self, object_store_id: int, include_raw_data: bool = False
|
|
179
201
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
180
202
|
"""Returns IndexedDBRecords for the given ObjectStore id.
|
|
181
203
|
|
|
182
204
|
Yields:
|
|
183
205
|
IndexedDBRecord instances.
|
|
184
206
|
"""
|
|
185
|
-
with sqlite3.connect(f
|
|
207
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
186
208
|
conn.text_factory = bytes
|
|
187
209
|
cursor = conn.execute(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
210
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID "
|
|
211
|
+
"FROM Records r "
|
|
212
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
213
|
+
"WHERE o.id = ?",
|
|
214
|
+
(object_store_id,),
|
|
215
|
+
)
|
|
192
216
|
for row in cursor:
|
|
193
217
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
194
218
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
@@ -196,43 +220,52 @@ class FileReader:
|
|
|
196
220
|
key=key,
|
|
197
221
|
value=value,
|
|
198
222
|
object_store_id=row[2],
|
|
199
|
-
object_store_name=row[3].decode(
|
|
223
|
+
object_store_name=row[3].decode("utf-8"),
|
|
200
224
|
database_name=self.database_name,
|
|
201
|
-
record_id=row[4]
|
|
225
|
+
record_id=row[4],
|
|
226
|
+
raw_key=row[0] if include_raw_data else None,
|
|
227
|
+
raw_value=row[1] if include_raw_data else None,
|
|
228
|
+
)
|
|
202
229
|
|
|
203
|
-
def Records(
|
|
230
|
+
def Records(
|
|
231
|
+
self, include_raw_data: bool = False
|
|
232
|
+
) -> Generator[IndexedDBRecord, None, None]:
|
|
204
233
|
"""Returns all the IndexedDBRecords."""
|
|
205
|
-
with sqlite3.connect(f
|
|
234
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
206
235
|
conn.text_factory = bytes
|
|
207
236
|
cursor = conn.execute(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
237
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID "
|
|
238
|
+
"FROM Records r "
|
|
239
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id"
|
|
240
|
+
)
|
|
211
241
|
for row in cursor:
|
|
212
242
|
try:
|
|
213
243
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
214
|
-
except(
|
|
244
|
+
except (
|
|
215
245
|
errors.ParserError,
|
|
216
246
|
errors.DecoderError,
|
|
217
|
-
NotImplementedError
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
print(f
|
|
247
|
+
NotImplementedError,
|
|
248
|
+
) as err:
|
|
249
|
+
print(f"Error parsing IndexedDB key: {err}", file=sys.stderr)
|
|
250
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|
|
221
251
|
continue
|
|
222
252
|
try:
|
|
223
253
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
224
|
-
except(
|
|
254
|
+
except (
|
|
225
255
|
errors.ParserError,
|
|
226
256
|
errors.DecoderError,
|
|
227
|
-
NotImplementedError
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
print(f
|
|
257
|
+
NotImplementedError,
|
|
258
|
+
) as err:
|
|
259
|
+
print(f"Error parsing IndexedDB value: {err}", file=sys.stderr)
|
|
260
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|
|
231
261
|
continue
|
|
232
262
|
yield IndexedDBRecord(
|
|
233
263
|
key=key,
|
|
234
264
|
value=value,
|
|
235
265
|
object_store_id=row[2],
|
|
236
|
-
object_store_name=row[3].decode(
|
|
266
|
+
object_store_name=row[3].decode("utf-8"),
|
|
237
267
|
database_name=self.database_name,
|
|
238
|
-
record_id=row[4]
|
|
268
|
+
record_id=row[4],
|
|
269
|
+
raw_key=row[0] if include_raw_data else None,
|
|
270
|
+
raw_value=row[1] if include_raw_data else None,
|
|
271
|
+
)
|