diff --git a/config-overrides.js b/config-overrides.js index 4826e3b..1058630 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -31,6 +31,7 @@ const extWebpack = (config, env) => { popup: paths.appSrc + "/popup.js", options: paths.appSrc + "/options.js", background: paths.appSrc + "/background.js", + backgroundthunderbird: paths.appSrc + "/background.thunderbird.js", content: paths.appSrc + "/content.js", }; diff --git a/package.json b/package.json index 901efe1..387eb47 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,13 @@ "build:chrome": "rm -rf build/chrome && BUILD_PATH=./build/chrome REACT_APP_CLIENT=chrome react-app-rewired build && rm build/chrome/content.html", "build:edge": "rm -rf build/edge && cp -r build/chrome build/edge", "build:firefox": "rm -rf build/firefox && cp -r build/chrome build/firefox && cat ./build/firefox/manifest.firefox.json > ./build/firefox/manifest.json && rm build/*/manifest.firefox.json", + "build:thunderbird":"rm -rf build/thunderbird && cp -r build/chrome build/thunderbird && cat ./build/thunderbird/manifest.thunderbird.json > ./build/thunderbird/manifest.json && cp ./build/thunderbird/backgroundthunderbird.js ./build/thunderbird/background.js && rm build/*/manifest.thunderbird.json && rm build/*/backgroundthunderbird.js && rm build/*/backgroundthunderbird.js.LICENSE.txt", "build:web": "rm -rf build/web && BUILD_PATH=./build/web REACT_APP_CLIENT=userscript react-app-rewired build", "build:userscript-ios": "file1=build/web/kiss-translator.user.js file2=build/web/kiss-translator-ios-safari.user.js && cp $file1 $file2 && sed -i 's|// @grant unsafeWindow|// @inject-into content|g' $file2", "build:userscript": "rm -rf build/userscript && mkdir build/userscript && cp build/web/*.user.js build/userscript/", "build:rules": "babel-node src/rules.js", - "build": "pnpm build:chrome && pnpm build:edge && pnpm build:firefox && pnpm build:web && pnpm build:userscript-ios && pnpm build:userscript && pnpm build:rules", - "zip": "cd build && zip -r chrome.zip chrome && zip -r edge.zip edge && cd firefox && zip -r ../firefox.zip .", + "build": "pnpm build:chrome && pnpm build:edge && pnpm build:firefox && pnpm build:thunderbird && pnpm build:web && pnpm build:userscript-ios && pnpm build:userscript && pnpm build:rules", + "zip": "cd build && zip -r chrome.zip chrome && zip -r edge.zip edge && (cd firefox && zip -r ../firefox.zip .) && (cd thunderbird && zip -r ../thunderbird.zip .)", "test": "react-app-rewired test", "eject": "react-scripts eject" }, diff --git a/public/manifest.thunderbird.json b/public/manifest.thunderbird.json new file mode 100644 index 0000000..2aa3459 --- /dev/null +++ b/public/manifest.thunderbird.json @@ -0,0 +1,78 @@ +{ + "manifest_version": 2, + "name": "__MSG_app_name__", + "description": "__MSG_app_description__", + "version": "1.8.11", + "default_locale": "en", + "author": "Gabe", + "homepage_url": "https://github.com/fishjar/kiss-translator", + "browser_specific_settings": { + "gecko": { + "id": "yugang2002@gmail.com", + "strict_min_version": "78.0" + } + }, + "background": { + "scripts": ["background.js"] + }, + "content_scripts": [ + { + "js": ["content.js"], + "matches": [""], + "all_frames": true + } + ], + "commands": { + "_execute_browser_action": { + "suggested_key": { + "default": "Alt+K" + } + }, + "toggleTranslate": { + "suggested_key": { + "default": "Alt+Q" + }, + "description": "__MSG_toggle_translate__" + }, + "openTranbox": { + "suggested_key": { + "default": "Alt+S" + }, + "description": "__MSG_open_tranbox__" + }, + "toggleStyle": { + "suggested_key": { + "default": "Alt+C" + }, + "description": "__MSG_toggle_style__" + }, + "openOptions": { + "description": "__MSG_open_options__" + } + }, + "permissions": [ + "", + "storage", + "menus", + "messagesModify", + "scripting", + "declarativeNetRequest" + ], + "icons": { + "16": "images/logo16.png", + "32": "images/logo32.png", + "48": "images/logo48.png", + "128": "images/logo128.png" + }, + "browser_action": { + "default_icon": { + "128": "images/logo128.png" + }, + "default_title": "__MSG_app_name__", + "default_popup": "popup.html" + }, + "options_ui": { + "page": "options.html", + "open_in_tab": true + } +} diff --git a/src/background.thunderbird.js b/src/background.thunderbird.js new file mode 100644 index 0000000..7b8e29c --- /dev/null +++ b/src/background.thunderbird.js @@ -0,0 +1,254 @@ +import browser from "webextension-polyfill"; +import { + MSG_FETCH, + MSG_GET_HTTPCACHE, + MSG_TRANS_TOGGLE, + MSG_OPEN_OPTIONS, + MSG_SAVE_RULE, + MSG_TRANS_TOGGLE_STYLE, + MSG_OPEN_TRANBOX, + MSG_CONTEXT_MENUS, + MSG_COMMAND_SHORTCUTS, + MSG_INJECT_JS, + MSG_INJECT_CSS, + MSG_UPDATE_CSP, + DEFAULT_CSPLIST, + CMD_TOGGLE_TRANSLATE, + CMD_TOGGLE_STYLE, + CMD_OPEN_OPTIONS, + CMD_OPEN_TRANBOX, +} from "./config"; +import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage"; +import { trySyncSettingAndRules } from "./libs/sync"; +import { fetchHandle, getHttpCache } from "./libs/fetch"; +import { sendTabMsg } from "./libs/msg"; +import { trySyncAllSubRules } from "./libs/subRules"; +import { tryClearCaches } from "./libs"; +import { saveRule } from "./libs/rules"; +import { getCurTabId } from "./libs/msg"; +import { injectInlineJs, injectInternalCss } from "./libs/injector"; +import { kissLog } from "./libs/log"; + +globalThis.ContextType = "BACKGROUND"; + +const REMOVE_HEADERS = [ + `content-security-policy`, + `content-security-policy-report-only`, + `x-webkit-csp`, + `x-content-security-policy`, +]; + +/** + * 添加右键菜单 + */ +async function addmenus(contextMenuType = 1) { + // 添加前先删除,避免重复ID的错误 + try { + await browser.menus.removeAll(); + } catch (err) { + // + } + + switch (contextMenuType) { + case 1: + browser.menus.create({ + id: CMD_TOGGLE_TRANSLATE, + title: browser.i18n.getMessage("app_name"), + contexts: ["page", "selection"], + }); + break; + case 2: + browser.menus.create({ + id: CMD_TOGGLE_TRANSLATE, + title: browser.i18n.getMessage("toggle_translate"), + contexts: ["page", "selection"], + }); + browser.menus.create({ + id: CMD_TOGGLE_STYLE, + title: browser.i18n.getMessage("toggle_style"), + contexts: ["page", "selection"], + }); + browser.menus.create({ + id: CMD_OPEN_TRANBOX, + title: browser.i18n.getMessage("open_tranbox"), + contexts: ["page", "selection"], + }); + browser.menus.create({ + id: "options_separator", + type: "separator", + contexts: ["page", "selection"], + }); + browser.menus.create({ + id: CMD_OPEN_OPTIONS, + title: browser.i18n.getMessage("open_options"), + contexts: ["page", "selection"], + }); + break; + default: + } +} + +/** + * 更新CSP策略 + * @param {*} csplist + */ +async function updateCspRules(csplist = DEFAULT_CSPLIST.join(",\n")) { + try { + const newRules = csplist + .split(/\n|,/) + .map((url) => url.trim()) + .filter(Boolean) + .map((url, idx) => ({ + id: idx + 1, + action: { + type: "modifyHeaders", + responseHeaders: REMOVE_HEADERS.map((header) => ({ + operation: "remove", + header, + })), + }, + condition: { + urlFilter: url, + resourceTypes: ["main_frame", "sub_frame"], + }, + })); + const oldRules = await browser.declarativeNetRequest.getDynamicRules(); + const oldRuleIds = oldRules.map((rule) => rule.id); + await browser.declarativeNetRequest.updateDynamicRules({ + removeRuleIds: oldRuleIds, + addRules: newRules, + }); + } catch (err) { + kissLog(err, "update csp rules"); + } +} + +/** + * 插件安装 + */ +browser.runtime.onInstalled.addListener(() => { + tryInitDefaultData(); + + // 右键菜单 + addmenus(); + + // 禁用CSP + updateCspRules(); +}); + +/** + * 浏览器启动 + */ +browser.runtime.onStartup.addListener(async () => { + // 同步数据 + await trySyncSettingAndRules(); + + const { clearCache, contextMenuType, subrulesList, csplist } = + await getSettingWithDefault(); + + // 清除缓存 + if (clearCache) { + tryClearCaches(); + } + + // 右键菜单 + // firefox重启后菜单会消失,故重复添加 + addmenus(contextMenuType); + + // 禁用CSP + updateCspRules(csplist); + + // 同步订阅规则 + trySyncAllSubRules({ subrulesList }); +}); + +/** + * 监听消息 + */ +browser.runtime.onMessage.addListener(async ({ action, args }) => { + switch (action) { + case MSG_FETCH: + return await fetchHandle(args); + case MSG_GET_HTTPCACHE: + const { input, init } = args; + return await getHttpCache(input, init); + case MSG_OPEN_OPTIONS: + return await browser.runtime.openOptionsPage(); + case MSG_SAVE_RULE: + return await saveRule(args); + case MSG_INJECT_JS: + return await browser.scripting.executeScript({ + target: { tabId: await getCurTabId(), allFrames: true }, + func: injectInlineJs, + args: [args], + world: "MAIN", + }); + case MSG_INJECT_CSS: + return await browser.scripting.executeScript({ + target: { tabId: await getCurTabId(), allFrames: true }, + func: injectInternalCss, + args: [args], + world: "MAIN", + }); + case MSG_UPDATE_CSP: + return await updateCspRules(args); + case MSG_CONTEXT_MENUS: + return await addmenus(args); + case MSG_COMMAND_SHORTCUTS: + return await browser.commands.getAll(); + default: + throw new Error(`message action is unavailable: ${action}`); + } +}); + +/** + * 监听快捷键 + */ +browser.commands.onCommand.addListener((command) => { + // console.log(`Command: ${command}`); + switch (command) { + case CMD_TOGGLE_TRANSLATE: + sendTabMsg(MSG_TRANS_TOGGLE); + break; + case CMD_OPEN_TRANBOX: + sendTabMsg(MSG_OPEN_TRANBOX); + break; + case CMD_TOGGLE_STYLE: + sendTabMsg(MSG_TRANS_TOGGLE_STYLE); + break; + case CMD_OPEN_OPTIONS: + browser.runtime.openOptionsPage(); + break; + default: + } +}); + +/** + * 监听右键菜单 + */ +browser.menus.onClicked.addListener(({ menuItemId }) => { + switch (menuItemId) { + case CMD_TOGGLE_TRANSLATE: + sendTabMsg(MSG_TRANS_TOGGLE); + break; + case CMD_TOGGLE_STYLE: + sendTabMsg(MSG_TRANS_TOGGLE_STYLE); + break; + case CMD_OPEN_TRANBOX: + sendTabMsg(MSG_OPEN_TRANBOX); + break; + case CMD_OPEN_OPTIONS: + browser.runtime.openOptionsPage(); + break; + default: + } +}); +/** + * 邮件显示中注册脚本 + */ +async function registerMsgDisplayScript() { + await messenger.messageDisplayScripts.register({ + js: [{file: "/content.js"}] + }); + } +registerMsgDisplayScript(); \ No newline at end of file