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 ExpirationUnits = require('../expirationunits'); 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.get(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.list(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/:id', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var code = await repository.codes.get(req.params.id); if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes))) { res.sendStatus(404); return; } var user = await repository.users.get(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 (config.code.maxExpiration !== null) { let now = new Date(); if (ExpirationUnits.apply(postedCode.expiration) > ExpirationUnits.apply(config.code.maxExpiration)) { res.sendStatus(400); return; } } if (postedCode.id) { var code = await repository.codes.get(postedCode.id); if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes))) { res.sendStatus(404); return; } await repository.codes.update({ id: postedCode.id, expiration: postedCode.expiration, description: postedCode.description, message: postedCode.message }); res.sendStatus(200); } else { var codeId = await repository.codes.insert({ userId: user.id, created: postedCode.created || new Date(), 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.get(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); }); })); router.get('/maxExpiration', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { res.send(config.code.maxExpiration !== null ? config.code.maxExpiration : { units: '', value: 1 }); }); })); /* Uploads */ router.get('/uploads', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var files = await repository.uploads.list(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.get(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); }); })); /* Users */ router.get('/users', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { if (!user.hasAuth(AuthTokens.ManageUsers)) { res.sendStatus(403); return; } var users = await repository.users.list(); res.send(users); }); })); router.get('/users/:id', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { if (req.params.id !== user.id && !user.hasAuth(AuthTokens.ManageUsers)) { res.sendStatus(404); return; } var user = await repository.users.get(req.params.id); if (user === null) { res.sendStatus(404); return; } res.send(user); }); })); router.post('/users', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { var postedUser = req.body; if (postedUser.id) { if (postedUser.id !== user.id && !user.hasAuth(AuthTokens.ManageUsers)) { res.sendStatus(403); return; } await repository.users.update({ id: postedUser.id, username: postedUser.username, name: postedUser.name, password: postedUser.password, email: postedUser.email, auth: postedUser.auth, active: postedUser.active }); res.sendStatus(200); } else { if (!user.hasAuth(AuthTokens.ManageUsers)) { res.sendStatus(403); return; } var userId = await repository.users.insert({ username: postedUser.username, name: postedUser.name, password: postedUser.password, email: postedUser.email, auth: postedUser.auth, active: postedUser.active, createdByUserId: postedUser.createdByUserId }); } res.send(userId); }); })); router.delete('/users/:id', asyncHandler(async (req, res) => { await checkAuthorization(req, res, repository, async (user) => { if (!user.hasAuth(AuthTokens.ManageUsers)) { res.sendStatus(403); return; } repository.users.delete(req.params.id); res.sendStatus(200); }); })); return router; }