tokenController.js + authController.js:
+ Added a standalone function to generate unique token.
Despite tokens being 64 characters long, meaning the chance to generate
the same token twice have very small chances, I would rather not leave
it to chances.
+ Some spacings.

config.sample.js:
+ Self-explanatory.
This commit is contained in:
Bobby Wibowo 2019-06-19 04:04:14 +07:00
parent add2970ae6
commit 0516ec2f2f
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
3 changed files with 41 additions and 11 deletions

View File

@ -129,7 +129,7 @@ module.exports = {
], ],
config: { config: {
windowMs: 30 * 1000, windowMs: 30 * 1000,
max: 1 max: 2
} }
} }
], ],

View File

@ -3,6 +3,7 @@ const config = require('./../config')
const db = require('knex')(config.database) const db = require('knex')(config.database)
const perms = require('./permissionController') const perms = require('./permissionController')
const randomstring = require('randomstring') const randomstring = require('randomstring')
const tokens = require('./tokenController')
const utils = require('./utilsController') const utils = require('./utilsController')
const authController = {} const authController = {}
@ -38,8 +39,10 @@ authController.register = async (req, res, next) => {
const username = req.body.username const username = req.body.username
const password = req.body.password const password = req.body.password
if (username === undefined) return res.json({ success: false, description: 'No username provided.' }) if (username === undefined)
if (password === undefined) return res.json({ success: false, description: 'No password provided.' }) return res.json({ success: false, description: 'No username provided.' })
if (password === undefined)
return res.json({ success: false, description: 'No password provided.' })
if (username.length < 4 || username.length > 32) if (username.length < 4 || username.length > 32)
return res.json({ success: false, description: 'Username must have 4-32 characters.' }) return res.json({ success: false, description: 'Username must have 4-32 characters.' })
@ -48,14 +51,19 @@ authController.register = async (req, res, next) => {
return res.json({ success: false, description: 'Password must have 6-64 characters.' }) return res.json({ success: false, description: 'Password must have 6-64 characters.' })
const user = await db.table('users').where('username', username).first() const user = await db.table('users').where('username', username).first()
if (user) return res.json({ success: false, description: 'Username already exists.' }) if (user)
return res.json({ success: false, description: 'Username already exists.' })
bcrypt.hash(password, 10, async (error, hash) => { bcrypt.hash(password, 10, async (error, hash) => {
if (error) { if (error) {
console.error(error) console.error(error)
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻.' }) return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻.' })
} }
const token = randomstring.generate(64)
const token = await tokens.generateUniqueToken()
if (!token)
return res.json({ success: false, description: 'Error generating unique token (╯°□°)╯︵ ┻━┻.' })
await db.table('users').insert({ await db.table('users').insert({
username, username,
password: hash, password: hash,
@ -63,6 +71,7 @@ authController.register = async (req, res, next) => {
enabled: 1, enabled: 1,
permission: perms.permissions.user permission: perms.permissions.user
}) })
utils.invalidateStatsCache('users') utils.invalidateStatsCache('users')
return res.json({ success: true, token }) return res.json({ success: true, token })
}) })
@ -73,7 +82,8 @@ authController.changePassword = async (req, res, next) => {
if (!user) return if (!user) return
const password = req.body.password const password = req.body.password
if (password === undefined) return res.json({ success: false, description: 'No password provided.' }) if (password === undefined)
return res.json({ success: false, description: 'No password provided.' })
if (password.length < 6 || password.length > 64) if (password.length < 6 || password.length > 64)
return res.json({ success: false, description: 'Password must have 6-64 characters.' }) return res.json({ success: false, description: 'Password must have 6-64 characters.' })
@ -214,12 +224,14 @@ authController.listUsers = async (req, res, next) => {
if (!user) return if (!user) return
const isadmin = perms.is(user, 'admin') const isadmin = perms.is(user, 'admin')
if (!isadmin) return res.status(403).end() if (!isadmin)
return res.status(403).end()
const count = await db.table('users') const count = await db.table('users')
.count('id as count') .count('id as count')
.then(rows => rows[0].count) .then(rows => rows[0].count)
if (!count) return res.json({ success: true, users: [], count }) if (!count)
return res.json({ success: true, users: [], count })
let offset = req.params.page let offset = req.params.page
if (offset === undefined) offset = 0 if (offset === undefined) offset = 0

View File

@ -4,8 +4,24 @@ const perms = require('./permissionController')
const randomstring = require('randomstring') const randomstring = require('randomstring')
const utils = require('./utilsController') const utils = require('./utilsController')
const TOKEN_LENGTH = 64
const UNIQUE_TOKEN_MAX_TRIES = 3
const tokenController = {} const tokenController = {}
tokenController.generateUniqueToken = () => {
return new Promise(resolve => {
const query = async i => {
const token = randomstring.generate(TOKEN_LENGTH)
const user = await db.table('users').where('token', token).first().catch(() => undefined)
if (user === undefined) return resolve(token)
if (++i < UNIQUE_TOKEN_MAX_TRIES) return query(i)
resolve(null)
}
query(0)
})
}
tokenController.verify = async (req, res, next) => { tokenController.verify = async (req, res, next) => {
const token = req.body.token const token = req.body.token
if (token === undefined) if (token === undefined)
@ -41,13 +57,15 @@ tokenController.change = async (req, res, next) => {
const user = await utils.authorize(req, res) const user = await utils.authorize(req, res)
if (!user) return if (!user) return
const newtoken = randomstring.generate(64) const newtoken = await tokenController.generateUniqueToken()
if (!newtoken)
return res.json({ success: false, description: 'Error generating unique token (╯°□°)╯︵ ┻━┻.' })
await db.table('users').where('token', user.token).update({ await db.table('users').where('token', user.token).update({
token: newtoken, token: newtoken,
timestamp: Math.floor(Date.now() / 1000) timestamp: Math.floor(Date.now() / 1000)
}) })
return res.json({
res.json({
success: true, success: true,
token: newtoken token: newtoken
}) })