2018-03-22 15:45:11 +00:00
|
|
|
const config = require('../../config');
|
2018-05-02 09:32:43 +00:00
|
|
|
const express = require('express');
|
2018-03-22 15:45:11 +00:00
|
|
|
const asyncHandler = require('express-async-handler');
|
|
|
|
const jwt = require('jsonwebtoken');
|
2018-04-26 14:34:07 +00:00
|
|
|
const path = require('path');
|
|
|
|
const resolvePath = require('resolve-path');
|
2018-04-26 13:39:21 +00:00
|
|
|
const AuthTokens = require('../authtokens');
|
2018-05-02 18:07:09 +00:00
|
|
|
const ExpirationUnits = require('../expirationunits');
|
2018-04-27 15:13:18 +00:00
|
|
|
const disk = require('diskusage');
|
2018-04-28 07:24:53 +00:00
|
|
|
const fs = require('mz/fs');
|
2018-03-22 15:45:11 +00:00
|
|
|
|
|
|
|
|
2018-04-26 13:39:21 +00:00
|
|
|
async function checkAuthorization(req, res, repository, onVerified)
|
2018-03-22 15:45:11 +00:00
|
|
|
{
|
2018-04-26 14:34:07 +00:00
|
|
|
var token;
|
|
|
|
|
|
|
|
if (req.headers.authorization)
|
2018-03-22 15:45:11 +00:00
|
|
|
{
|
2018-04-26 14:34:07 +00:00
|
|
|
if (req.headers.authorization.split(' ')[0] !== 'Bearer')
|
|
|
|
{
|
|
|
|
res.sendStatus(400);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
token = req.headers.authorization.split(' ')[1];
|
|
|
|
}
|
2018-04-28 07:51:58 +00:00
|
|
|
else if (req.cookies && req.cookies.adminToken)
|
2018-04-26 14:34:07 +00:00
|
|
|
{
|
2018-04-28 07:51:58 +00:00
|
|
|
token = req.cookies.adminToken;
|
2018-04-26 14:34:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res.sendStatus(403);
|
2018-03-22 15:45:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:34:07 +00:00
|
|
|
|
2018-03-22 15:45:11 +00:00
|
|
|
jwt.verify(token, config.jwtSecret, async (err, decoded) =>
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
res.sendStatus(403);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (decoded.userId)
|
2018-04-26 13:39:21 +00:00
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var user = await repository.users.get(decoded.userId);
|
2018-04-26 13:39:21 +00:00
|
|
|
if (user === null || !user.active)
|
|
|
|
{
|
|
|
|
res.sendStatus(403);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
await onVerified(user);
|
|
|
|
}
|
2018-03-22 15:45:11 +00:00
|
|
|
else
|
|
|
|
res.sendStatus(400);
|
|
|
|
}
|
|
|
|
catch (e)
|
|
|
|
{
|
|
|
|
console.log(e);
|
|
|
|
res.sendStatus(500);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = (repository) =>
|
|
|
|
{
|
|
|
|
var router = express.Router();
|
|
|
|
|
2018-04-26 13:39:21 +00:00
|
|
|
|
|
|
|
router.get('/whoami', asyncHandler(async (req, res) =>
|
|
|
|
{
|
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
|
|
|
{
|
|
|
|
res.send({
|
2018-04-28 07:51:58 +00:00
|
|
|
userId: user.id,
|
2018-04-26 13:39:21 +00:00
|
|
|
username: user.username,
|
|
|
|
auth: user.auth
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
2018-04-27 15:13:18 +00:00
|
|
|
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
|
|
|
|
*/
|
2018-03-22 15:45:11 +00:00
|
|
|
router.get('/codes', asyncHandler(async (req, res) =>
|
|
|
|
{
|
2018-04-26 13:39:21 +00:00
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
2018-03-22 15:45:11 +00:00
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var codes = await repository.codes.list(user.hasAuth(AuthTokens.ViewAllCodes) ? null : user.id);
|
2018-04-28 07:24:53 +00:00
|
|
|
var usernames = await repository.users.getNames();
|
2018-04-26 12:08:08 +00:00
|
|
|
|
|
|
|
codes.forEach((item) =>
|
|
|
|
{
|
|
|
|
item.username = usernames[item.userId];
|
|
|
|
});
|
|
|
|
|
|
|
|
res.send(codes);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
2018-04-28 08:18:27 +00:00
|
|
|
router.get('/codes/:id', asyncHandler(async (req, res) =>
|
2018-04-27 15:13:18 +00:00
|
|
|
{
|
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var code = await repository.codes.get(req.params.id);
|
2018-04-28 07:51:58 +00:00
|
|
|
if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes)))
|
2018-04-27 15:13:18 +00:00
|
|
|
{
|
|
|
|
res.sendStatus(404);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-28 08:18:27 +00:00
|
|
|
var user = await repository.users.get(code.userId);
|
2018-04-27 15:13:18 +00:00
|
|
|
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;
|
|
|
|
|
2018-05-02 18:07:09 +00:00
|
|
|
|
|
|
|
if (config.code.maxExpiration !== null)
|
|
|
|
{
|
|
|
|
let now = new Date();
|
|
|
|
|
|
|
|
if (ExpirationUnits.apply(postedCode.expiration) > ExpirationUnits.apply(config.code.maxExpiration))
|
|
|
|
{
|
|
|
|
res.sendStatus(400);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-27 15:13:18 +00:00
|
|
|
if (postedCode.id)
|
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var code = await repository.codes.get(postedCode.id);
|
2018-04-28 07:51:58 +00:00
|
|
|
if (code === null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes)))
|
2018-04-27 15:13:18 +00:00
|
|
|
{
|
|
|
|
res.sendStatus(404);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-28 08:18:27 +00:00
|
|
|
await repository.codes.update({
|
2018-04-27 15:13:18 +00:00
|
|
|
id: postedCode.id,
|
|
|
|
expiration: postedCode.expiration,
|
|
|
|
description: postedCode.description,
|
|
|
|
message: postedCode.message
|
|
|
|
});
|
|
|
|
|
|
|
|
res.sendStatus(200);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var codeId = await repository.codes.insert({
|
2018-04-27 15:13:18 +00:00
|
|
|
userId: user.id,
|
2018-05-02 18:07:09 +00:00
|
|
|
created: postedCode.created || new Date(),
|
2018-04-27 15:13:18 +00:00
|
|
|
expiration: postedCode.expiration,
|
|
|
|
description: postedCode.description,
|
|
|
|
message: postedCode.message
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
res.send(codeId);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
2018-04-28 07:51:58 +00:00
|
|
|
router.delete('/codes/:id', asyncHandler(async (req, res) =>
|
|
|
|
{
|
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var code = await repository.codes.get(req.params.id);
|
2018-04-28 07:51:58 +00:00
|
|
|
if (code == null || (code.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllCodes)))
|
|
|
|
{
|
|
|
|
res.sendStatus(404);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
repository.codes.delete(code.id);
|
|
|
|
res.sendStatus(200);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2018-05-02 18:07:09 +00:00
|
|
|
|
|
|
|
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 });
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2018-04-27 15:13:18 +00:00
|
|
|
/*
|
|
|
|
Uploads
|
|
|
|
*/
|
2018-04-26 12:08:08 +00:00
|
|
|
router.get('/uploads', asyncHandler(async (req, res) =>
|
|
|
|
{
|
2018-04-26 13:39:21 +00:00
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
2018-04-26 12:08:08 +00:00
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var files = await repository.uploads.list(user.hasAuth(AuthTokens.ViewAllUploads) ? null : user.id);
|
2018-04-28 07:24:53 +00:00
|
|
|
var usernames = await repository.users.getNames();
|
|
|
|
var codedescriptions = await repository.codes.getDescriptions();
|
2018-04-26 12:08:08 +00:00
|
|
|
|
|
|
|
files.forEach((item) =>
|
|
|
|
{
|
2018-04-28 07:24:53 +00:00
|
|
|
item.username = item.userId !== null ? usernames[item.userId] : null;
|
|
|
|
item.codedescription = item.code !== null ? codedescriptions[item.code] : null;
|
2018-04-26 12:08:08 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
res.send(files);
|
2018-03-22 15:45:11 +00:00
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2018-04-26 12:08:08 +00:00
|
|
|
|
2018-04-28 07:24:53 +00:00
|
|
|
router.delete('/uploads/:id', asyncHandler(async (req, res) =>
|
|
|
|
{
|
|
|
|
await checkAuthorization(req, res, repository, async (user) =>
|
|
|
|
{
|
2018-04-28 08:18:27 +00:00
|
|
|
var upload = await repository.uploads.get(req.params.id);
|
2018-04-28 07:51:58 +00:00
|
|
|
if (upload == null || (upload.userId !== user.id && !user.hasAuth(AuthTokens.ViewAllUploads)))
|
2018-04-28 07:24:53 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
2018-04-26 14:34:07 +00:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
2018-04-28 08:18:27 +00:00
|
|
|
/*
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
2018-03-22 15:45:11 +00:00
|
|
|
return router;
|
|
|
|
}
|