diff --git a/apps/web/src/common/attachments.js b/apps/web/src/common/attachments.js index dd5833b50..33e4c821f 100644 --- a/apps/web/src/common/attachments.js +++ b/apps/web/src/common/attachments.js @@ -64,3 +64,27 @@ export function getTotalSize(attachments) { } return size; } + +export async function readAttachment(hash) { + const attachment = db.attachments.attachment(hash); + if (!attachment) return; + const downloadResult = await db.fs.downloadFile( + attachment.metadata.hash, + attachment.metadata.hash, + attachment.chunkSize, + attachment.metadata + ); + if (!downloadResult) throw new Error("Failed to download file."); + + const key = await db.attachments.decryptKey(attachment.key); + if (!key) throw new Error("Invalid key for attachment."); + + return await FS.readEncrypted(attachment.metadata.hash, key, { + chunkSize: attachment.chunkSize, + iv: attachment.iv, + salt: attachment.salt, + length: attachment.length, + alg: attachment.alg, + outputType: "text" + }); +} diff --git a/apps/web/src/components/editor/index.tsx b/apps/web/src/components/editor/index.tsx index bfc7a8c35..8cc3ce782 100644 --- a/apps/web/src/components/editor/index.tsx +++ b/apps/web/src/components/editor/index.tsx @@ -37,7 +37,7 @@ import Header from "./header"; import { Attachment } from "../icons"; import { useEditorInstance } from "./context"; import { attachFile, AttachmentProgress, insertAttachment } from "./picker"; -import { downloadAttachment } from "../../common/attachments"; +import { downloadAttachment, readAttachment } from "../../common/attachments"; import { EV, EVENTS } from "@notesnook/core/common"; import { db } from "../../common/db"; import useMobile from "../../hooks/use-mobile"; @@ -278,6 +278,9 @@ export function Editor(props: EditorProps) { onDownloadAttachment={(attachment) => downloadAttachment(attachment.hash) } + onReadAttachment={(hash) => + readAttachment(hash) as Promise + } onInsertAttachment={(type) => { const mime = type === "file" ? "*/*" : "image/*"; insertAttachment(mime).then((file) => { diff --git a/apps/web/src/components/editor/tiptap.tsx b/apps/web/src/components/editor/tiptap.tsx index 40aac6ee4..f6573c498 100644 --- a/apps/web/src/components/editor/tiptap.tsx +++ b/apps/web/src/components/editor/tiptap.tsx @@ -58,6 +58,7 @@ type TipTapProps = { onChange?: (id: string, sessionId: string, content: string) => void; onInsertAttachment?: (type: AttachmentType) => void; onDownloadAttachment?: (attachment: Attachment) => void; + onReadAttachment?: (hash: string) => Promise; onAttachFile?: (file: File) => void; onFocus?: () => void; content?: string; @@ -100,6 +101,7 @@ function TipTap(props: TipTapProps) { onChange, onInsertAttachment, onDownloadAttachment, + onReadAttachment, onAttachFile, onFocus = () => {}, content, @@ -220,6 +222,9 @@ function TipTap(props: TipTapProps) { onDownloadAttachment?.(attachment); return true; }, + async onLoadWebClip(_editor, attachmentHash) { + return await onReadAttachment?.(attachmentHash); + }, onOpenLink: (url) => { window.open(url, "_blank"); return true; diff --git a/apps/web/src/interfaces/fs.js b/apps/web/src/interfaces/fs.js index 9fefe7326..3c24aff4e 100644 --- a/apps/web/src/interfaces/fs.js +++ b/apps/web/src/interfaces/fs.js @@ -181,6 +181,8 @@ async function readEncrypted(filename, key, cipherData) { return cipherData.outputType === "base64" ? Buffer.from(plainText).toString("base64") + : cipherData.outputType === "text" + ? new TextDecoder().decode(plainText) : plainText; } diff --git a/packages/core/content-types/tiptap.js b/packages/core/content-types/tiptap.js index 77c67d67c..f036f9387 100644 --- a/packages/core/content-types/tiptap.js +++ b/packages/core/content-types/tiptap.js @@ -205,6 +205,7 @@ export class Tiptap { } break; } + case "iframe": case "span": { const hash = attr[ATTRIBUTES.hash]; if (!hash) return;