SolidScribe/server/models/User.js
2020-03-13 23:34:32 +00:00

170 lines
4.7 KiB
JavaScript

var crypto = require('crypto')
let db = require('@config/database')
let Auth = require('@helpers/Auth')
let User = module.exports = {}
//Login a user, if that user does not exist create them
//Issues login token
User.login = (username, password) => {
return new Promise((resolve, reject) => {
const lowerName = username.toLowerCase();
db.promise()
.query('SELECT * FROM user WHERE username = ? LIMIT 1', [lowerName])
.then((rows, fields) => {
//Pull out user data from database results
const lookedUpUser = rows[0][0];
//User not found, create a new account with set data
if(rows[0].length == 0){
User.create(lowerName, password)
.then(loginToken => {
resolve(loginToken)
})
return
}
//hash the password and check for a match
const salt = new Buffer(lookedUpUser.salt, 'binary')
crypto.pbkdf2(password, salt, lookedUpUser.iterations, 512, 'sha512', function(err, delivered_key){
if(delivered_key.toString('hex') === lookedUpUser.password){
//Passback a json web token
const token = Auth.createToken(lookedUpUser.id)
resolve(token)
} else {
reject('Password does not match database')
}
})
})
.catch(console.log)
})
}
//Create user account
//Issues login token
User.create = (username, password) => {
//For some reason, username won't get into the promise. But password will @TODO figure this out
const lowerName = username.toLowerCase().trim()
return new Promise((resolve, reject) => {
db.promise()
.query('SELECT * FROM user WHERE username = ? LIMIT 1', [lowerName])
.then((rows, fields) => {
if(rows[0].length === 0){ //No users returned, create new one. Start with hashing password
//Params for hash function
let shasum = crypto.createHash('sha512') //Prepare Hash
const ran = parseInt(Date.now()) //Get current time in miliseconds
const semiRandomInt = Math.floor(Math.random()*11) //Grab a random number
const otherRandomInt = (ran*semiRandomInt+ran)*semiRandomInt-ran //Mix things up a bit
shasum.update(''+otherRandomInt) //Update Hasd
const saltString = shasum.digest('hex')
const salt = new Buffer(saltString, 'binary') //Generate Salt hash
const iterations = 25000
crypto.pbkdf2(password, salt, iterations, 512, 'sha512', function(err, delivered_key) {
//Create new user object with freshly salted password
var currentDate = new Date().toISOString().slice(0, 19).replace('T', ' ');
var new_user = {
username: lowerName,
password: delivered_key.toString('hex'),
salt: salt,
iterations: iterations,
last_login: currentDate,
created: currentDate
};
db.promise()
.query('INSERT INTO user SET ?', new_user)
.then((rows, fields) => {
if(rows[0].affectedRows == 1){
const newUserId = rows[0].insertId
const loginToken = Auth.createToken(newUserId)
resolve(loginToken)
} else {
//Emit Error to user
reject('New user could not be created')
}
})
.catch(console.log)
})
} else {
reject('Username already in use.')
}//END user create
})
.catch(console.log)
})
}
//Counts notes, pinned notes, archived notes, shared notes, unread notes, total files and types
User.getCounts = (userId) => {
return new Promise((resolve, reject) => {
let countTotals = {}
db.promise().query(
`SELECT
SUM(pinned = 1 && archived = 0 && share_user_id IS NULL) AS pinnedNotes,
SUM(archived = 1 && share_user_id IS NULL) AS archivedNotes,
SUM(encrypted = 1) AS encryptedNotes,
SUM(share_user_id IS NULL) AS totalNotes,
SUM(share_user_id != ?) AS sharedToNotes,
SUM( (share_user_id != ? && opened IS null) || (share_user_id != ? && note_raw_text.updated > opened) ) AS unreadNotes
FROM note
LEFT JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
WHERE user_id = ?`, [userId, userId, userId, userId])
.then( (rows, fields) => {
Object.assign(countTotals, rows[0][0]) //combine results
return db.promise().query(
`SELECT count(id) AS sharedFromNotes
FROM note WHERE share_user_id = ?`, [userId]
)
})
.then( (rows, fields) => {
Object.assign(countTotals, rows[0][0]) //combine results
return db.promise().query(
`SELECT
SUM(attachment_type = 1) as linkFiles,
SUM(attachment_type != 1) as otherFiles,
COUNT(id) as totalFiles
FROM attachment WHERE visible = 1
AND user_id = ?
`, [userId]
)
}).then( (rows, fields) => {
Object.assign(countTotals, rows[0][0]) //combine results
//Convert everything to an int or 0
Object.keys(countTotals).forEach( key => {
const count = parseInt(countTotals[key])
countTotals[key] = count ? count : 0
})
resolve(countTotals)
})
})
}