mirror of
https://github.com/spacebarchat/server.git
synced 2026-10-23 06:32:34 +00:00
Fix attachments
This commit is contained in:
1 parent
5b501fa8da
commit
103922e841
16 files changed
+141
-117
No files matched your search
+1
-22
@@ -17,12 +17,11 @@
|
||||
*/
|
||||
|
||||
import { Server, ServerOptions } from "lambert-server";
|
||||
import { Attachment, Config, initDatabase, registerRoutes } from "@spacebar/util";
|
||||
import { Config, initDatabase, registerRoutes } from "@spacebar/util";
|
||||
import { CORS, BodyParser } from "@spacebar/api";
|
||||
import path from "path";
|
||||
import guildProfilesRoute from "./routes/guild-profiles";
|
||||
import morgan from "morgan";
|
||||
import { Like } from "typeorm";
|
||||
|
||||
export type CDNServerOptions = ServerOptions;
|
||||
|
||||
@@ -36,7 +35,6 @@ export class CDNServer extends Server {
|
||||
async start() {
|
||||
await initDatabase();
|
||||
await Config.init();
|
||||
await this.cleanupSignaturesInDb();
|
||||
|
||||
const logRequests = process.env["LOG_REQUESTS"] != undefined;
|
||||
if (logRequests) {
|
||||
@@ -73,23 +71,4 @@ export class CDNServer extends Server {
|
||||
async stop() {
|
||||
return super.stop();
|
||||
}
|
||||
|
||||
async cleanupSignaturesInDb() {
|
||||
console.log("[CDN] Cleaning up signatures in database");
|
||||
const attachmentsToFix = await Attachment.find({
|
||||
where: { url: Like("%?ex=%") },
|
||||
});
|
||||
if (attachmentsToFix.length === 0) {
|
||||
console.log("[CDN] No attachments to fix");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[CDN] Found", attachmentsToFix.length, " attachments to fix");
|
||||
for (const attachment of attachmentsToFix) {
|
||||
attachment.url = attachment.url.split("?ex=")[0];
|
||||
attachment.proxy_url = attachment.proxy_url?.split("?ex=")[0];
|
||||
await attachment.save();
|
||||
console.log(`[CDN] Fixed attachment ${attachment.id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Config, hasValidSignature, NewUrlUserSignatureData, Snowflake, UrlSignResult } from "@spacebar/util";
|
||||
import { Attachment, Config, hasValidSignature, NewUrlUserSignatureData, Snowflake, UrlSignResult } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import imageSize from "image-size";
|
||||
import { HTTPError } from "lambert-server";
|
||||
@@ -30,16 +30,16 @@ const router = Router({ mergeParams: true });
|
||||
|
||||
const SANITIZED_CONTENT_TYPE = ["text/html", "text/mhtml", "multipart/related", "application/xhtml+xml"];
|
||||
|
||||
router.post("/:channel_id", multer.single("file"), async (req: Request, res: Response) => {
|
||||
if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature");
|
||||
router.post("/:channel_id/:message_id", multer.single("file"), async (req: Request, res: Response) => {
|
||||
if (req.headers.signature !== Config.get().security.requestSignature)
|
||||
throw new HTTPError(`Invalid request signature, expected '${Config.get().security.requestSignature}', got ${req.headers.signature}`);
|
||||
|
||||
if (!req.file) throw new HTTPError("file missing");
|
||||
|
||||
const { buffer, mimetype, size, originalname } = req.file;
|
||||
const { channel_id } = req.params as { [key: string]: string };
|
||||
const { channel_id, message_id } = req.params as { [key: string]: string };
|
||||
const filename = originalname.replaceAll(" ", "_").replace(/[^a-zA-Z0-9._]+/g, "");
|
||||
const id = Snowflake.generate();
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
const path = `attachments/${channel_id}/${message_id}/${filename}`;
|
||||
|
||||
const endpoint = Config.get()?.cdn.endpointPublic;
|
||||
|
||||
@@ -57,7 +57,9 @@ router.post("/:channel_id", multer.single("file"), async (req: Request, res: Res
|
||||
const finalUrl = `${endpoint}/${path}`;
|
||||
|
||||
const file = {
|
||||
id,
|
||||
id: Snowflake.generate(),
|
||||
channel_id,
|
||||
message_id,
|
||||
content_type: mimetype,
|
||||
filename: filename,
|
||||
size,
|
||||
@@ -70,11 +72,11 @@ router.post("/:channel_id", multer.single("file"), async (req: Request, res: Res
|
||||
return res.json(file);
|
||||
});
|
||||
|
||||
router.get("/:channel_id/:id/:filename", cache, async (req: Request, res: Response) => {
|
||||
const { channel_id, id, filename } = req.params as { [key: string]: string };
|
||||
router.get("/:channel_id/:message_id/:filename", cache, async (req: Request, res: Response) => {
|
||||
const { channel_id, message_id, filename } = req.params as { [key: string]: string };
|
||||
// const { format } = req.query;
|
||||
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
const path = `attachments/${channel_id}/${message_id}/${filename}`;
|
||||
|
||||
const fullUrl = (req.headers["x-forwarded-proto"] ?? req.protocol) + "://" + (req.headers["x-forwarded-host"] ?? req.hostname) + req.originalUrl;
|
||||
|
||||
@@ -91,14 +93,24 @@ router.get("/:channel_id/:id/:filename", cache, async (req: Request, res: Respon
|
||||
}),
|
||||
UrlSignResult.fromUrl(fullUrl),
|
||||
);
|
||||
console.warn("[CDN/Attachments] Client sent invalid attachment URL signature");
|
||||
if (!hasValidAuth) console.warn("[CDN/Attachments] Client sent invalid attachment URL signature");
|
||||
}
|
||||
|
||||
if (!hasValidAuth) {
|
||||
return res.status(404).send("This content is no longer available.");
|
||||
}
|
||||
if (!hasValidAuth) return res.status(404).send("This content is no longer available.");
|
||||
|
||||
const file = await storage.get(path);
|
||||
let file = await storage.get(path);
|
||||
// handle re-keying paths to be correct
|
||||
if (!file) {
|
||||
const att = await Attachment.findOne({ where: { id: message_id, channel_id: channel_id } });
|
||||
if (att) {
|
||||
const oldPath = `attachments/${channel_id}/${att.id}/${filename}`;
|
||||
if (await storage.exists(oldPath)) {
|
||||
console.log(`[CDN/Attachments] Moving ${oldPath} -> ${path}!`);
|
||||
await storage.move(oldPath, path);
|
||||
file = await storage.get(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file) throw new HTTPError("File not found");
|
||||
const type = await fileTypeFromBuffer(file);
|
||||
let content_type = type?.mime || "application/octet-stream";
|
||||
@@ -112,11 +124,11 @@ router.get("/:channel_id/:id/:filename", cache, async (req: Request, res: Respon
|
||||
return res.send(file);
|
||||
});
|
||||
|
||||
router.delete("/:channel_id/:id/:filename", async (req: Request, res: Response) => {
|
||||
router.delete("/:channel_id/:message_id/:filename", async (req: Request, res: Response) => {
|
||||
if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature");
|
||||
|
||||
const { channel_id, id, filename } = req.params as { [key: string]: string };
|
||||
const path = `attachments/${channel_id}/${id}/${filename}`;
|
||||
const { channel_id, message_id, filename } = req.params as { [key: string]: string };
|
||||
const path = `attachments/${channel_id}/${message_id}/${filename}`;
|
||||
|
||||
await storage.delete(path);
|
||||
|
||||
|
||||
Reference in new issue
Block a user