Blame Raw
· · · 101 lines (3.3 KB)
0 contributors
1import path from 'node:path';
2import fs from 'node:fs';
3
4import express from 'express';
5import sanitize from 'sanitize-filename';
6import { sync as writeFileSyncAtomic } from 'write-file-atomic';
7
8import { validateAssetFileName } from './assets.js';
9import { clientRelativePath } from '../util.js';
10
11export const router = express.Router();
12
13router.post('/sanitize-filename', async (request, response) => {
14 try {
15 const fileName = String(request.body.fileName);
16 if (!fileName) {
17 return response.status(400).send('No fileName specified');
18 }
19
20 const sanitizedFilename = sanitize(fileName);
21 return response.send({ fileName: sanitizedFilename });
22 } catch (error) {
23 console.error(error);
24 return response.sendStatus(500);
25 }
26});
27
28router.post('/upload', async (request, response) => {
29 try {
30 if (!request.body.name) {
31 return response.status(400).send('No upload name specified');
32 }
33
34 if (!request.body.data) {
35 return response.status(400).send('No upload data specified');
36 }
37
38 // Validate filename
39 const validation = validateAssetFileName(request.body.name);
40 if (validation.error)
41 return response.status(400).send(validation.message);
42
43 const pathToUpload = path.join(request.user.directories.files, request.body.name);
44 writeFileSyncAtomic(pathToUpload, request.body.data, 'base64');
45 const url = clientRelativePath(request.user.directories.root, pathToUpload);
46 console.info(`Uploaded file: ${url} from ${request.user.profile.handle}`);
47 return response.send({ path: url });
48 } catch (error) {
49 console.error(error);
50 return response.sendStatus(500);
51 }
52});
53
54router.post('/delete', async (request, response) => {
55 try {
56 if (!request.body.path) {
57 return response.status(400).send('No path specified');
58 }
59
60 const pathToDelete = path.join(request.user.directories.root, request.body.path);
61 if (!pathToDelete.startsWith(request.user.directories.files)) {
62 return response.status(400).send('Invalid path');
63 }
64
65 if (!fs.existsSync(pathToDelete)) {
66 return response.status(404).send('File not found');
67 }
68
69 fs.unlinkSync(pathToDelete);
70 console.info(`Deleted file: ${request.body.path} from ${request.user.profile.handle}`);
71 return response.sendStatus(200);
72 } catch (error) {
73 console.error(error);
74 return response.sendStatus(500);
75 }
76});
77
78router.post('/verify', async (request, response) => {
79 try {
80 if (!Array.isArray(request.body.urls)) {
81 return response.status(400).send('No URLs specified');
82 }
83
84 const verified = {};
85
86 for (const url of request.body.urls) {
87 const pathToVerify = path.join(request.user.directories.root, url);
88 if (!pathToVerify.startsWith(request.user.directories.files)) {
89 console.warn(`File verification: Invalid path: ${pathToVerify}`);
90 continue;
91 }
92 const fileExists = fs.existsSync(pathToVerify);
93 verified[url] = fileExists;
94 }
95
96 return response.send(verified);
97 } catch (error) {
98 console.error(error);
99 return response.sendStatus(500);
100 }
101});