const config = require('../../config'); const express = require('Express'); const asyncHandler = require('express-async-handler'); const jwt = require('jsonwebtoken'); const path = require('path'); const resolvePath = require('resolve-path'); const AuthTokens = require('../authtokens'); const disk = require('diskusage'); const fs = require('mz/fs'); async function checkAuthorization(req, res, repository, onVerified) { var token; if (req.headers.authorization) { if (req.headers.authorization.split(' ')[0] !== 'Bearer') { res.sendStatus(400); return; } token = req.headers.authorization.split(' ')[1]; } else if (req.cookies && req.cookies.adminToken) { token = req.cookies.adminToken; } else { res.sendStatus(403); return; } jwt.verify(token, config.jwtSecret, async (err, decoded) => { try { if (err) { res.sendStatus(403); return; } if (decoded.userId) { var user = await repository.users.getUser(decoded.userId); if (user === null || !user.active) { res.sendStatus(403); return; } else await onVerified(user); } else res.sendStatus(400); } catch (e) { console.log(e); res.sendStatus(500); } }); } module.exports = (repository) => { var router = express.Router(); router.get('/whoami', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { res.send({ userId: user.id, username: user.username, auth: user.auth }); }); })); router.get('/diskspace', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { disk.check(config.fileUpload.path, (err, info) => { if (err) { res.sendStatus(500); return; } res.send(info); }); }); })); /* Codes */ router.get('/codes', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var codes = await repository.codes.getCodes(user.hasAuth(AuthTokens.ViewAllCodes) ? null : user.id); var usernames = await repository.users.getNames(); codes.forEach((item) => { item.username = usernames[item.userId]; }); res.send(codes); }); })); router.get('/codes/:code', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var code = await repository.codes.getCode(req.params.code); if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes))) { res.sendStatus(404); return; } var user = await repository.users.getUser(code.userId); if (user !== null) code.username = user.name; res.send(code); }); })); router.post('/codes', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var postedCode = req.body; if (postedCode.id) { var code = await repository.codes.getCode(postedCode.id); if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes))) { res.sendStatus(404); return; } await repository.codes.updateCode({ id: postedCode.id, expiration: postedCode.expiration, description: postedCode.description, message: postedCode.message }); res.sendStatus(200); } else { var codeId = await repository.codes.addCode({ userId: user.id, expiration: postedCode.expiration, description: postedCode.description, message: postedCode.message }); } res.send(codeId); }); })); router.delete('/codes/:id', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var code = await repository.codes.getCode(req.params.id); if (code == null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes))) { res.sendStatus(404); return; } repository.codes.delete(code.id); res.sendStatus(200); }); })); /* Uploads */ router.get('/uploads', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var files = await repository.uploads.getUploads(user.hasAuth(AuthTokens.ViewAllUploads) ? null : user.id); var usernames = await repository.users.getNames(); var codedescriptions = await repository.codes.getDescriptions(); files.forEach((item) => { item.username = item.userId !== null ? usernames[item.userId] : null; item.codedescription = item.code !== null ? codedescriptions[item.code] : null; }); res.send(files); }); })); router.delete('/uploads/:id', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var upload = await repository.uploads.getUpload(req.params.id); if (upload == null || (upload.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllUploads))) { res.sendStatus(404); return; } repository.uploads.delete(upload.id); await Promise.all(upload.files.map(async (file) => { if (!file.id) return; if (!(await repository.uploads.fileExists(file.id))) { var fullpath = resolvePath(config.fileUpload.path, file.id); try { await fs.unlink(fullpath); } catch (err) { console.log('Failed to delete ' + fullpath); } } })); res.sendStatus(200); }); })); router.get('/download/:fileid/:displayname', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { // TODO should we check if the user has access to the file? // for now not that important, if you know the file's UID and are logged in var fullpath = resolvePath(config.fileUpload.path, req.params.fileid); res.download(fullpath, req.params.displayname); }); })); return router; }