SolidScribe/server/helpers/Auth.js

152 lines
4.4 KiB
JavaScript
Raw Normal View History

const db = require('@config/database')
const jwt = require('jsonwebtoken')
const cs = require('@helpers/CryptoString')
let Auth = {}
const tokenSecretKey = process.env.JSON_KEY
Auth.createToken = (userId, masterKey, pastId = null, pastCreatedDate = null) => {
return new Promise((resolve, reject) => {
const created = pastCreatedDate ? pastCreatedDate : Math.floor(+new Date/1000)
const userHash = cs.hash(String(userId)).toString('base64')
//Encrypt Master Password and save it to the server
const sessionId = pastId ? pastId : cs.createSmallSalt().slice(0,9) //Use existing session id
const salt = cs.createSmallSalt()
const tempPass = cs.createSmallSalt()
const encryptedMasterPass = cs.encrypt(tempPass, salt, masterKey)
//Deactivate all other session keys, they delete after 30 seconds
db.promise().query('UPDATE user_active_session SET active = 0 WHERE session_id = ?', [sessionId])
.then((r,f) => {
return db.promise().query(
'INSERT INTO user_active_session (salt, encrypted_master_password, created, uses, user_hash, session_id) VALUES (?,?,?,?,?,?)',
[salt, encryptedMasterPass, created, 40, userHash, sessionId])
})
.then((r,f) => {
const sessionNum = r[0].insertId
//Required Data for JWT payload
const tokenPayload = {userId, tempPass, sessionNum}
//Return token
const token = jwt.sign(tokenPayload, tokenSecretKey)
return resolve(token)
})
})
}
Auth.decodeToken = (token, request = null) => {
return new Promise((resolve, reject) => {
let decodedToken = null
//Delete all tokens older than 20 days before continuing or inacive and older than 1 minute
const now = (Math.floor((+new Date)/1000))
const twentyDays = (Math.floor((+new Date)/1000)) - (86400 * 20)
const thirtySeconds = (Math.floor((+new Date)/1000)) - (30)
//Decode Json web token
jwt.verify(token, tokenSecretKey, function(err, decoded){
if(err || decoded.tempPass == undefined || decoded.tempPass.length < 5){
throw new Error('Bad Token')
}
decodedToken = decoded
db.promise().query('DELETE from user_active_session WHERE (created < ?) OR (active = false AND last_used < ?)', [twentyDays, thirtySeconds])
.then((r,f) => {
//Lookup session data in database
db.promise().query('SELECT * FROM user_active_session WHERE id = ? LIMIT 1', [decodedToken.sessionNum])
.then((r,f) => {
if(r == undefined || r[0].length == 0){
throw new Error('Active Session not found for token')
}
const row = r[0][0]
// console.log(decodedToken.sessionNum + ' uses -> ' + row.uses)
if(row.uses <= 0){
throw new Error('Token is used up')
}
//Decrypt master key from lookup
const masterKey = cs.decrypt(decodedToken.tempPass, row.salt, row.encrypted_master_password)
if(masterKey == null){
// console.log('Deleting invalid session')
Auth.terminateSession(row.session_id)
throw new Error ('Unable to decrypt password for session')
}
//Async update DB counts and disable session if needed
db.promise().query('UPDATE user_active_session SET uses = uses -1, last_used = ? WHERE id = ? LIMIT 1', [now, decodedToken.sessionNum])
.then((r,f) => {
let userData = {
'userId': decodedToken.userId,
'masterKey': masterKey,
'sessionId': row.session_id,
'created': row.created,
'remainingUses':(row.uses--),
'active': row.active
}
//Return token Data
return resolve(userData)
})
})
.catch(error => {
//Token errors result in having sessions deleted
// console.log('-- Auth Token Error --')
// console.log(error)
reject(error)
})
})
})
})
}
Auth.terminateSession = (sessionId) => {
return db.promise().query('DELETE from user_active_session WHERE session_id = ?', [sessionId])
}
Auth.deletAllLoginKeys = (userId) => {
const userHash = cs.hash(String(userId)).toString('base64')
return db.promise().query('DELETE FROM user_active_session WHERE user_hash = ?', [userHash])
}
Auth.test = () => {
const testUserId = 22
const testPass = cs.createSmallSalt()
Auth.createToken(testUserId, testPass)
.then(token => {
console.log('Test: Create JWT -> Pass')
return Auth.decodeToken(token)
})
.then(userData => {
console.log('Test: Decrypted key Match -> ' + (testPass == userData.masterKey))
return Auth.deletAllLoginKeys(testUserId)
})
.then(results => {
console.log('Test: Remove user Json Web Tokens - Pass')
})
}
module.exports = Auth