diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..773225f --- /dev/null +++ b/TODO.md @@ -0,0 +1,13 @@ +# DONE 🎉 +- 图片上传 +- 图片 paste上传,drop上传 +- 图片预览,保存 +- 图片预览,保存 自动下载按钮 +- 重构文本加解密节点 +# TODO 🚧 +- 视频上传,预览,保存解密 + +# PLAN 📝 +- fetch hook,/view fetch encrypted文件时自动转换 +- service worker 加解密 +- 设置界面,配置、查看密钥对 exchange密钥对按钮 \ No newline at end of file diff --git a/ts/clientEncrypt.ts b/ts/clientEncrypt.ts index 0ea3609..d7d68ca 100644 --- a/ts/clientEncrypt.ts +++ b/ts/clientEncrypt.ts @@ -7,6 +7,8 @@ import type { ComfyApi, ComfyNodeDef, } from "@comfyorg/comfyui-frontend-types"; +import { encryptDataWithServerKey, encryptFileWithServerKey } from "./utils/cryptoUtils.js"; +import { bytesToBase64 } from "./utils/base64Utils.js"; const app: ComfyApp = rawApp; const api: ComfyApi = rawApi; @@ -46,66 +48,21 @@ async function getPublicKey(): Promise { // 使用公钥加密文本 async function encryptText( - text: string, - publicKey?: string + text: string ): Promise { - publicKey ??= await getPublicKey() ?? undefined; - if (!publicKey) { - throw new Error( - "Failed to get public key for encryption" - ); - } try { - // 将PEM格式的公钥转换为CryptoKey对象 - const pemHeader = "-----BEGIN PUBLIC KEY-----"; - const pemFooter = "-----END PUBLIC KEY-----"; - const pemContents = publicKey - .substring( - publicKey.indexOf(pemHeader) + pemHeader.length, - publicKey.indexOf(pemFooter) - ) - .replace(/\s/g, ""); - - // 解码Base64 - const binaryDer = window.atob(pemContents); - const binaryDerArray = new Uint8Array(binaryDer.length); - for (let i = 0; i < binaryDer.length; i++) { - binaryDerArray[i] = binaryDer.charCodeAt(i); - } - - // 导入公钥 - const cryptoKey = await window.crypto.subtle.importKey( - "spki", - binaryDerArray, - { - name: "RSA-OAEP", - hash: "SHA-256", - }, - false, - ["encrypt"] - ); - - // 加密文本 - const encoder = new TextEncoder(); - const data = encoder.encode(text); - const encrypted = await window.crypto.subtle.encrypt( - { - name: "RSA-OAEP", - }, - cryptoKey, - data + const encrypted = await encryptDataWithServerKey( + new TextEncoder().encode(text) ); // 转换为Base64 - const encryptedBase64 = btoa( - String.fromCharCode(...new Uint8Array(encrypted)) - ); + const encryptedBase64 = bytesToBase64(encrypted); // 添加前缀标识这是加密数据 return "ENCRYPTED:" + encryptedBase64; } catch (error) { console.error("Encryption error:", error); - return text; // 加密失败时返回原文本 + throw error; } } @@ -138,9 +95,6 @@ app.registerExtension({ let prompt = ""; - - - const encryptedText = await encryptText( textWidget.value ); diff --git a/ts/utils/base64Utils.ts b/ts/utils/base64Utils.ts new file mode 100644 index 0000000..70db0f6 --- /dev/null +++ b/ts/utils/base64Utils.ts @@ -0,0 +1,7 @@ +export function base64ToBytes(base64: string) { + return new Uint8Array(atob(base64).split("").map(n => n.charCodeAt(0))) +} + +export function bytesToBase64(bytes: Uint8Array): string { + return btoa([...bytes].map((n) => String.fromCharCode(n)).join("")); +} diff --git a/ts/utils/cryptoUtils.ts b/ts/utils/cryptoUtils.ts index 7d8b9a8..ce7b016 100644 --- a/ts/utils/cryptoUtils.ts +++ b/ts/utils/cryptoUtils.ts @@ -71,12 +71,14 @@ async function encryptData(data: Uint8Array, publicKeyPem: string): Promise { - const serverKeys = await getServerKeysWithExchange(); - // 读取文件内容 const arrayBuffer = await file.arrayBuffer(); const data = new Uint8Array(arrayBuffer); + return await encryptDataWithServerKey(data); +} +export async function encryptDataWithServerKey(data: Uint8Array): Promise { + const serverKeys = await getServerKeysWithExchange(); return await encryptData(data, serverKeys.publicKey); } @@ -167,7 +169,7 @@ async function decryptData(encryptedData: Uint8Array, privateKeyPem: string): Pr * @param encryptedData 加密的数据 * @returns 解密后的数据 */ -export async function decryptFileWithServerKey(encryptedData: Uint8Array): Promise { +export async function decryptDataWithServerKey(encryptedData: Uint8Array): Promise { const serverKeys = await getServerKeysWithExchange(); return await decryptData(encryptedData, serverKeys.privateKey); } diff --git a/ts/utils/imageLoader.ts b/ts/utils/imageLoader.ts index c43a7c4..643d25a 100644 --- a/ts/utils/imageLoader.ts +++ b/ts/utils/imageLoader.ts @@ -4,7 +4,7 @@ */ import type { ComfyApi } from "@comfyorg/comfyui-frontend-types"; -import { decryptFileWithServerKey, decryptFileWithClientKey } from "./cryptoUtils.js"; +import { decryptDataWithServerKey, decryptFileWithClientKey } from "./cryptoUtils.js"; import { getMimeTypeFromFilename } from "./fileUtils.js"; export interface ImageLoadParams { @@ -33,7 +33,7 @@ export async function loadEncryptedImageFromFilename(filename: string): Promise< const encryptedData = new Uint8Array(encryptedArrayBuffer); // 使用服务端私钥解密(UploadImage场景) - const decryptedData = await decryptFileWithServerKey(encryptedData); + const decryptedData = await decryptDataWithServerKey(encryptedData); // 转换为Blob URL const blob = new Blob([new Uint8Array(decryptedData)], {