mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-14 00:16:21 +00:00
b35f4ae6eb
this required expanding our custom error classes with support for arbitrary internal api error codes however it'll only be used for invalid token errors for now (10001) no plan to assign codes to other existing api errors at that point it's probably better to redo the whole api infrastructure
105 lines
2.5 KiB
JavaScript
105 lines
2.5 KiB
JavaScript
const randomstring = require('randomstring')
|
|
const perms = require('./permissionController')
|
|
const utils = require('./utilsController')
|
|
const apiErrorsHandler = require('./handlers/apiErrorsHandler')
|
|
const ClientError = require('./utils/ClientError')
|
|
const ServerError = require('./utils/ServerError')
|
|
const config = require('./../config')
|
|
const db = require('knex')(config.database)
|
|
|
|
const self = {
|
|
tokenLength: 64,
|
|
tokenMaxTries: 3,
|
|
onHold: new Set()
|
|
}
|
|
|
|
self.generateUniqueToken = async () => {
|
|
for (let i = 0; i < self.tokenMaxTries; i++) {
|
|
const token = randomstring.generate(self.tokenLength)
|
|
if (self.onHold.has(token)) continue
|
|
|
|
// Put token on-hold (wait for it to be inserted to DB)
|
|
self.onHold.add(token)
|
|
|
|
const user = await db.table('users')
|
|
.where('token', token)
|
|
.select('id')
|
|
.first()
|
|
if (user) {
|
|
self.onHold.delete(token)
|
|
continue
|
|
}
|
|
|
|
return token
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
self.verify = async (req, res, next) => {
|
|
try {
|
|
const token = typeof req.body.token === 'string'
|
|
? req.body.token.trim()
|
|
: ''
|
|
|
|
if (!token) throw new ClientError('No token provided.', { statusCode: 403 })
|
|
|
|
const user = await db.table('users')
|
|
.where('token', token)
|
|
.select('username', 'permission')
|
|
.first()
|
|
|
|
if (!user) {
|
|
throw new ClientError('Invalid token.', { statusCode: 403, code: 10001 })
|
|
}
|
|
|
|
const obj = {
|
|
success: true,
|
|
username: user.username,
|
|
permissions: perms.mapPermissions(user)
|
|
}
|
|
|
|
if (utils.clientVersion) {
|
|
obj.version = utils.clientVersion
|
|
}
|
|
|
|
await res.json(obj)
|
|
} catch (error) {
|
|
return apiErrorsHandler(error, req, res, next)
|
|
}
|
|
}
|
|
|
|
self.list = async (req, res, next) => {
|
|
try {
|
|
const user = await utils.authorize(req)
|
|
await res.json({ success: true, token: user.token })
|
|
} catch (error) {
|
|
return apiErrorsHandler(error, req, res, next)
|
|
}
|
|
}
|
|
|
|
self.change = async (req, res, next) => {
|
|
try {
|
|
const user = await utils.authorize(req, 'token')
|
|
|
|
const newToken = await self.generateUniqueToken()
|
|
if (!newToken) {
|
|
throw new ServerError('Failed to allocate a unique token. Try again?')
|
|
}
|
|
|
|
await db.table('users')
|
|
.where('token', user.token)
|
|
.update({
|
|
token: newToken,
|
|
timestamp: Math.floor(Date.now() / 1000)
|
|
})
|
|
self.onHold.delete(newToken)
|
|
|
|
await res.json({ success: true, token: newToken })
|
|
} catch (error) {
|
|
return apiErrorsHandler(error, req, res, next)
|
|
}
|
|
}
|
|
|
|
module.exports = self
|