You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Chrome扩展Manifest V3中嵌入libsodium.js的问题

在Chrome扩展Manifest V3的后台服务工作者中使用libsodium.js的问题

问题背景

我正尝试使用libsodium.js——一个经Emscripten转译为WASM的C语言库,但遇到了Chrome扩展Manifest V3环境下的适配问题。找到的两篇相关参考内容都无法解决问题:

  • 旧帖子提到Chrome扩展禁止使用eval(),而libsodium.js初始化会调用该方法,Manifest V3中只能通过沙盒页面规避,但配套示例并非针对V3版本;
  • 另一帖子的答案链接已失效,其思路是通过iframe与DOM通信,但我需要在后台服务工作者中使用该库,这个方案不适用。

已尝试的方法及问题

  1. 沙盒页面加载:在沙盒页面中成功运行了独立构建版sodium.js,但沙盒页面无法调用chrome.* API,无法与后台服务工作者通信;
  2. 后台服务工作者导入尝试:
    • 使用importScripts()导入:触发CSP违规错误

      Uncaught (in promise) RuntimeError: Aborted(CompileError: WebAssembly.instantiate(): Refused to compile or instantiate WebAssembly module because neither 'wasm-eval' nor 'unsafe-eval' is an allowed source of script in the following Content Security Policy directive: "script-src 'self'"). Build with -sASSERTIONS for more info.

    • 将manifest.json中background设为module类型后,使用import {_sodium} from '../thirdparty/js/libsodium-wrappers.js'导入模块构建版:

      Uncaught SyntaxError: The requested module '../thirdparty/js/libsodium-wrappers.js' does not provide an export named '_sodium'

    • 直接使用import '../thirdparty/js/libsodium-wrappers.js'导入:

      Uncaught TypeError: Cannot read properties of undefined (reading 'sodium')

可行解决方案

方案1:调整CSP并使用ES模块版本

  1. 修改manifest.json的CSP配置,添加'wasm-eval'权限:
    {
      "manifest_version": 3,
      "background": {
        "service_worker": "background.js",
        "type": "module"
      },
      "content_security_policy": {
        "extension_pages": "script-src 'self' 'wasm-eval'; object-src 'self'"
      }
    }
    
  2. 下载libsodium.js的ES模块构建版本(需与libsodium-wrappers.js配套),将文件放在扩展目录的thirdparty/js下;
  3. 在后台服务工作者中正确导入并初始化:
    import * as sodium from '../thirdparty/js/libsodium-wrappers.js';
    
    // 初始化libsodium
    async function initSodium() {
      await sodium.ready;
      // 之后即可调用sodium的API,例如:
      const key = sodium.crypto_secretbox_keygen();
      console.log('生成密钥:', key);
    }
    
    initSodium();
    

方案2:沙盒页面+消息通信

如果无法调整CSP,可通过沙盒页面作为libsodium的运行容器,配合消息机制与后台服务工作者通信:

  1. 在manifest.json中配置沙盒页面:
    {
      "manifest_version": 3,
      "sandbox": {
        "pages": ["sandbox.html"]
      },
      "background": {
        "service_worker": "background.js"
      }
    }
    
  2. 创建sandbox.html,加载独立构建版sodium.js并处理消息:
    <script src="thirdparty/js/sodium.js"></script>
    <script>
      // 等待libsodium初始化完成
      sodium.ready.then(() => {
        // 监听来自后台的消息
        window.addEventListener('message', async (event) => {
          if (event.source !== parent) return;
          const { type, data } = event.data;
          let result;
          // 根据消息类型执行对应操作
          switch(type) {
            case 'crypto_secretbox_keygen':
              result = sodium.crypto_secretbox_keygen();
              break;
            // 可添加更多操作类型
          }
          // 向后台返回结果
          parent.postMessage({ type, result }, '*');
        });
      });
    </script>
    
  3. 在后台服务工作者中创建沙盒iframe并通信:
    async function getSandboxPort() {
      const iframe = document.createElement('iframe');
      iframe.src = chrome.runtime.getURL('sandbox.html');
      iframe.style.display = 'none';
      document.body.appendChild(iframe);
    
      return new Promise(resolve => {
        window.addEventListener('message', (event) => {
          if (event.source === iframe.contentWindow) {
            // 建立双向通信通道
            const port = {
              send: (type, data) => iframe.contentWindow.postMessage({ type, data }, '*'),
              onMessage: (callback) => {
                window.addEventListener('message', (event) => {
                  if (event.source === iframe.contentWindow) {
                    callback(event.data);
                  }
                });
              }
            };
            resolve(port);
          }
        }, { once: true });
      });
    }
    
    // 使用示例
    async function generateKey() {
      const port = await getSandboxPort();
      return new Promise(resolve => {
        port.onMessage((message) => {
          if (message.type === 'crypto_secretbox_keygen') {
            resolve(message.result);
          }
        });
        port.send('crypto_secretbox_keygen');
      });
    }
    

内容的提问来源于stack exchange,提问作者Jacob Jewett

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:13:16