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.
Files changed (34) hide show
  1. dfindexeddb/indexeddb/chromium/blink.py +116 -74
  2. dfindexeddb/indexeddb/chromium/definitions.py +240 -125
  3. dfindexeddb/indexeddb/chromium/record.py +651 -346
  4. dfindexeddb/indexeddb/chromium/sqlite.py +362 -0
  5. dfindexeddb/indexeddb/chromium/v8.py +100 -78
  6. dfindexeddb/indexeddb/cli.py +282 -121
  7. dfindexeddb/indexeddb/firefox/definitions.py +7 -4
  8. dfindexeddb/indexeddb/firefox/gecko.py +98 -74
  9. dfindexeddb/indexeddb/firefox/record.py +78 -26
  10. dfindexeddb/indexeddb/safari/definitions.py +5 -3
  11. dfindexeddb/indexeddb/safari/record.py +86 -53
  12. dfindexeddb/indexeddb/safari/webkit.py +85 -71
  13. dfindexeddb/indexeddb/types.py +4 -1
  14. dfindexeddb/leveldb/cli.py +146 -138
  15. dfindexeddb/leveldb/definitions.py +6 -2
  16. dfindexeddb/leveldb/descriptor.py +70 -56
  17. dfindexeddb/leveldb/ldb.py +39 -33
  18. dfindexeddb/leveldb/log.py +41 -30
  19. dfindexeddb/leveldb/plugins/chrome_notifications.py +30 -18
  20. dfindexeddb/leveldb/plugins/interface.py +5 -6
  21. dfindexeddb/leveldb/plugins/manager.py +10 -9
  22. dfindexeddb/leveldb/record.py +71 -62
  23. dfindexeddb/leveldb/utils.py +105 -13
  24. dfindexeddb/utils.py +36 -31
  25. dfindexeddb/version.py +2 -2
  26. dfindexeddb-20260205.dist-info/METADATA +171 -0
  27. dfindexeddb-20260205.dist-info/RECORD +41 -0
  28. {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info}/WHEEL +1 -1
  29. dfindexeddb-20241105.dist-info/AUTHORS +0 -12
  30. dfindexeddb-20241105.dist-info/METADATA +0 -424
  31. dfindexeddb-20241105.dist-info/RECORD +0 -41
  32. {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info}/entry_points.txt +0 -0
  33. {dfindexeddb-20241105.dist-info → dfindexeddb-20260205.dist-info/licenses}/LICENSE +0 -0
  34. {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'file:{self.filename}?mode=ro', uri=True) as conn:
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'file:{self.filename}?mode=ro', uri=True) as conn:
120
+ with sqlite3.connect(f"file:{self.filename}?mode=ro", uri=True) as conn:
111
121
  cursor = conn.execute(
112
- 'SELECT id, name, keypath, autoinc FROM ObjectStoreInfo')
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(self, record_id: int) -> Optional[IndexedDBRecord]:
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'file:{self.filename}?mode=ro', uri=True) as conn:
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
- 'SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM '
134
- 'Records r '
135
- 'JOIN ObjectStoreInfo o ON r.objectStoreID == o.id '
136
- 'WHERE r.recordID = ?', (record_id, ))
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('utf-8'),
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'file:{self.filename}?mode=ro', uri=True) as conn:
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
- 'SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID FROM '
163
- 'Records r '
164
- 'JOIN ObjectStoreInfo o ON r.objectStoreID == o.id '
165
- 'WHERE o.name = ?', (name, )):
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('utf-8'),
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'file:{self.filename}?mode=ro', uri=True) as conn:
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
- 'SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID '
189
- 'FROM Records r '
190
- 'JOIN ObjectStoreInfo o ON r.objectStoreID == o.id '
191
- 'WHERE o.id = ?', (object_store_id, ))
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('utf-8'),
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(self) -> Generator[IndexedDBRecord, None, None]:
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'file:{self.filename}?mode=ro', uri=True) as conn:
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
- 'SELECT r.key, r.value, r.objectStoreID, o.name, r.recordID '
209
- 'FROM Records r '
210
- 'JOIN ObjectStoreInfo o ON r.objectStoreID == o.id')
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) as err:
218
- print(
219
- f'Error parsing IndexedDB key: {err}', file=sys.stderr)
220
- print(f'Traceback: {traceback.format_exc()}', file=sys.stderr)
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) as err:
228
- print(
229
- f'Error parsing IndexedDB value: {err}', file=sys.stderr)
230
- print(f'Traceback: {traceback.format_exc()}', file=sys.stderr)
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('utf-8'),
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
+ )