dfindexeddb 20241031__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.
- dfindexeddb/indexeddb/chromium/blink.py +116 -74
- dfindexeddb/indexeddb/chromium/definitions.py +152 -124
- dfindexeddb/indexeddb/chromium/record.py +536 -348
- dfindexeddb/indexeddb/chromium/v8.py +112 -141
- dfindexeddb/indexeddb/cli.py +125 -114
- dfindexeddb/indexeddb/firefox/definitions.py +7 -4
- dfindexeddb/indexeddb/firefox/gecko.py +103 -79
- dfindexeddb/indexeddb/firefox/record.py +66 -24
- dfindexeddb/indexeddb/safari/definitions.py +12 -10
- dfindexeddb/indexeddb/safari/record.py +68 -51
- dfindexeddb/indexeddb/safari/webkit.py +112 -189
- dfindexeddb/indexeddb/types.py +5 -2
- dfindexeddb/leveldb/cli.py +146 -131
- dfindexeddb/leveldb/definitions.py +6 -2
- dfindexeddb/leveldb/descriptor.py +75 -45
- dfindexeddb/leveldb/ldb.py +39 -30
- dfindexeddb/leveldb/log.py +44 -27
- dfindexeddb/leveldb/plugins/chrome_notifications.py +30 -18
- dfindexeddb/leveldb/plugins/interface.py +5 -6
- dfindexeddb/leveldb/plugins/manager.py +11 -10
- dfindexeddb/leveldb/record.py +71 -62
- dfindexeddb/leveldb/utils.py +21 -13
- dfindexeddb/utils.py +35 -30
- dfindexeddb/version.py +2 -2
- dfindexeddb-20251109.dist-info/METADATA +222 -0
- dfindexeddb-20251109.dist-info/RECORD +40 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info}/WHEEL +1 -1
- dfindexeddb-20241031.dist-info/AUTHORS +0 -12
- dfindexeddb-20241031.dist-info/METADATA +0 -424
- dfindexeddb-20241031.dist-info/RECORD +0 -41
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info}/entry_points.txt +0 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info/licenses}/LICENSE +0 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.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
|
|
@@ -54,6 +55,7 @@ class IndexedDBRecord:
|
|
|
54
55
|
database_name: the IndexedDB database name from the IDBDatabaseInfo table.
|
|
55
56
|
record_id: the record ID from the Record table.
|
|
56
57
|
"""
|
|
58
|
+
|
|
57
59
|
key: Any
|
|
58
60
|
value: Any
|
|
59
61
|
object_store_id: int
|
|
@@ -80,24 +82,28 @@ class FileReader:
|
|
|
80
82
|
"""
|
|
81
83
|
self.filename = filename
|
|
82
84
|
|
|
83
|
-
with sqlite3.connect(f
|
|
85
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
84
86
|
cursor = conn.execute(
|
|
85
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseVersion"'
|
|
87
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseVersion"'
|
|
88
|
+
)
|
|
86
89
|
result = cursor.fetchone()
|
|
87
90
|
self.database_version = result[0]
|
|
88
91
|
|
|
89
92
|
cursor = conn.execute(
|
|
90
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "MetadataVersion"'
|
|
93
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "MetadataVersion"'
|
|
94
|
+
)
|
|
91
95
|
result = cursor.fetchone()
|
|
92
96
|
self.metadata_version = result[0]
|
|
93
97
|
|
|
94
98
|
cursor = conn.execute(
|
|
95
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseName"'
|
|
99
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "DatabaseName"'
|
|
100
|
+
)
|
|
96
101
|
result = cursor.fetchone()
|
|
97
102
|
self.database_name = result[0]
|
|
98
103
|
|
|
99
104
|
cursor = conn.execute(
|
|
100
|
-
'SELECT value FROM IDBDatabaseInfo WHERE key = "MaxObjectStoreID"'
|
|
105
|
+
'SELECT value FROM IDBDatabaseInfo WHERE key = "MaxObjectStoreID"'
|
|
106
|
+
)
|
|
101
107
|
result = cursor.fetchone()
|
|
102
108
|
self.max_object_store_id = result[0]
|
|
103
109
|
|
|
@@ -107,9 +113,10 @@ class FileReader:
|
|
|
107
113
|
Yields:
|
|
108
114
|
ObjectStoreInfo instances.
|
|
109
115
|
"""
|
|
110
|
-
with sqlite3.connect(f
|
|
116
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
111
117
|
cursor = conn.execute(
|
|
112
|
-
|
|
118
|
+
"SELECT id, name, keypath, autoinc FROM ObjectStoreInfo"
|
|
119
|
+
)
|
|
113
120
|
results = cursor.fetchall()
|
|
114
121
|
for result in results:
|
|
115
122
|
key_path = plistlib.loads(result[2])
|
|
@@ -118,22 +125,25 @@ class FileReader:
|
|
|
118
125
|
name=result[1],
|
|
119
126
|
key_path=key_path,
|
|
120
127
|
auto_inc=result[3],
|
|
121
|
-
database_name=self.database_name
|
|
128
|
+
database_name=self.database_name,
|
|
129
|
+
)
|
|
122
130
|
|
|
123
131
|
def RecordById(self, record_id: int) -> Optional[IndexedDBRecord]:
|
|
124
132
|
"""Returns an IndexedDBRecord for the given record_id.
|
|
125
133
|
|
|
126
134
|
Returns:
|
|
127
|
-
the IndexedDBRecord or None if the record_id does not exist in the
|
|
135
|
+
the IndexedDBRecord or None if the record_id does not exist in the
|
|
128
136
|
database.
|
|
129
137
|
"""
|
|
130
|
-
with sqlite3.connect(f
|
|
138
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
131
139
|
conn.text_factory = bytes
|
|
132
140
|
cursor = conn.execute(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM "
|
|
142
|
+
"Records r "
|
|
143
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
144
|
+
"WHERE r.recordID = ?",
|
|
145
|
+
(record_id,),
|
|
146
|
+
)
|
|
137
147
|
row = cursor.fetchone()
|
|
138
148
|
if not row:
|
|
139
149
|
return None
|
|
@@ -143,52 +153,56 @@ class FileReader:
|
|
|
143
153
|
key=key,
|
|
144
154
|
value=value,
|
|
145
155
|
object_store_id=row[2],
|
|
146
|
-
object_store_name=row[3].decode(
|
|
156
|
+
object_store_name=row[3].decode("utf-8"),
|
|
147
157
|
database_name=self.database_name,
|
|
148
|
-
record_id=row[4]
|
|
158
|
+
record_id=row[4],
|
|
159
|
+
)
|
|
149
160
|
|
|
150
161
|
def RecordsByObjectStoreName(
|
|
151
|
-
self,
|
|
152
|
-
name: str
|
|
162
|
+
self, name: str
|
|
153
163
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
154
164
|
"""Returns IndexedDBRecords for the given ObjectStore name.
|
|
155
165
|
|
|
156
166
|
Yields:
|
|
157
167
|
IndexedDBRecord instances.
|
|
158
168
|
"""
|
|
159
|
-
with sqlite3.connect(f
|
|
169
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
160
170
|
conn.text_factory = bytes
|
|
161
171
|
for row in conn.execute(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
172
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM "
|
|
173
|
+
"Records r "
|
|
174
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
175
|
+
"WHERE o.name = ?",
|
|
176
|
+
(name,),
|
|
177
|
+
):
|
|
166
178
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
167
179
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
168
180
|
yield IndexedDBRecord(
|
|
169
181
|
key=key,
|
|
170
182
|
value=value,
|
|
171
183
|
object_store_id=row[2],
|
|
172
|
-
object_store_name=row[3].decode(
|
|
184
|
+
object_store_name=row[3].decode("utf-8"),
|
|
173
185
|
database_name=self.database_name,
|
|
174
|
-
record_id=row[4]
|
|
186
|
+
record_id=row[4],
|
|
187
|
+
)
|
|
175
188
|
|
|
176
189
|
def RecordsByObjectStoreId(
|
|
177
|
-
self,
|
|
178
|
-
object_store_id: int
|
|
190
|
+
self, object_store_id: int
|
|
179
191
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
180
192
|
"""Returns IndexedDBRecords for the given ObjectStore id.
|
|
181
193
|
|
|
182
194
|
Yields:
|
|
183
195
|
IndexedDBRecord instances.
|
|
184
196
|
"""
|
|
185
|
-
with sqlite3.connect(f
|
|
197
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
186
198
|
conn.text_factory = bytes
|
|
187
199
|
cursor = conn.execute(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
200
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID "
|
|
201
|
+
"FROM Records r "
|
|
202
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id "
|
|
203
|
+
"WHERE o.id = ?",
|
|
204
|
+
(object_store_id,),
|
|
205
|
+
)
|
|
192
206
|
for row in cursor:
|
|
193
207
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
194
208
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
@@ -196,43 +210,46 @@ class FileReader:
|
|
|
196
210
|
key=key,
|
|
197
211
|
value=value,
|
|
198
212
|
object_store_id=row[2],
|
|
199
|
-
object_store_name=row[3].decode(
|
|
213
|
+
object_store_name=row[3].decode("utf-8"),
|
|
200
214
|
database_name=self.database_name,
|
|
201
|
-
record_id=row[4]
|
|
215
|
+
record_id=row[4],
|
|
216
|
+
)
|
|
202
217
|
|
|
203
218
|
def Records(self) -> Generator[IndexedDBRecord, None, None]:
|
|
204
219
|
"""Returns all the IndexedDBRecords."""
|
|
205
|
-
with sqlite3.connect(f
|
|
220
|
+
with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
|
|
206
221
|
conn.text_factory = bytes
|
|
207
222
|
cursor = conn.execute(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
223
|
+
"SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID "
|
|
224
|
+
"FROM Records r "
|
|
225
|
+
"JOIN ObjectStoreInfo o ON r.objectStoreID == o.id"
|
|
226
|
+
)
|
|
211
227
|
for row in cursor:
|
|
212
228
|
try:
|
|
213
229
|
key = webkit.IDBKeyData.FromBytes(row[0]).data
|
|
214
|
-
except(
|
|
230
|
+
except (
|
|
215
231
|
errors.ParserError,
|
|
216
232
|
errors.DecoderError,
|
|
217
|
-
NotImplementedError
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
print(f
|
|
233
|
+
NotImplementedError,
|
|
234
|
+
) as err:
|
|
235
|
+
print(f"Error parsing IndexedDB key: {err}", file=sys.stderr)
|
|
236
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|
|
221
237
|
continue
|
|
222
238
|
try:
|
|
223
239
|
value = webkit.SerializedScriptValueDecoder.FromBytes(row[1])
|
|
224
|
-
except(
|
|
240
|
+
except (
|
|
225
241
|
errors.ParserError,
|
|
226
242
|
errors.DecoderError,
|
|
227
|
-
NotImplementedError
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
print(f
|
|
243
|
+
NotImplementedError,
|
|
244
|
+
) as err:
|
|
245
|
+
print(f"Error parsing IndexedDB value: {err}", file=sys.stderr)
|
|
246
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|
|
231
247
|
continue
|
|
232
248
|
yield IndexedDBRecord(
|
|
233
249
|
key=key,
|
|
234
250
|
value=value,
|
|
235
251
|
object_store_id=row[2],
|
|
236
|
-
object_store_name=row[3].decode(
|
|
252
|
+
object_store_name=row[3].decode("utf-8"),
|
|
237
253
|
database_name=self.database_name,
|
|
238
|
-
record_id=row[4]
|
|
254
|
+
record_id=row[4],
|
|
255
|
+
)
|