dump_localstorage.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/env python3
  2. """Dump Chromium Local Storage.
  3. Usage:
  4. python dump_localstorage.py <leveldb-dir> [--origin <url>] [--key <pattern>]
  5. The leveldb-dir is a copy of the app's `Local Storage/leveldb/` dir. Copy first,
  6. remove the LOCK file, then point this at the copy.
  7. """
  8. import argparse
  9. import pathlib
  10. import sys
  11. from ccl_chromium_reader import ccl_chromium_localstorage
  12. def main() -> int:
  13. ap = argparse.ArgumentParser(description=__doc__)
  14. ap.add_argument("path", type=pathlib.Path, help="Path to leveldb dir")
  15. ap.add_argument("--origin", help="Filter by origin (substring match)")
  16. ap.add_argument("--key", help="Filter by script_key (substring match)")
  17. ap.add_argument("--max-bytes", type=int, default=300, help="Truncate values longer than this")
  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. ls = ccl_chromium_localstorage.LocalStoreDb(args.path)
  23. origins = sorted(set(ls.iter_storage_keys()))
  24. for origin in origins:
  25. if args.origin and args.origin not in origin:
  26. continue
  27. # latest-wins: leveldb is append-only
  28. latest: dict = {}
  29. for rec in ls.iter_records_for_storage_key(origin):
  30. latest[rec.script_key] = rec.value
  31. keys = sorted(latest.keys())
  32. if args.key:
  33. keys = [k for k in keys if args.key in k]
  34. if not keys:
  35. continue
  36. print(f"\n=== {origin} ({len(keys)} keys) ===")
  37. for k in keys:
  38. v = latest[k]
  39. if isinstance(v, str) and len(v) > args.max_bytes:
  40. v = v[: args.max_bytes] + f"...[+{len(latest[k]) - args.max_bytes}b]"
  41. print(f" {k!r}")
  42. print(f" => {v!r}")
  43. return 0
  44. if __name__ == "__main__":
  45. sys.exit(main())