const logger = require("../Logger");
const JsonResponse = require("./JsonResponse");
const crypto = require("crypto");
const config = require("../config");
const jwt = require("jsonwebtoken");
const ResetPasswordMail = require("../sms-mail/ResetPasswordMail");
const { v4: uuidv4 } = require("uuid");
const { Vonage } = require("@vonage/server-sdk");
const CrudController = require("./CrudController");
const ConnectedUser = require("../database/dto/ConnectedUser");
const vonage = new Vonage({
apiKey: "31e8eb0c",
apiSecret: "Lu0Ab5gRUxiNR0lJ",
});
const resetPasswordValidator = require("../Validators/ResetPasswordValidator");
/**
* @extends Myintranet.Controllers.CrudController
* @memberOf Myintranet.Controllers
* @inheritDoc
*/
class SecurityController extends CrudController {
attachUser(request, response, next) {
let db = request.db;
if (request.headers["authorization"] !== undefined) {
let token = request.headers["authorization"].split(" ")[1];
if (token.trim().length <= 10) {
// token found in the browser dosent much criteria
logger.error("Token found but incoherent");
response
.status(401)
.json(new JsonResponse(false, {}, "Token found but incoherent"));
} else {
jwt.verify(token, config.secret, function (err, decoded) {
if (err) {
logger.error(err.message);
response
.status(401)
.json(new JsonResponse(false, err, err.message));
} else {
db.User.findOne({
where: { id: decoded.id, login: decoded.email },
include: [db.Consultant],
})
.then((user) => {
if (user === null) {
// token found in the browser and the user dosen't exists in database
logger.error("User not found with id : " + decoded.id);
response
.status(401)
.json(
new JsonResponse(
false,
{},
"User not found with id : " + decoded.id
)
);
} else {
request.connectedUser = user;
request.user = user;
next();
}
})
.catch((error) => {
logger.error(error.message);
response
.status(401)
.json(new JsonResponse(false, error, error.message));
});
}
});
}
} else {
//TODO : LOG IP ADDR ans some security stuff to be able in the futur to ban an ip or a mac address .... or to know who is the caller to a secured root whithout token
logger.error("No authentication data");
response
.status(401)
.json(
new JsonResponse(
false,
["No authentication data"],
"No authentication data"
)
);
}
}
login(request, response) {
let db = request.db;
let { email, password } = request.body;
logger.info(`SecurityController.login Authentication of ${email} `);
db.User.findOne({ where: { login: email } })
.then((foundUser) => {
if (!foundUser) {
logger.error(
`SecurityController.login ${email} Not found in database`
);
response.json(
new JsonResponse(
false,
[],
`${email} N'existe pas dans la base de donnée`
)
);
} else {
// console.log(foundUser)
let hash = crypto.createHmac("sha512", foundUser.salt);
hash.update(password);
let hasedPassword = hash.digest("hex");
// console.log(hasedPassword, foundUser.password)
if (hasedPassword == foundUser.password) {
let U = foundUser.toJSON();
U.token = this.getAuthToken(U);
if(U.type==="Admin"){
foundUser.getEmployeurs().then(employeurs=>{
U.employeurs = employeurs;
response.json(new JsonResponse(true, new ConnectedUser(U), ""));
})
}else{
response.json(new JsonResponse(true, new ConnectedUser(U), ""));
}
} else {
logger.warn(
`${email} tries to connect with false password : ${password}`
);
response.json(new JsonResponse(false, [], "Password incorrect"));
}
}
})
.catch((err) => {
// throw err;
logger.error(err.message);
response.json(new JsonResponse(false, err, err.message));
});
}
getAuthToken(user) {
//TODO: add environnement url and check it in the security to make the token only valid for the environnement its created on
//todo need to check the email of the user
let { id, login } = user;
return jwt.sign({ id, email: login }, config.secret, {
expiresIn: 3600 * 24 * 365,
});
}
sendResetPasswordEmail(user, cb) {
let reesetmail = new ResetPasswordMail(
user,
"Reinitialisation du mot de passe de My-Intranet"
);
return reesetmail.send();
}
isPhone(data) {
// console.log("isPhone :" + new RegExp("^(?:(?:\\+|00)33|0)\\s*[1-9](?:\\d{2}){4}$").test(data),data)
return new RegExp("^(?:(?:\\+|00)33|0)\\s*[1-9](?:\\d{2}){4}$").test(data);
}
async SendResetPasswordSMS(user, db, cb) {
// console.log(user.phone);
// const from = "Vonage APIs";//'0619629393'
// const to = user.phone
let url = config.siteUrl + "/api/securedLink/" + user.link.token + "/reset";
const from = "MY-INTRANET";
const to = user.phone.replace(/^0/, "33").replace("+", "");
const text = `Bonjour ${user.firstname} ${user.lastname}
Réinitialisez votre mot de passe en cliquant sur le lien ci-dessous. Par mesure de sécurité, ce lien expirera dans une heure.
${url}
Si vous n'avez pas besoin de réinitialiser votre mot de passe, merci d'ignorer ce message.
`;
const t = await db.sequelize.transaction();
try {
let resp = await vonage.sms.send({ to, from, text });
await db.Action.create(
{
UtilisateurId: user.id,
meta: JSON.stringify(user),
type: "mise a jour",
text: `<b>${user.firstname} ${
user.lastname
}</b> a Fait une demande de reiinitialisation de mot de passe par SMS a : <b>${to}</b> le : ${new Date(
Date.now()
).toLocaleString("fr-FR")}`,
},
{ transaction: t }
);
await db.SMSHisto.create(
{
msisdn: from,
text,
to,
type: "from My intranet",
UtilisateurId: user.id,
orphan: false,
},
{ transaction: t }
);
if (resp.messages[0]["status"] === "0") {
await t.commit();
cb && cb();
} else {
logger.error(
`Message failed with error: ${resp.messages[0]["error-text"]}`
);
await t.rollback();
}
} catch (e) {
logger.error(`Message failed with error: ${e.message}`);
await t.rollback();
throw e;
}
}
sendResetPasswordMail(request, response) {
let db = request.db;
if (this.isPhone(request.body.email)) {
db.User.findOne({
where: {
phone: {
[db.Sequelize.Op.like]:
"%" + request.body.email.replace(/^33/, "").replace(/^0/, ""),
},
},
}).then((user) => {
if (!user) {
//user not found
// reponse positive pour eviter la verification
response.json(
new JsonResponse(false, { email: request.body.email }, "SMS Sent 0")
);
} else {
//user found in database
db.SecuredLink.create({
token: uuidv4(),
UtilisateurId: user.id,
reason: "reset password",
}).then((link) => {
user.link = link;
this.SendResetPasswordSMS(user, db, () => {
response.json(
new JsonResponse(
true,
{ email: request.body.email },
"Email Sent"
)
);
});
});
}
});
} else {
db.User.findOne({ where: { login: request.body.email } }).then((user) => {
if (!user) {
// let userReset = user.toJSON()
// reponse positive pour eviter la verification (un hacker peut utiliser cette methode pour demanser le reset de mot de passe)
// meme si l'utilisateur n'existe pas
response.json(new JsonResponse(true, [], "Email Sent"));
} else {
//user found in database
db.SecuredLink.create({ token: uuidv4(), UtilisateurId: user.id })
.then((link) => {
user.link = link;
this.sendResetPasswordEmail(user)
.then((info) => {
response.json(
new JsonResponse(
true,
{ email: request.body.email },
"Email Sent"
)
);
})
.catch((err) => {
logger.error("Error sending mail " + err.message);
response.json(new JsonResponse(false, err, err.message));
});
})
.catch((err) => {
logger.error(
"Unable to create secured Link for reset password " +
err.message
);
response.json(
new JsonResponse(
false,
err,
"Unable to create secured Link for reset password " +
err.message
)
);
});
}
});
}
}
// resetUserPassword(request, response) {
// let db = request.db;
// db.User.findOne({include: {model: db.SecuredLink, where: {token: request.params.id}}}).then(user => {
// if (!user) {
// response.json(new JsonResponse(false, {}, "User not found "));
// } else {
// let hach = this.getPasswordAndSalt(request.body.password);
// user.password = hach.password;
// user.salt = hach.salt;
// user.save().then(u => {
// user.securedLinks[0].destroy().then(res => {
// response.json(new JsonResponse(true, user, "User found with id : " + user.id));
// }).catch(err => {
// logger.error("Error Wile resetting password " + err.message);
// response.json(new JsonResponse(false, err, err.message));
// });
// }).catch(err => {
// logger.error("Error Wile Saving the new password " + err.message);
// response.json(new JsonResponse(false, err, err.message));
// });
// }
// });
// }
// resetUserPassword(request, response) {
// let db = request.db;
// db.User.findOne({include: {model: db.SecuredLink, where: {token: request.params.id}}}).then(user => {
// if (!user) {
// response.json(new JsonResponse(false, {}, "User not found "));
// } else {
// let hach = this.getPasswordAndSalt(request.body.password);
// user.password = hach.password;
// user.salt = hach.salt;
// user.save().then(u => {
// user.securedLinks[0].destroy().then(res => {
// response.json(new JsonResponse(true, user, "User found with id : " + user.id));
// }).catch(err => {
// logger.error("Error Wile resetting password " + err.message);
// response.json(new JsonResponse(false, err, err.message));
// });
// }).catch(err => {
// logger.error("Error Wile Saving the new password " + err.message);
// response.json(new JsonResponse(false, err, err.message));
// });
// }
// });
// }
resetUserPassword(request, response) {
let db = request.db;
let { newPass, confirmPass } = request.body;
let validationResult = resetPasswordValidator.validate(request.body);
if (validationResult.length > 0) {
response.json(
new JsonResponse(
false,
validationResult,
"Validation error: " + validationResult[0].message
)
);
} else {
if (newPass === confirmPass) {
db.User.findOne({
include: {
model: db.SecuredLink,
where: { token: request.params.id },
},
}).then((user) => {
if (!user) {
response.json(new JsonResponse(false, {}, "User not found "));
} else {
let hach = this.getPasswordAndSalt(request.body.password);
user.password = hach.password;
user.salt = hach.salt;
user
.save()
.then((u) => {
user.securedLinks[0]
.destroy()
.then((res) => {
response.json(
new JsonResponse(
true,
user,
"User found with id: " + user.id
)
);
})
.catch((err) => {
logger.error(
"Error while resetting password: " + err.message
);
response.json(new JsonResponse(false, err, err.message));
});
})
.catch((err) => {
logger.error(
"Error while saving the new password: " + err.message
);
response.json(new JsonResponse(false, err, err.message));
});
}
});
} else {
logger.error("Le mot de passe et sa confirmation ne sont pas identiques");
response.json(
new JsonResponse(
false,
"",
"Le mot de passe et sa confirmation ne sont pas identiques"
)
);
}
}
}
}
module.exports = new SecurityController();