ai-browser-profile 1.0.7 → 1.0.9
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.
|
@@ -214,14 +214,19 @@ def inject_via_cdp(
|
|
|
214
214
|
cookies: Iterable[Cookie],
|
|
215
215
|
cdp_url: str = "http://127.0.0.1:9222",
|
|
216
216
|
) -> int:
|
|
217
|
-
"""Inject cookies into a running Chrome via CDP
|
|
217
|
+
"""Inject cookies into a running Chrome via CDP.
|
|
218
|
+
|
|
219
|
+
Tries Storage.setCookies at the browser root first. If the browser has
|
|
220
|
+
zero Page targets that command fails with "Browser context management is
|
|
221
|
+
not supported" — in that case we fall back to opening a stub about:blank
|
|
222
|
+
tab, attaching to it, and using Network.setCookies on that session.
|
|
218
223
|
|
|
219
224
|
Args:
|
|
220
225
|
cookies: iterable of Cookie objects.
|
|
221
226
|
cdp_url: base http(s) URL of the Chrome DevTools endpoint, or a
|
|
222
227
|
cdp://host:port shorthand, or a raw ws:// URL.
|
|
223
228
|
|
|
224
|
-
Returns: number of cookies
|
|
229
|
+
Returns: number of cookies actually accepted by Chrome.
|
|
225
230
|
"""
|
|
226
231
|
from websocket import create_connection
|
|
227
232
|
|
|
@@ -230,6 +235,22 @@ def inject_via_cdp(
|
|
|
230
235
|
# unless the target was launched with --remote-allow-origins. Suppressing
|
|
231
236
|
# the header bypasses the check; localhost CDP is already privileged.
|
|
232
237
|
ws = create_connection(ws_url, timeout=10, suppress_origin=True)
|
|
238
|
+
msg_id = 0
|
|
239
|
+
|
|
240
|
+
def _send(method, params=None, session_id=None):
|
|
241
|
+
nonlocal msg_id
|
|
242
|
+
msg_id += 1
|
|
243
|
+
msg = {"id": msg_id, "method": method}
|
|
244
|
+
if params:
|
|
245
|
+
msg["params"] = params
|
|
246
|
+
if session_id:
|
|
247
|
+
msg["sessionId"] = session_id
|
|
248
|
+
ws.send(json.dumps(msg))
|
|
249
|
+
while True:
|
|
250
|
+
resp = json.loads(ws.recv())
|
|
251
|
+
if resp.get("id") == msg_id:
|
|
252
|
+
return resp
|
|
253
|
+
|
|
233
254
|
try:
|
|
234
255
|
batch = []
|
|
235
256
|
for c in cookies:
|
|
@@ -248,19 +269,49 @@ def inject_via_cdp(
|
|
|
248
269
|
batch.append(param)
|
|
249
270
|
if not batch:
|
|
250
271
|
return 0
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
272
|
+
|
|
273
|
+
# First: try Storage.setCookies at the browser root. Works when at
|
|
274
|
+
# least one Page target exists (i.e. any tab is open).
|
|
275
|
+
resp = _send("Storage.setCookies", {"cookies": batch})
|
|
276
|
+
err = resp.get("error", {})
|
|
277
|
+
if not err:
|
|
278
|
+
log.info("Injected %d cookies via Storage.setCookies", len(batch))
|
|
279
|
+
return len(batch)
|
|
280
|
+
|
|
281
|
+
# Fallback: open a stub tab so the browser context is materialised,
|
|
282
|
+
# then use Network.setCookies on its session.
|
|
283
|
+
msg = err.get("message", "")
|
|
284
|
+
if "Browser context management is not supported" not in msg:
|
|
285
|
+
log.warning("Storage.setCookies failed: %s", err)
|
|
259
286
|
return 0
|
|
287
|
+
|
|
288
|
+
log.info("Storage.setCookies unavailable (no tabs); opening stub tab and retrying via Network.setCookies")
|
|
289
|
+
target_id = None
|
|
290
|
+
try:
|
|
291
|
+
r = _send("Target.createTarget", {"url": "about:blank"})
|
|
292
|
+
target_id = r.get("result", {}).get("targetId")
|
|
293
|
+
if not target_id:
|
|
294
|
+
log.warning("Couldn't create stub tab: %s", r)
|
|
295
|
+
return 0
|
|
296
|
+
r = _send("Target.attachToTarget", {"targetId": target_id, "flatten": True})
|
|
297
|
+
session_id = r.get("result", {}).get("sessionId")
|
|
298
|
+
if not session_id:
|
|
299
|
+
log.warning("Couldn't attach to stub tab: %s", r)
|
|
300
|
+
return 0
|
|
301
|
+
r = _send("Network.setCookies", {"cookies": batch}, session_id=session_id)
|
|
302
|
+
if r.get("error"):
|
|
303
|
+
log.warning("Network.setCookies failed: %s", r["error"])
|
|
304
|
+
return 0
|
|
305
|
+
log.info("Injected %d cookies via Network.setCookies (per-tab fallback)", len(batch))
|
|
306
|
+
return len(batch)
|
|
307
|
+
finally:
|
|
308
|
+
if target_id:
|
|
309
|
+
try:
|
|
310
|
+
_send("Target.closeTarget", {"targetId": target_id})
|
|
311
|
+
except Exception:
|
|
312
|
+
pass
|
|
260
313
|
finally:
|
|
261
314
|
ws.close()
|
|
262
|
-
log.info("Injected %d cookies via CDP", len(batch))
|
|
263
|
-
return len(batch)
|
|
264
315
|
|
|
265
316
|
|
|
266
317
|
# --- helpers used by CLI and external callers ---
|
|
@@ -179,15 +179,50 @@ def read_indexeddb(
|
|
|
179
179
|
[o.strip() for o in origins if o and o.strip()] if origins else None
|
|
180
180
|
)
|
|
181
181
|
|
|
182
|
+
# Defaults to skip even when no explicit filter is given:
|
|
183
|
+
# chrome-extension:// — extensions, not portable across browsers
|
|
184
|
+
# localhost / 127.* — dev servers, irrelevant across machines
|
|
185
|
+
# file:// — local file URLs
|
|
186
|
+
SKIP_PREFIXES = (
|
|
187
|
+
"chrome-extension://",
|
|
188
|
+
"http://localhost",
|
|
189
|
+
"https://localhost",
|
|
190
|
+
"http://127.",
|
|
191
|
+
"https://127.",
|
|
192
|
+
"file://",
|
|
193
|
+
)
|
|
194
|
+
# Skip pathologically large origins by default (e.g. kapwing video editor
|
|
195
|
+
# which stores 2 GB of project blobs). Caller can still ask for them
|
|
196
|
+
# explicitly via origin_filter.
|
|
197
|
+
MAX_LEVELDB_BYTES = 200 * 1024 * 1024 # 200 MB
|
|
198
|
+
|
|
199
|
+
def _dir_size(p) -> int:
|
|
200
|
+
try:
|
|
201
|
+
return sum(f.stat().st_size for f in p.rglob("*") if f.is_file())
|
|
202
|
+
except Exception:
|
|
203
|
+
return 0
|
|
204
|
+
|
|
182
205
|
out: dict[str, list[IdbDbDump]] = {}
|
|
183
206
|
skipped_dbs = 0
|
|
207
|
+
skipped_origins = 0
|
|
184
208
|
|
|
185
209
|
for leveldb_dir in sorted(idb_root.glob("*.indexeddb.leveldb")):
|
|
186
210
|
origin = _idb_dir_to_origin(leveldb_dir.name)
|
|
187
211
|
if origin is None:
|
|
188
212
|
continue
|
|
189
|
-
if origin_filter
|
|
190
|
-
|
|
213
|
+
if origin_filter:
|
|
214
|
+
if not any(f in origin for f in origin_filter):
|
|
215
|
+
continue
|
|
216
|
+
else:
|
|
217
|
+
# No explicit filter — apply default safety skips.
|
|
218
|
+
if any(origin.startswith(p) for p in SKIP_PREFIXES):
|
|
219
|
+
skipped_origins += 1
|
|
220
|
+
continue
|
|
221
|
+
size = _dir_size(leveldb_dir)
|
|
222
|
+
if size > MAX_LEVELDB_BYTES:
|
|
223
|
+
log.info("skipping oversized IndexedDB %s (%.1f MB)", origin, size/1024/1024)
|
|
224
|
+
skipped_origins += 1
|
|
225
|
+
continue
|
|
191
226
|
|
|
192
227
|
blob_dir = leveldb_dir.parent / leveldb_dir.name.replace(".leveldb", ".blob")
|
|
193
228
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-browser-profile",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Extract user identity (name, emails, accounts, addresses, payments) from browser data into a self-ranking SQLite database. Install as a Claude Code agent skill.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-browser-profile": "bin/cli.js"
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@assistant-ui/react": "^0.12.25",
|
|
48
48
|
"@google/generative-ai": "^0.24.1",
|
|
49
|
-
"@m13v/seo-components": "^0.41.
|
|
49
|
+
"@m13v/seo-components": "^0.41.1",
|
|
50
50
|
"@remotion/player": "^4.0.446",
|
|
51
|
-
"@seo/components": "npm:@m13v/seo-components@^0.41.
|
|
51
|
+
"@seo/components": "npm:@m13v/seo-components@^0.41.1",
|
|
52
52
|
"@supabase/supabase-js": "^2.103.3",
|
|
53
53
|
"@tailwindcss/postcss": "^4",
|
|
54
54
|
"@types/node": "^20",
|