import express from 'express' import { ensureLogin } from '../../scripts/ensureLogin' import wrap from '../../scripts/asyncRoute' import * as API from '../api/admin' import { sendMail } from '../api/emailer' import { User, Login } from '../api' const router = express.Router() const apiRouter = express.Router() // Check for privilege required to access the admin panel router.use(ensureLogin, wrap(async (req, res, next) => { if (!req.session.privilege) { const u = await User.get(req.session.user) req.session.privilege = u.nw_privilege } if (req.session.user && req.session.privilege !== 5) { return res.redirect('/login') } res.locals.server_time = process.uptime() next() })) /* ================ * ASK PASSWORD * ================ */ router.get('/access', (req, res) => { if (!req.session.accesstime || req.session.accesstime < Date.now()) { return res.status(401).jsonp({ error: 'Access expired' }) } res.jsonp({ access: req.session.accesstime - Date.now() }) }) // Post password to continue router.post('/', wrap(async (req, res, next) => { if (!req.body.password) return next() if (req.body.csrf !== req.session.csrf) { req.flash('message', { error: true, text: 'Invalid session token' }) return next() } const passReady = await Login.password(req.session.user, req.body.password) if (passReady) { req.session.accesstime = Date.now() + 600000 // 10 minutes return res.redirect('/admin') } else { req.flash('message', { error: true, text: 'Invalid password' }) } next() })) // Ensure that the admin panel is not kept open for prolonged time router.use(wrap(async (req, res, next) => { if (req.session.accesstime) { if (req.session.accesstime > Date.now()) { req.session.accesstime = Date.now() + 600000 return next() } delete req.session.accesstime } res.render('user/password', { post: '/admin' }) })) /* ========= * VIEWS * ========= */ router.get('/', (req, res) => { res.render('admin/index') }) router.get('/oauth2', wrap(async (req, res) => { res.render('admin/oauth2') })) /* ======= * API * ======= */ function csrfVerify (req, res, next) { if (req.body.csrf !== req.session.csrf) { return next(new Error('Invalid session')) } next() } /* ============= * User Data * ============= */ apiRouter.get('/users', wrap(async (req, res) => { let page = parseInt(req.query.page) if (isNaN(page) || page < 1) { page = 1 } const users = await API.getAllUsers(page, req.session.user.id) res.jsonp(users) })) apiRouter.get('/user/:id', wrap(async (req, res) => { const id = parseInt(req.params.id) if (isNaN(id)) { throw new Error('Invalid number') } res.jsonp(await API.getUser(id)) })) apiRouter.post('/user', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.user_id) if (isNaN(id)) { throw new Error('Invalid or missing user ID') } res.jsonp(await API.editUser(id, req.body)) })) apiRouter.post('/user/resend_activation', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.user_id) if (isNaN(id)) { throw new Error('Invalid or missing user ID') } res.jsonp(await API.resendActivationEmail(id)) })) apiRouter.post('/user/revoke_totp', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.user_id) if (isNaN(id)) { throw new Error('Invalid or missing user ID') } res.jsonp(await API.revokeTotpToken(id)) })) apiRouter.post('/user/reset_password', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.user_id) if (isNaN(id)) { throw new Error('Invalid or missing user ID') } res.jsonp(await API.sendPasswordEmail(id)) })) apiRouter.post('/user/lock', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.user_id) if (isNaN(id)) { throw new Error('Invalid or missing user ID') } res.jsonp(await API.lockAccount(id)) })) const availableScopes = ['uuid', 'email', 'username', 'display_name'] apiRouter.get('/search/users', wrap(async (req, res) => { if (!req.query.terms) throw new Error('Please specify search terms!') const scopes = [] if (req.query.scopes) { const scq = req.query.scopes.split(',') for (const i in scq) { scq[i] = scq[i].trim() if (availableScopes.indexOf(scq[i]) !== -1) { scopes.push(scq[i]) } } } if (!scopes.length) { scopes.push('email') } const results = await API.searchUsers(req.query.terms, scopes) res.jsonp(results) })) /* =============== * OAuth2 Data * =============== */ apiRouter.get('/clients', wrap(async (req, res) => { let page = parseInt(req.query.page) if (isNaN(page) || page < 1) { page = 1 } const clients = await API.getAllClients(page) res.jsonp(clients) })) apiRouter.get('/client/:id', wrap(async (req, res) => { const id = parseInt(req.params.id) if (isNaN(id)) { throw new Error('Invalid number') } const client = await API.getClient(id) res.jsonp(client) })) apiRouter.post('/client/new', csrfVerify, wrap(async (req, res) => { await API.createClient(req.body, req.session.user) res.status(204).end() })) apiRouter.post('/client/update', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.id) if (!id || isNaN(id)) throw new Error('ID missing') await API.updateClient(id, req.body) res.status(204).end() })) apiRouter.post('/client/new_secret', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.id) if (isNaN(id)) { throw new Error('Invalid client ID') } const client = await API.newSecret(id) res.jsonp(client) })) apiRouter.post('/client/delete', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.id) if (isNaN(id)) { throw new Error('Invalid client ID') } const client = await API.removeClient(id) res.jsonp(client) })) /* ======== * Bans * ======== */ apiRouter.get('/bans', wrap(async (req, res) => { let page = parseInt(req.query.page) if (isNaN(page) || page < 1) { page = 1 } const bans = await API.getAllBans(page) res.jsonp(bans) })) apiRouter.post('/ban/pardon', csrfVerify, wrap(async (req, res) => { const id = parseInt(req.body.id) if (isNaN(id)) { throw new Error('Invalid number') } const ban = await API.removeBan(id) res.jsonp(ban) })) apiRouter.post('/ban', csrfVerify, wrap(async (req, res) => { if (!req.body.user_id) throw new Error('ID missing') const result = await API.addBan(req.body, req.session.user.id) res.jsonp(result) })) apiRouter.post('/email', csrfVerify, wrap(async (req, res) => { if (!req.body.email) throw new Error('Email missing') if (!req.body.title) throw new Error('Title missing') if (!req.body.content) throw new Error('Content missing') var message = { subject: req.body.title, html: req.body.content } const result = await sendMail(req.body.email, message) res.jsonp(result) })) apiRouter.use((err, req, res, next) => { console.error(err) return res.status(400).jsonp({ error: err.message }) }) router.use('/api', apiRouter) export default router