feat & refactor: 支持app端签名的请求,支持右键操作书架书籍,逻辑大幅重构,更改默认的设备逻辑为自动注册,支持载入某些书籍内置的CSS、支持跳转正文注释等等

This commit is contained in:
naiy committed 2026-08-03 16:17:49 +08:00
1 parent 2f2ee606c0
commit 3586b01dbb
47 files changed
+3594 -243

No files matched your search

+65
View File
@@ -0,0 +1,65 @@
import { defaultConfig, type DeviceConfig } from "../config";
import { b64decode, getSubtle, unhex } from ".";
// 正文算法: AES/CBC/PKCS5Padding
// 返回 string(xhtml/html) | 章节 JSON 对象 | undefined(解析失败)
export async function decryptChapter(
encrypted: string,
config: DeviceConfig = defaultConfig,
): Promise<string | unknown> {
if (!encrypted) {
throw new Error("Invalid encrypted chapter");
};
const buf = b64decode(encrypted);
const iv = buf.slice(0, 16);
const data = buf.slice(16);
const key = config.key_info?.key;
if (!key) {
throw new Error("Missing decrypt key")
}
const subtle = getSubtle();
const cryptoKey = await subtle.importKey(
"raw",
key,
{ name: "AES-CBC" },
false,
["decrypt"],
);
return subtle.decrypt(
{ name: "AES-CBC", iv },
cryptoKey,
data,
).then((decrypted) => {
const decoder = new TextDecoder();
const plain = decoder.decode(decrypted);
if (plain.trim().startsWith("<")) { // xhtml || html
return plain;
}
try {
return JSON.parse(plain); // mostly JSONObject
} catch (e: any) {
console.warn('Invalid chapter content: ', plain, e);
return undefined;
}
});
}
export async function decryptComicImage(image: ArrayBuffer, key: string /* hex */): Promise<ArrayBuffer> {
const subtle = getSubtle();
// AESGCM
const cryptoKey = await subtle.importKey(
"raw",
unhex(key),
{ name: "AES-GCM" },
false,
["decrypt"],
);
const iv = image.slice(0, 12);
const data = image.slice(12);
return await subtle.decrypt(
{ name: "AES-GCM", iv },
cryptoKey,
data,
);
}