普通视图

发现新文章,点击刷新页面。
昨天 — 2025年8月21日首页

写一个Chrome插件

作者 一涯
2025年8月21日 11:58

最近一直用的cookie同步插件被禁用了,然后利用chatGPT自己搞了一个

1. 文件清单(直接在项目目录放这些文件)

  • manifest.json

  • background.js (service worker)

  • popup.html

  • popup.js

  • popup.css(可选,可以直接写在html里面)

  • README.md(可选,使用说明)

  • icons(放展示图标)

将上面的文件放入文件夹中,只保留必要的文件,最终结果如下:

image.png

其中icons可以通过网上的免费图标网站自己设计一些

image.png

1. manifest.json

{
  "manifest_version": 3,
  "name": "Multi Cookie Sync",
  "version": "1.0",
  "description": "Sync all cookies from one site to another with multiple rules.",
  "permissions": [
    "cookies",
    "storage",
    "scripting"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "background": {
    "service_worker": "background.js"
  }
}

2. background.js

Chrome 扩展 (Manifest V3) 里:

  • background.js 并不是强制必须的
  • 只有当你需要在后台执行逻辑(比如监听消息、操作 cookie、下载文件等 需要扩展 API 权限 的动作)时,才需要它作为 service worker 存在。

我的需求其实只是将某个网站的cookie同步到开发环境的页面中,绕开SSO登录的逻辑,不需要一些文件的导入导出,或者下载之类的操作,所以我这个文件是空的。

其中监听事件是扩展 API、长生命周期的监听(cookie 变化、tab 更新、消息监听)

比如:

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type === "EXPORT_COOKIES") {
    // 读取 cookie
  }
});

注意:该文件中不能访问DOM

3. popup.html

这个就是打开插件后展示的界面

image.png

其中代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>Multi Cookie Sync</title>
  <meta charset="UTF-8">
  <style>
    body { font-family: sans-serif; width: 360px; padding: 10px; }
    input, button { width: 100%; margin: 5px 0; }
    label { font-weight: bold; display: block; margin-top: 8px; }
    .pair { margin-bottom: 10px; border-bottom: 1px solid #ccc; padding-bottom: 10px; }
    .input-actions { display: flex; gap: 10px; }
    .input-actions button { flex: 1; }
  </style>
</head>
<body>
  <h3>添加同步规则</h3>

  <input type="text" id="sourceUrl" placeholder="源站 URL,例如 https://a.example.com">
  <input type="text" id="targetUrl" placeholder="目标站 URL,例如 https://b.example.com">

  <div class="input-actions">
    <button id="addPairBtn">添加配对</button>
    <button id="clearInputBtn">清空输入</button>
  </div>

  <h3>配对规则列表</h3>
  <div id="pairList"></div>

  <button id="syncAllBtn">同步全部 Cookie</button>
  <p id="status"></p>

  <script src="popup.js"></script>
</body>
</html>

4. popup.js

负责 和用户交互(点按钮、输入网址)

const sourceInput = document.getElementById("sourceUrl");
const targetInput = document.getElementById("targetUrl");
const statusEl = document.getElementById("status");
const pairListEl = document.getElementById("pairList");

function renderPairs(pairs) {
  pairListEl.innerHTML = "";
  pairs.forEach((pair, index) => {
    const div = document.createElement("div");
    div.className = "pair";
    div.innerHTML = `
      <div><strong>源:</strong>${pair.source}</div>
      <div><strong>目标:</strong>${pair.target}</div>
      <button data-index="${index}" class="deleteBtn">删除</button>
    `;
    pairListEl.appendChild(div);
  });

  document.querySelectorAll(".deleteBtn").forEach(btn => {
    btn.addEventListener("click", (e) => {
      const i = parseInt(e.target.dataset.index);
      chrome.storage.sync.get({ sitePairs: [] }, ({ sitePairs }) => {
        sitePairs.splice(i, 1);
        chrome.storage.sync.set({ sitePairs }, () => renderPairs(sitePairs));
      });
    });
  });
}

document.getElementById("addPairBtn").addEventListener("click", () => {
  const sourceUrl = sourceInput.value.trim();
  const targetUrl = targetInput.value.trim();

  if (!sourceUrl || !targetUrl) {
    statusEl.innerText = "请填写完整的源站和目标站 URL";
    return;
  }

  chrome.storage.sync.get({ sitePairs: [] }, ({ sitePairs }) => {
    sitePairs.push({ source: sourceUrl, target: targetUrl });
    chrome.storage.sync.set({ sitePairs }, () => {
      renderPairs(sitePairs);
      statusEl.innerText = "已添加规则";
    });
  });

  // ❌ 不再清空输入框(除非用户点击“清空”按钮)
});

document.getElementById("clearInputBtn").addEventListener("click", () => {
  sourceInput.value = "";
  targetInput.value = "";
});

document.getElementById("syncAllBtn").addEventListener("click", () => {
  chrome.storage.sync.get({ sitePairs: [] }, async ({ sitePairs }) => {
    for (const pair of sitePairs) {
      try {
        const cookies = await chrome.cookies.getAll({ url: pair.source });
        for (const cookie of cookies) {
          await chrome.cookies.set({
            url: pair.target,
            name: cookie.name,
            value: cookie.value,
            domain: new URL(pair.target).hostname,
            path: cookie.path || "/",
            secure: cookie.secure,
            httpOnly: cookie.httpOnly,
            sameSite: cookie.sameSite || "no_restriction",
            expirationDate: cookie.expirationDate || (Date.now() / 1000 + 3600)
          });
        }
      } catch (e) {
        console.warn(`同步失败: ${pair.source}${pair.target}`, e);
      }
    }

    statusEl.innerText = "所有规则 Cookie 同步完成。";
  });
});

chrome.storage.sync.get({ sitePairs: [] }, ({ sitePairs }) => {
  renderPairs(sitePairs);
});

// 1. 监听输入变化并存入 storage
sourceInput.addEventListener("input", () => {
  chrome.storage.local.set({ currentSourceUrl: sourceInput.value });
});
targetInput.addEventListener("input", () => {
  chrome.storage.local.set({ currentTargetUrl: targetInput.value });
});

// 2. 页面打开时恢复输入框内容
chrome.storage.local.get(["currentSourceUrl", "currentTargetUrl"], (data) => {
  if (data.currentSourceUrl) sourceInput.value = data.currentSourceUrl;
  if (data.currentTargetUrl) targetInput.value = data.currentTargetUrl;
});
document.getElementById("clearInputBtn").addEventListener("click", () => {
  sourceInput.value = "";
  targetInput.value = "";
  chrome.storage.local.remove(["currentSourceUrl", "currentTargetUrl"]);
});

3. 安装和使用

  • 将上面文件放到一个文件夹(例如 cookie-syncer)。

  • 打开 Chrome → chrome://extensions/

  • 打开右上角「开发者模式」。

  • 点击「加载已解压的扩展程序」,选择该文件夹。

  • 点击浏览器工具栏扩展图标打开弹窗。

其中目标站就是想要从其同步cookie的网站,比如公司内登录过的SSO网站

❌
❌