dump_indexeddb.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/env python3
  2. """Dump Chromium IndexedDB.
  3. Usage:
  4. python dump_indexeddb.py <leveldb-dir> [--store <name>] [--max <n>]
  5. The leveldb-dir is a copy of `IndexedDB/https_<host>_0.indexeddb.leveldb/`.
  6. Remove the LOCK file from the copy first.
  7. """
  8. import argparse
  9. import pathlib
  10. import sys
  11. from ccl_chromium_reader import ccl_chromium_indexeddb
  12. def main() -> int:
  13. ap = argparse.ArgumentParser(description=__doc__)
  14. ap.add_argument("path", type=pathlib.Path)
  15. ap.add_argument("--store", help="Filter by object store name")
  16. ap.add_argument("--max", type=int, default=10, help="Max records per store to print")
  17. ap.add_argument("--max-bytes", type=int, default=300, help="Truncate value repr")
  18. args = ap.parse_args()
  19. if not args.path.exists():
  20. print(f"error: {args.path} does not exist", file=sys.stderr)
  21. return 1
  22. db = ccl_chromium_indexeddb.WrappedIndexDB(args.path)
  23. db_ids = list(db.database_ids)
  24. if not db_ids:
  25. print("no databases found")
  26. return 0
  27. for db_id in db_ids:
  28. wdb = db[db_id.dbid_no]
  29. print(f"\n=== DB: {wdb.name} (id={db_id.dbid_no}) ===")
  30. for store_name in wdb.object_store_names:
  31. if args.store and args.store not in store_name:
  32. continue
  33. store = wdb[store_name]
  34. recs = list(store.iterate_records())
  35. print(f" STORE: {store_name} ({len(recs)} records)")
  36. for i, rec in enumerate(recs[: args.max]):
  37. v = repr(rec.value)
  38. if len(v) > args.max_bytes:
  39. v = v[: args.max_bytes] + f"...[+{len(repr(rec.value)) - args.max_bytes}c]"
  40. print(f" [{i}] key={rec.key!r}")
  41. print(f" val={v}")
  42. if len(recs) > args.max:
  43. print(f" ... +{len(recs) - args.max} more")
  44. return 0
  45. if __name__ == "__main__":
  46. sys.exit(main())