const express = require('express'); const path = require('path'); const bcrypt = require('bcrypt'); const util = require('util'); const Actions = require('./ActionSystem'); const RepositorySystem = require('./RepositorySystem'); const RoutingSystem = require('./RoutingSystem'); const Mail = require('./MailSystem'); const Logger = require('./LoggerSystem'); const Config = require('./config'); let UserConfig = { fields: [ { key: "email", type: "text" }, { key: "username", type: "text" }, { key:"password", type: "text" }, { key:"token", type: "text" }, { key:"role", type: "integer" }, { key: "enable", type: "integer", defaultsTo: 0 } ] } class UserSystem { constructor(){ this.repository = RepositorySystem.create('Users', UserConfig); this.Middleware = this._middleware.bind(this); let mainroutes = [ { type: 'custom', method: 'post', endpoint: '/login', customFn: (req, res) => this.login(req.body.username, req.body.password) .then((a) => res.send(a)) .catch((e) => { if(e.message === "403") res.status(403).send(); else res.sendStatus(400); }) }, { type: 'custom', method: 'get', endpoint: '/logout', customFn: (req, res) => this.logout(req) .then((a) => res.sendStatus(200)) .catch((e) => res.sendStatus(400)) }, { type: 'custom', method: 'post', endpoint: '/register', customFn: (req, res) => this.register(req.body.email,req.body.username, req.body.password) .then((a) => res.send(a)) .catch((e) => { console.log(e.message); if(e.message === "Converting circular structure to JSON"){ return res.sendStatus(200); } return res.sendStatus(400); }) }, { type: 'custom', method: 'get', endpoint: '/verifyemail', customFn: (req, res) => this.verifyemail(req.query.id) .then((a) => res.sendStatus(200)) .catch((e) => { console.log(e.message); if(e.message === "Converting circular structure to JSON"){ return res.sendStatus(200); } return res.sendStatus(400); }) }, { type: 'custom', method: 'post', endpoint: '/changepass', customFn: (req, res) => this.changepass(req.user, req.body.cpass,req.body.npass) .then((a) => res.status(200).send()) .catch((e) => { console.log(e.message); if(e.message === "Converting circular structure to JSON"){ return res.sendStatus(200); } return res.sendStatus(400); }) }, { type: 'custom', method: 'get', endpoint: '/me', customFn: (req, res) => { Actions.emit('getUsers', req.user) .then((user) => res.send(user)) } } ]; RoutingSystem.loadRoutes(mainroutes, this.router, '/users'); } logout(req) { let userID = req.user.id; if(userID) { return this.repository.update(userID, { token: '' }).catch((e) => console.log(e, userID)); } else { return Promise.resolve('Logged out!'); } } verifyemail(id) { return this.repository.raw().where('password', 'like', '____' + id + '%') .then((data) => { if(!data.length) { throw new Error("No such user with verification id : " + id); } console.log(data); let user = data[0]; return this.repository.update(user.id, {enable: true}); }); } register(email, username,password, role = 1){ let data = { email, username, role }; return this.repository.get('username',username) .then((data) => { if(data.length > 0) { throw Error('Already registered'); } return true; }) .then(() => { let hash = bcrypt.hash(password, 10); return hash; }) .then((hash) => { data.password = hash; return Actions.emit('postUsers', data); }) .then((data) => { return this.repository.insert(data).then(() => data); }) .then((data) => { let { email, username, password } = data; let token = password.slice(4,20); Mail.send( email, Config.MAIL_WELCOME_SUBJECT.replace("{username}",username), Config.MAIL_WELCOME_TXT.replace("{token}", token), Config.MAIL_WELCOME_HTML.replace("{token}", token) ) }); } login(username,password){ let id = -1; return this.repository.get('username', username) .then((data) => { if(data.length == 0){ throw Error('no such user'); } return data[0]; }) .then((user) =>{ if(user.enable !== 1) { throw Error("403"); } id = user.id; return bcrypt.compare(password,user.password) }) .then((isPassCorrect) => { if(!isPassCorrect) throw Error('Wrong password'); return bcrypt.genSaltSync(10); }) .then((token) => this.repository.update(id, {token}).then(() => token)) .then((token) => this.getByToken(token)) .then((user) => Actions.emit("getUsers", user)); } changepass(user, cpass, npass) { if(!user) { return Promise.reject('No user'); } console.log(user, cpass, npass) return this.repository.get('id', user.id) .then((data) => { let user = data[0]; if(!user) throw new Error("No user with id " + user.id); let p = user.password; return bcrypt.compare(cpass,p); }) .then((isPassCorrect) => { if(!isPassCorrect) throw Error('Wrong password'); return bcrypt.hash(npass, 10); }) .then((hash) => { console.log("HASH : " , hash); return this.repository.update(user.id, {password: hash}) }); } getByToken(token){ let user = null; return this.repository.get('token', token).then((data) => data[0]); } role(req, res, role) { // Need middleware on load if(req.user.role === undefined || req.user.role < role){ //res.sendStatus(401); let e = new Error("401"); e.status = 401; console.log(req.user) throw e; } } _middleware(req, res, next) { const token = req.headers.token; if(!token || token.length < 5){ req.user = { ip : req.connection.remoteAddress, role: 0 }; return next(); } else { this.repository.get('token',token) .then((data)=> { req.user = data[0] || {role: 0}; req.user.ip = req.connection.remoteAddress; next(); }).catch((error)=> { console.log("Cannot parseToken"); Logger.error(error); res.status(401).send({message:"Cannot parse token. Access denied!"}); }); } } } module.exports = new UserSystem()