JavaScript无法用Promise直接包装“剪贴板数据的异步解密”,因Clipboard API不提供加密解密功能,需先用readText()读取再用Web Crypto API解密,全过程须在安全上下文和用户手势触发下执行。

JavaScript 中无法直接用 Promise 包装“剪贴板数据的异步解密”,因为浏览器剪贴板 API(navigator.clipboard)本身不提供加密或解密能力,也不暴露原始加密数据——它只负责安全地读写文本、图像等受权限约束的内容。所谓“解密”必须由你自行实现,且需在读取剪贴板内容后进行(例如读取到一串 Base64 编码的密文,再用 Web Crypto API 解密)。因此,正确做法是:先用 clipboard.readText()(或 read())获取数据,再用 Promise 链式处理解密逻辑。
1. 用 Promise 包装 clipboard.readText() 读取文本
现代浏览器中 navigator.clipboard.readText() 已返回原生 Promise,但为兼容性或统一风格,可显式包装:
function readClipboardText() {
if (!navigator.clipboard) {
return Promise.reject(new Error('Clipboard API not supported'));
}
return navigator.clipboard.readText();
}
<p>// 使用
readClipboardText()
.then(text => console.log('粘贴板文本:', text))
.catch(err => console.error('读取失败:', err));
2. 读取加密文本后用 Web Crypto 解密(AES-GCM 示例)
假设剪贴板中存的是 AES-GCM 加密后的 Base64 密文(含 iv + ciphertext),你需要:生成密钥(或从用户输入派生)、解析密文、调用 crypto.subtle.decrypt()。整个流程天然适合 Promise 链:
async function readAndDecrypt() {
const encryptedB64 = await navigator.clipboard.readText();
<p>// 解析 Base64 → Uint8Array(示例格式:iv|ciphertext)
const [ivB64, cipherB64] = encryptedB64.split('|');
const iv = base64ToArrayBuffer(ivB64);
const ciphertext = base64ToArrayBuffer(cipherB64);</p><p>// 假设你已有密钥(实际应安全获取,如 PBKDF2 派生)
const key = await importKey(/<em> ... </em>/); // 见下方说明</p><p>const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);</p><p>return new TextDecoder().decode(decrypted);
}</p><p>// 辅助函数:Base64 → ArrayBuffer
function base64ToArrayBuffer(b64) {
const bin = atob(b64);
const len = bin.length;
const buf = new ArrayBuffer(len);
const view = new Uint8Array(buf);
for (let i = 0; i < len; i++) view[i] = bin.charCodeAt(i);
return buf;
}
3. 安全导入密钥(Promise 包装的常见方式)
密钥通常不能硬编码,需由口令派生(PBKDF2)或从 IndexedDB 安全加载。以下是以口令派生 AES 密钥的 Promise 封装:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
async function deriveKey(password, salt) {
const enc = new TextEncoder();
const pwBuf = enc.encode(password);
<p>const keyMaterial = await crypto.subtle.importKey(
'raw', pwBuf, { name: 'PBKDF2' }, false, ['deriveKey']
);</p><p>return crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 100_000, hash: 'SHA-256' },
keyMaterial,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
4. 完整流程示例(读取 + 解密 + 错误处理)
把上述步骤组合成一个健壮的异步函数,带清晰错误提示:
async function decryptFromClipboard(password) {
try {
const encrypted = await navigator.clipboard.readText();
if (!encrypted.includes('|')) throw new Error('格式错误:期望 iv|ciphertext');
<pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">const [ivB64, cipherB64] = encrypted.split('|');
const iv = base64ToArrayBuffer(ivB64);
const ciphertext = base64ToArrayBuffer(cipherB64);
const salt = iv.slice(0, 16); // 假设 salt 存在 iv 前部
const key = await deriveKey(password, salt);
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: iv.slice(16) },
key,
ciphertext
);
return new TextDecoder().decode(decrypted);} catch (err) {
throw new Error(解密失败:${err.message});
}
}
// 调用 decryptFromClipboard('my-secret-pass') .then(plain => console.log('明文:', plain)) .catch(console.error);
注意:所有涉及 crypto.subtle 的操作必须在安全上下文(HTTPS 或 localhost)中运行;navigator.clipboard 读取需用户手势触发(如 click 事件内调用),否则会拒绝权限。不复杂但容易忽略。

















