diff --git a/src/api/routes/channels/#channel_id/attachments.ts b/src/api/routes/channels/#channel_id/attachments.ts index d515a120..d0297dce 100644 --- a/src/api/routes/channels/#channel_id/attachments.ts +++ b/src/api/routes/channels/#channel_id/attachments.ts @@ -35,6 +35,7 @@ import { import { Request, Response, Router } from "express"; import { In } from "typeorm"; import { CloudAttachment } from "../../../../util/entities/CloudAttachment"; +import fetch from "node-fetch-commonjs"; const router: Router = Router(); @@ -97,4 +98,38 @@ router.post( }, ); +router.delete("/:cloud_attachment_url", async (req: Request, res: Response) => { + const { channel_id, cloud_attachment_url } = req.params; + + const user = await User.findOneOrFail({ where: { id: req.user_id } }); + const channel = await Channel.findOneOrFail({ where: { id: channel_id } }); + const att = await CloudAttachment.findOneOrFail({ where: { uploadFilename: decodeURI(cloud_attachment_url) } }); + if (att.userId !== user.id) { + return res.status(403).json({ + code: 403, + message: "You do not own this attachment.", + }); + } + + if (att.channelId !== channel.id) { + return res.status(400).json({ + code: 400, + message: "Attachment does not belong to this channel.", + }); + } + + const response = await fetch( + `${Config.get().cdn.endpointPrivate || "http://localhost:3001"}/attachments/${att.uploadFilename}`, + { + headers: { + signature: Config.get().security.requestSignature + }, + method: "DELETE", + }, + ); + + await att.remove(); + return res.status(response.status).send(response.body); +}); + export default router; diff --git a/src/cdn/routes/attachments.ts b/src/cdn/routes/attachments.ts index fbab566a..2ab75224 100644 --- a/src/cdn/routes/attachments.ts +++ b/src/cdn/routes/attachments.ts @@ -124,13 +124,13 @@ router.put("/:channel_id/:batch_id/:attachment_id/:filename", multer.single("fil uploadFilename: `${channel_id}/${batch_id}/${attachment_id}/${filename}`, channelId: channel_id, userAttachmentId: attachment_id, - userFilename: filename + userFilename: filename, }, }); const maxLength = Config.get().cdn.maxAttachmentSize; - console.log("[Cloud Upload] Uploading attachment", att.id, att.userFilename, `Max size: ${maxLength} bytes\n`, att); + console.log("[Cloud Upload] Uploading attachment", att.id, att.userFilename, `Max size: ${maxLength} bytes`); const chunks: Buffer[] = []; let length = 0; @@ -161,9 +161,32 @@ router.put("/:channel_id/:batch_id/:attachment_id/:filename", multer.single("fil att.size = buffer.length; await att.save(); - console.log("[Cloud Upload] Saved attachment", att.id, att.userFilename, att); + console.log("[Cloud Upload] Saved attachment", att.id, att.userFilename); res.status(200).end(); }); }); +router.delete("/:channel_id/:batch_id/:attachment_id/:filename", async (req: Request, res: Response) => { + if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature"); + + const { channel_id, batch_id, attachment_id, filename } = req.params; + const path = `attachments/${channel_id}/${batch_id}/${attachment_id}/${filename}`; + + const att = await CloudAttachment.findOne({ + where: { + uploadFilename: `${channel_id}/${batch_id}/${attachment_id}/${filename}`, + channelId: channel_id, + userAttachmentId: attachment_id, + userFilename: filename, + }, + }); + + if (att) { + await att.remove(); + await storage.delete(path); + return res.send({ success: true }); + } + return res.status(404).send("Attachment not found"); +}); + export default router;