rename cookie_grabber -> tmwd_cdp_bridge (CDP bridge extension)

This commit is contained in:
Liang Jiaqing
2026-03-04 11:15:32 +08:00
parent dcf65d72c7
commit 0ab90af250
11 changed files with 178 additions and 153 deletions

View File

@@ -1,24 +0,0 @@
// background.js - 保留原有事件 + 新增消息监听
chrome.runtime.onInstalled.addListener(() => {
console.log('Cookie Grabber installed');
});
// content script 请求cookie时的处理
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'getCookies' && sender.tab) {
const url = sender.tab.url;
// 普通cookie + partitioned cookie 双查合并
chrome.cookies.getAll({url}, cookies => {
console.log('[CookieGrabber] normal cookies:', cookies.map(c => c.name));
chrome.cookies.getAll({url, partitionKey: {topLevelSite: url.match(/^https?:\/\/[^/]+/)[0]}}, pCookies => {
console.log('[CookieGrabber] partitioned cookies:', pCookies.map(c => c.name));
const map = {};
cookies.forEach(c => map[c.name] = c.value);
pCookies.forEach(c => map[c.name] = c.value);
const str = Object.entries(map).map(([k,v]) => k + '=' + v).join('; ');
sendResponse({cookies: str});
});
});
return true; // 异步响应
}
});

View File

@@ -1,18 +0,0 @@
// content.js - MutationObserver 监听触发元素
const TRIGGER_ID = '__ljqcg__';
const obs = new MutationObserver(muts => {
for (const m of muts) {
for (const node of m.addedNodes) {
if (node.nodeType === 1 && node.id === TRIGGER_ID) {
chrome.runtime.sendMessage({type: 'getCookies'}, res => {
if (res && res.cookies) node.textContent = res.cookies;
else node.textContent = '__cg_error__';
});
return;
}
}
}
});
obs.observe(document.documentElement, {childList: true, subtree: true});

View File

@@ -1,32 +0,0 @@
{
"manifest_version": 3,
"name": "Cookie Grabber",
"version": "1.0",
"description": "获取所有 cookies",
"permissions": [
"cookies",
"storage",
"tabs",
"activeTab"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"content.js"
],
"run_at": "document_idle"
}
]
}

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HttpOnly Cookie Grabber</title>
<script src="popup.js" defer></script>
<style>
body { font-family: Arial, sans-serif; padding: 10px; }
ul { padding-left: 20px; }
li { margin: 5px 0; }
pre { background-color: #f8f8f8; padding: 10px; border: 1px solid #ccc; max-height: 150px; overflow-y: auto; }
button { margin-top: 10px; }
</style>
</head>
<body>
<h1>Get All Cookies</h1>
<ul id="cookiesDisplay">No available cookies</ul>
<button id="refresh">Refresh and Copy Cookies</button>
</body>
</html>

View File

@@ -1,56 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
// 当刷新按钮被点击时,获取当前页面的 cookies
document.getElementById('refresh').addEventListener('click', fetchCookies);
// 加载时显示当前页面的 cookies
fetchCookies();
});
// 从 cookies 存储中获取当前页面的 cookies
function fetchCookies() {
// 获取当前活动的标签页
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const activeTab = tabs[0]; // 获取活动标签页
const currentUrl = activeTab.url; // 当前页面的 URL
console.log("当前活动的 URL:", currentUrl);
// 双查: 普通 + partitioned
const origin = currentUrl.match(/^https?:\/\/[^\/]+/)[0];
chrome.cookies.getAll({ url: currentUrl }, (cookies) => {
chrome.cookies.getAll({ url: currentUrl, partitionKey: { topLevelSite: origin } }, (pCookies) => {
const map = {};
cookies.forEach(c => map[c.name] = c.value);
pCookies.forEach(c => map[c.name] = c.value);
const allCookies = Object.entries(map);
const cookiesDisplay = document.getElementById('cookiesDisplay');
cookiesDisplay.innerHTML = '';
if (allCookies.length === 0) {
cookiesDisplay.innerHTML = '<li>No available cookies</li>';
} else {
let cookiesString = '';
allCookies.forEach(([name, value]) => {
const li = document.createElement('li');
li.textContent = `${name}: ${value}`;
cookiesDisplay.appendChild(li);
cookiesString += `${name}=${value}; `;
});
console.log('cookies:', allCookies.length);
copyCookiesToClipboard(cookiesString.trim());
}
});
});
});
}
// 将 cookies 复制到剪贴板
function copyCookiesToClipboard(cookiesString) {
// 使用 Clipboard API 复制到剪贴板
navigator.clipboard.writeText(cookiesString)
.then(() => {
console.log("Cookies copied to clipboard:", cookiesString);
})
.catch(err => {
console.error("Unable to copy to clipboard:", err);
});
}

View File

@@ -0,0 +1,43 @@
// background.js - Cookie + CDP Bridge
chrome.runtime.onInstalled.addListener(() => console.log('CDP Bridge installed'));
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'getCookies') {
handleGetCookies(msg, sender).then(sendResponse);
return true;
}
if (msg.action === 'cdp') {
handleCDP(msg, sender).then(sendResponse);
return true;
}
});
async function handleGetCookies(msg, sender) {
try {
const url = msg.url || sender.tab?.url;
const origin = url.match(/^https?:\/\/[^\/]+/)[0];
const all = await chrome.cookies.getAll({ url });
const part = await chrome.cookies.getAll({ url, partitionKey: { topLevelSite: origin } }).catch(() => []);
const merged = [...all];
for (const c of part) {
if (!merged.some(x => x.name === c.name && x.domain === c.domain)) merged.push(c);
}
return { ok: true, data: merged };
} catch (e) {
return { ok: false, error: e.message };
}
}
async function handleCDP(msg, sender) {
const tabId = msg.tabId || sender.tab?.id;
if (!tabId) return { ok: false, error: 'no tabId' };
try {
await chrome.debugger.attach({ tabId }, '1.3');
const result = await chrome.debugger.sendCommand({ tabId }, msg.method, msg.params || {});
await chrome.debugger.detach({ tabId });
return { ok: true, data: result };
} catch (e) {
try { await chrome.debugger.detach({ tabId }); } catch (_) {}
return { ok: false, error: e.message };
}
}

View File

@@ -0,0 +1,31 @@
// content.js - DOM trigger bridge
const TID = '__ljq_ctrl';
new MutationObserver(muts => {
for (const m of muts) for (const n of m.addedNodes) {
if (n.id === TID || (n.querySelector && n.querySelector('#' + TID))) {
const el = n.id === TID ? n : n.querySelector('#' + TID);
handle(el);
}
}
}).observe(document.documentElement, { childList: true, subtree: true });
async function handle(el) {
try {
const cmd = el.dataset.cmd || 'cookies';
let resp;
if (cmd === 'cookies') {
resp = await chrome.runtime.sendMessage({ action: 'getCookies', url: location.href });
} else if (cmd === 'cdp') {
const method = el.dataset.method;
const params = el.dataset.params ? JSON.parse(el.dataset.params) : {};
const tabId = el.dataset.tabid ? parseInt(el.dataset.tabid) : undefined;
resp = await chrome.runtime.sendMessage({ action: 'cdp', method, params, tabId });
} else {
resp = { ok: false, error: 'unknown cmd: ' + cmd };
}
el.textContent = JSON.stringify(resp);
} catch (e) {
el.textContent = JSON.stringify({ ok: false, error: e.message });
}
}

View File

@@ -0,0 +1,28 @@
{
"manifest_version": 3,
"name": "Cookie Grabber",
"version": "2.0",
"description": "Cookie viewer + CDP bridge",
"permissions": [
"cookies",
"tabs",
"activeTab",
"debugger"
],
"host_permissions": ["<all_urls>"],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_idle",
"all_frames": true
}
],
"action": {
"default_popup": "popup.html",
"default_title": "Cookie Grabber"
}
}

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{width:420px;max-height:500px;margin:0;padding:8px;font:12px monospace;background:#1e1e1e;color:#d4d4d4;overflow-y:auto}
h3{margin:4px 0;color:#569cd6}
button{background:#264f78;color:#fff;border:none;padding:4px 12px;cursor:pointer;border-radius:3px;margin-bottom:6px}
button:hover{background:#37699e}
pre{white-space:pre-wrap;word-break:break-all;margin:0;padding:6px;background:#252526;border-radius:3px;max-height:420px;overflow-y:auto}
</style>
</head>
<body>
<h3>🍪 Cookies</h3>
<button id="refresh">刷新</button>
<pre id="out">点击刷新获取 cookies...</pre>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,24 @@
document.addEventListener('DOMContentLoaded', () => {
const out = document.getElementById('out');
const btn = document.getElementById('refresh');
btn.addEventListener('click', fetchCookies);
fetchCookies();
});
async function fetchCookies() {
const out = document.getElementById('out');
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab?.url) { out.textContent = 'No active tab'; return; }
const resp = await chrome.runtime.sendMessage({ action: 'getCookies', url: tab.url });
if (!resp?.ok) { out.textContent = 'Error: ' + (resp?.error || 'unknown'); return; }
if (!resp.data.length) { out.textContent = '(no cookies)'; return; }
// 展示带标记
out.textContent = resp.data.map(c =>
`${c.name}=${c.value}` + (c.httpOnly ? ' [H]' : '') + (c.secure ? ' [S]' : '') + (c.partitionKey ? ' [P]' : '')
).join('\n');
// 自动复制 name=value; 格式到剪贴板
const str = resp.data.map(c => `${c.name}=${c.value}`).join('; ');
await navigator.clipboard.writeText(str);
} catch (e) { out.textContent = 'Error: ' + e.message; }
}