mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 02:40:39 +09:00
Allow arbitrary issue attachments
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
517fe5093e
commit
e9c8bd4805
5 changed files with 242 additions and 13 deletions
|
|
@ -47,7 +47,12 @@ import { logger } from "../middleware/logger.js";
|
|||
import { forbidden, HttpError, unauthorized } from "../errors.js";
|
||||
import { assertCompanyAccess, getActorInfo } from "./authz.js";
|
||||
import { shouldWakeAssigneeOnCheckout } from "./issues-checkout-wakeup.js";
|
||||
import { isAllowedContentType, MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
|
||||
import {
|
||||
isInlineAttachmentContentType,
|
||||
MAX_ATTACHMENT_BYTES,
|
||||
normalizeContentType,
|
||||
SVG_CONTENT_TYPE,
|
||||
} from "../attachment-types.js";
|
||||
import { queueIssueAssignmentWakeup } from "../services/issue-assignment-wakeup.js";
|
||||
|
||||
const MAX_ISSUE_COMMENT_LIMIT = 500;
|
||||
|
|
@ -2108,11 +2113,7 @@ export function issueRoutes(
|
|||
res.status(400).json({ error: "Missing file field 'file'" });
|
||||
return;
|
||||
}
|
||||
const contentType = (file.mimetype || "").toLowerCase();
|
||||
if (!isAllowedContentType(contentType)) {
|
||||
res.status(422).json({ error: `Unsupported attachment type: ${contentType || "unknown"}` });
|
||||
return;
|
||||
}
|
||||
const contentType = normalizeContentType(file.mimetype);
|
||||
if (file.buffer.length <= 0) {
|
||||
res.status(422).json({ error: "Attachment is empty" });
|
||||
return;
|
||||
|
|
@ -2176,11 +2177,17 @@ export function issueRoutes(
|
|||
assertCompanyAccess(req, attachment.companyId);
|
||||
|
||||
const object = await storage.getObject(attachment.companyId, attachment.objectKey);
|
||||
res.setHeader("Content-Type", attachment.contentType || object.contentType || "application/octet-stream");
|
||||
const responseContentType = normalizeContentType(attachment.contentType || object.contentType);
|
||||
res.setHeader("Content-Type", responseContentType);
|
||||
res.setHeader("Content-Length", String(attachment.byteSize || object.contentLength || 0));
|
||||
res.setHeader("Cache-Control", "private, max-age=60");
|
||||
res.setHeader("X-Content-Type-Options", "nosniff");
|
||||
if (responseContentType === SVG_CONTENT_TYPE) {
|
||||
res.setHeader("Content-Security-Policy", "sandbox; default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'");
|
||||
}
|
||||
const filename = attachment.originalFilename ?? "attachment";
|
||||
res.setHeader("Content-Disposition", `inline; filename=\"${filename.replaceAll("\"", "")}\"`);
|
||||
const disposition = isInlineAttachmentContentType(responseContentType) ? "inline" : "attachment";
|
||||
res.setHeader("Content-Disposition", `${disposition}; filename=\"${filename.replaceAll("\"", "")}\"`);
|
||||
|
||||
object.stream.on("error", (err) => {
|
||||
next(err);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue