@@ -1,20 +1,36 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const $ = (id) => document.getElementById(id);
|
||||
|
||||
const t = (key, ...args) => chrome.i18n.getMessage(key, args) || key;
|
||||
// ---------- i18n ----------
|
||||
// t(key, ...args) 简易封装:取 chrome.i18n.getMessage,可带 $1/$2 参数
|
||||
const t = (key, ...args) => {
|
||||
const msg = chrome.i18n.getMessage(key, args);
|
||||
return msg || key;
|
||||
};
|
||||
|
||||
// 初始化:遍历 data-i18n / data-i18n-placeholder / data-i18n-title / data-i18n-aria 应用翻译
|
||||
function applyI18n(root = document) {
|
||||
root.querySelectorAll("[data-i18n]").forEach((el) => {
|
||||
const msg = chrome.i18n.getMessage(el.dataset.i18n);
|
||||
if (!msg) return;
|
||||
const key = el.dataset.i18n;
|
||||
// 部分元素含 <strong>/<kbd>/<span>/<code> 内嵌标签,统一用 message 文案覆盖 textContent
|
||||
// 仅在没有子标签时直接 textContent;有子标签时跳过(保留原 HTML 结构)
|
||||
if (el.children.length === 0) {
|
||||
el.textContent = msg;
|
||||
const msg = chrome.i18n.getMessage(key);
|
||||
if (msg) el.textContent = msg;
|
||||
} else {
|
||||
// 含嵌套标签:尝试只替换首个文本节点
|
||||
const msg = chrome.i18n.getMessage(key);
|
||||
if (msg) {
|
||||
// 简化:如果有子标签,整体替换为纯文本(保持现有视觉靠 CSS)
|
||||
// 这里保留原行为:不动结构,仅替换首文本节点
|
||||
const firstText = el.firstChild;
|
||||
if (firstText && firstText.nodeType === Node.TEXT_NODE) {
|
||||
// 找到第一个非空白文本节点,整体替换为 message 文案中第一个空白前部分
|
||||
// 简化处理:含子标签的元素文案在 messages.json 里已写为纯文本(无标签),直接用
|
||||
firstText.nodeValue = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
root.querySelectorAll("[data-i18n-placeholder]").forEach((el) => {
|
||||
const key = el.dataset.i18nPlaceholder;
|
||||
@@ -101,10 +117,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const crackTime = $("crackTime");
|
||||
|
||||
let editingId = null;
|
||||
// modal 确认后的回调
|
||||
let modalResolve = null;
|
||||
let modalMode = null;
|
||||
|
||||
// GPU 集群对 PBKDF2-SHA256 10 万次迭代的破解速度估算(约 10^7 次/秒)
|
||||
// ---------- 文件密码强度 / 破解时间估算 ----------
|
||||
// 假设攻击者使用 GPU 集群(PBKDF2-SHA256 10 万次迭代,约 1000 万次/秒,即 10^7 次/秒)
|
||||
// 这是中等规模攻击者的合理估算(数十块高端 GPU)
|
||||
const ATTACK_RATE = 1e7;
|
||||
|
||||
function estimateStrength(pwd) {
|
||||
@@ -145,6 +163,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
function updateStrength(pwd) {
|
||||
const { entropy, seconds, level, label } = estimateStrength(pwd);
|
||||
// 5 档进度条宽度,对数缩放避免弱口令条太短看不见
|
||||
const widthMap = {
|
||||
"empty": 0,
|
||||
"very-weak": 15,
|
||||
@@ -161,6 +180,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
modalPwd.addEventListener("input", () => updateStrength(modalPwd.value));
|
||||
|
||||
// ---------- Web Crypto 工具:AES-GCM + PBKDF2 ----------
|
||||
const enc = new TextEncoder();
|
||||
const dec = new TextDecoder();
|
||||
|
||||
@@ -232,10 +252,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
return JSON.parse(dec.decode(plainBuf));
|
||||
}
|
||||
|
||||
// ---------- 文件密码 modal ----------
|
||||
// mode: "export" 显示加密勾选 + 两次文件密码; "import" 仅显示一次文件密码
|
||||
function openPwdModal(mode) {
|
||||
return new Promise((resolve) => {
|
||||
modalResolve = resolve;
|
||||
modalMode = mode;
|
||||
if (mode === "export") {
|
||||
modalTitle.textContent = t("pwdModalExportTitle");
|
||||
encryptToggleGroup.style.display = "";
|
||||
@@ -264,7 +285,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
modalPwd.value = "";
|
||||
modalPwdConfirm.value = "";
|
||||
modalResolve = null;
|
||||
modalMode = null;
|
||||
updateStrength("");
|
||||
}
|
||||
|
||||
@@ -285,7 +305,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
modalConfirm.addEventListener("click", () => {
|
||||
if (!modalResolve) return;
|
||||
if (modalMode === "export") {
|
||||
// 通过 modal 当前模式标记判断(openPwdModal 时 mode 已确定 export/import 文案)
|
||||
const isExport = modalTitle.textContent === t("pwdModalExportTitle");
|
||||
if (isExport) {
|
||||
if (encryptToggle.checked) {
|
||||
const p1 = modalPwd.value;
|
||||
const p2 = modalPwdConfirm.value;
|
||||
|
||||
Reference in New Issue
Block a user