diff --git a/server/models/helpers/DocumentHelper.tsx b/server/models/helpers/DocumentHelper.tsx index ff42056a1..3aca06544 100644 --- a/server/models/helpers/DocumentHelper.tsx +++ b/server/models/helpers/DocumentHelper.tsx @@ -19,9 +19,7 @@ import { import attachmentCreator from "@server/commands/attachmentCreator"; import { parser, schema } from "@server/editor"; import { trace } from "@server/logging/tracing"; -import type Document from "@server/models/Document"; -import type Revision from "@server/models/Revision"; -import User from "@server/models/User"; +import { Document, Revision, User } from "@server/models"; import FileStorage from "@server/storage/files"; import diff from "@server/utils/diff"; import parseAttachmentIds from "@server/utils/parseAttachmentIds"; @@ -112,10 +110,19 @@ export default class DocumentHelper { centered: options?.centered, }); - if (options?.signedUrls && "teamId" in document) { + if (options?.signedUrls) { + const teamId = + document instanceof Document + ? document.teamId + : (await document.$get("document"))?.teamId; + + if (!teamId) { + return output; + } + output = await DocumentHelper.attachmentsToSignedUrls( output, - document.teamId, + teamId, typeof options.signedUrls === "number" ? options.signedUrls : undefined ); } @@ -145,10 +152,10 @@ export default class DocumentHelper { static async diff( before: Document | Revision | null, after: Revision, - options?: HTMLOptions + { signedUrls, ...options }: HTMLOptions = {} ) { if (!before) { - return await DocumentHelper.toHTML(after, options); + return await DocumentHelper.toHTML(after, { ...options, signedUrls }); } const beforeHTML = await DocumentHelper.toHTML(before, options); @@ -158,11 +165,27 @@ export default class DocumentHelper { // Extract the content from the article tag and diff the HTML, we don't // care about the surrounding layout and stylesheets. - const diffedContentAsHTML = diff( + let diffedContentAsHTML = diff( beforeDOM.window.document.getElementsByTagName("article")[0].innerHTML, afterDOM.window.document.getElementsByTagName("article")[0].innerHTML ); + // Sign only the URLS in the diffed content + if (signedUrls) { + const teamId = + before instanceof Document + ? before.teamId + : (await before.$get("document"))?.teamId; + + if (teamId) { + diffedContentAsHTML = await DocumentHelper.attachmentsToSignedUrls( + diffedContentAsHTML, + teamId, + typeof signedUrls === "number" ? signedUrls : undefined + ); + } + } + // Inject the diffed content into the original document with styling and // serialize back to a string. const article = beforeDOM.window.document.querySelector("article"); @@ -318,6 +341,7 @@ export default class DocumentHelper { expiresIn = 3000 ) { const attachmentIds = parseAttachmentIds(text); + await Promise.all( attachmentIds.map(async (id) => { const attachment = await Attachment.findOne({ @@ -332,6 +356,7 @@ export default class DocumentHelper { attachment.key, expiresIn ); + text = text.replace( new RegExp(escapeRegExp(attachment.redirectUrl), "g"), signedUrl diff --git a/server/storage/files/LocalStorage.ts b/server/storage/files/LocalStorage.ts index 500dcd8e3..631a978bc 100644 --- a/server/storage/files/LocalStorage.ts +++ b/server/storage/files/LocalStorage.ts @@ -114,7 +114,7 @@ export default class LocalStorage extends BaseStorage { expiresIn, } ); - return Promise.resolve(`/api/files.get?sig=${sig}`); + return Promise.resolve(`${env.URL}/api/files.get?sig=${sig}`); }; public getFileStream(key: string) { diff --git a/shared/editor/components/Styles.ts b/shared/editor/components/Styles.ts index 056826ddc..906d070d0 100644 --- a/shared/editor/components/Styles.ts +++ b/shared/editor/components/Styles.ts @@ -249,6 +249,17 @@ const findAndReplaceStyle = () => css` } `; +const emailStyle = (props: Props) => css` + .attachment { + display: block; + color: ${props.theme.text} !important; + box-shadow: 0 0 0 1px ${props.theme.divider}; + white-space: nowrap; + border-radius: 8px; + padding: 6px 8px; + } +`; + const style = (props: Props) => ` flex-grow: ${props.grow ? 1 : 0}; justify-content: start; @@ -1546,6 +1557,7 @@ const EditorContainer = styled.div` ${codeMarkCursor} ${codeBlockStyle} ${findAndReplaceStyle} + ${emailStyle} `; export default EditorContainer; diff --git a/shared/editor/rules/links.ts b/shared/editor/rules/links.ts index 296a1dca6..0745e7bfd 100644 --- a/shared/editor/rules/links.ts +++ b/shared/editor/rules/links.ts @@ -29,6 +29,7 @@ function isAttachment(token: Token) { // external (public share are pre-signed and this is a reasonable way of detecting them) href?.startsWith("/api/attachments.redirect") || href?.startsWith("/api/files.get") || + href?.startsWith(`${env.URL}/api/files.get`) || ((href?.startsWith(env.AWS_S3_UPLOAD_BUCKET_URL) || href?.startsWith(env.AWS_S3_ACCELERATE_URL)) && href?.includes("X-Amz-Signature"))