const express = require('express'); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); const request = require('request'); const crypto = require('crypto'); const uuidv4 = require('uuid/v4'); const Op = require('sequelize').Op; const multer = require('multer'); var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'src/uploads/') }, filename: function (req, file, cb) { var ext = ""; if (file.originalname.includes(".")) { ext = "." + file.originalname.split(".")[1]; } return cb(null, 'img-' + Date.now() + ext) } }) var upload = multer({ storage: storage }) const server = express(); server.use(cookieParser()) server.use(bodyParser.urlencoded({ extended: true })); async function addImagesAndTagsToPosts(models, posts) { for (const post of posts) { const images = await models.pictures.findAll({ attributes: ["source"], where: { postId: post.id } }).map(x => x.source); post.images = images; const tags = await models.tags.findAll({ attributes: ["text"], where: { postId: post.id } }).map(x => x.text); post.tags = tags; } } function listen(port) { server.listen(port, () => console.info(`Listening on port ${port}!`)); } function setUpRoutes(models, jwtFunctions, database) { // Authentication routine server.use(function (req, res, next) { if (req.path.startsWith("/admin")) { let cookie = req.cookies.authorization if (!cookie) { console.debug("Redirecting to login - no cookie") res.redirect('/login'); return; } try { const decryptedUserId = jwtFunctions.verify(cookie); models.users.findOne({ where: { username: decryptedUserId } }).then((user, error) => { if (user) { res.locals.user = user.get({ plain: true }); } else { console.debug("Redirecting to login - invalid cookie") res.redirect('/login'); return; } }); } catch (e) { res.status(400).send(e.message); } } next(); }) // Route logging server.use(function (req, res, next) { let cookie = req.cookies.session; if (!cookie) { cookie = uuidv4(); res.cookie('session', session, { expires: new Date(Date.now() + (1000 * 60 * 60)) }); } models.requests.create({ createdAt: new Date(), session: cookie, method: req.method, url: req.originalUrl }); next() }) server.get('/', (req, res) => res.sendFile(__dirname + "/html/index.html")) server.get('/index', (req, res) => res.sendFile(__dirname + "/html/index.html")) server.get('/admin', (req, res) => res.sendFile(__dirname + "/html/admin.html")); server.get('/login', (req, res) => res.sendFile(__dirname + "/html/login.html")) server.get('/bread', (req, res) => res.sendFile(__dirname + "/html/bread.html")); server.get('/blog', (req, res) => res.sendFile(__dirname + "/html/blog.html")); server.get('/tags', (req, res) => res.sendFile(__dirname + "/html/tags.html")); server.get('/feed', (req, res) => res.sendFile(__dirname + "/html/feed.html")); server.get('/essay', (req, res) => res.sendFile(__dirname + "/html/essay.html")); server.get('/snake', (req, res) => res.sendFile(__dirname + "/html/snake.html")); server.get('/setScore', (req, res) => { request(`http://localhost:8000?${req.url.split("?")[1]}`, function (error, response, body) { }); }) server.get('/admin/stats', async (req, res, next) => { try { var sessionResult = await database.query("SELECT session, count(id) as c FROM requests GROUP BY session", { type: database.QueryTypes.SELECT }) var urlResult = await database.query("SELECT method, url, count(id) as c FROM requests GROUP BY method, url", { type: database.QueryTypes.SELECT }) res.status(200).send({ session: sessionResult, url: urlResult }); next(); } catch (e) { res.status(400).send(e.message); } }) server.get('/blog/:id', async (req, res, next) => { // TODO add single page blog posts }) server.get('/tags/:name', async (req, res, next) => { console.log("TAGS/NAME"); try { const { name } = req.params; const postsWithTag = await models.tags.findAll({ attributes: ["postId"], where: { text: name } }) .map(function (x) { return { id: x.postId } }); var posts = await models.posts.findAll({ where: { [Op.or]: postsWithTag }, order: [['createdAt', 'DESC']] }); posts = posts.map(x => x.get({ plain: true })); await addImagesAndTagsToPosts(models, posts) console.log(posts); res.status(200).send(posts); next(); } catch (e) { console.error(e); res.status(400).send(e.message); } }) server.get('/posts/:type', async (req, res, next) => { try { const { type } = req.params; var posts = await models.posts.findAll({ where: { type: type }, order: [['createdAt', 'DESC']] }); posts = posts.map(x => x.get({ plain: true })); await addImagesAndTagsToPosts(models, posts) res.status(200).send(posts); next(); } catch (e) { res.status(400).send(e.message); } }) server.post('/posts', upload.array('images'), async (req, res, next) => { try { const type = req.body.type const newPost = await models.posts.create(req.body); req.files.forEach(async (file) => { await models.pictures.create({ "source": "uploads/" + file.filename, "postId": newPost.id }); console.log("uploaded ", file.path); }) req.body.tags.split(" ").forEach(async (tag) => { await models.tags.create({ "text": tag, "postId": newPost.id }); }) console.log(newPost); res.redirect(`/${type}`); next(); } catch (e) { res.status(400).send(e.message); } }) server.post('/login', async (req, res, next) => { const hash = crypto.createHash("sha512").update(req.body.password, "binary").digest("base64"); const user = await models.users.findOne({ where: { username: req.body.username, password: hash } }) if (user) { const token = jwtFunctions.sign(user.username); res.cookie('authorization', token, { expires: new Date(Date.now() + (1000 * 60 * 60)) }); console.debug("Redirecting to admin - logged in") res.redirect('/admin'); } else { console.debug("Redirecting to login - invalid login") res.redirect('/login'); } }) server.get('/favicon.ico', (req, res) => res.sendFile(__dirname + "/icon/favicon.ico")) server.get('/css/:id', (req, res) => { res.sendFile(__dirname + "/css/" + req.params.id); }); server.get('/uploads/:id', (req, res) => { res.sendFile(__dirname + "/uploads/" + req.params.id); }); server.get('/essay/:id', (req, res) => { res.sendFile(__dirname + "/html/essay/" + req.params.id); }); server.get('/js/:id', (req, res) => { res.sendFile(__dirname + "/js/" + req.params.id); }); } module.exports = { listen, setUpRoutes };