refs #6434 feat: improve signIn method
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Javier Segarra 2023-11-28 13:22:17 +01:00
parent 37555cbb63
commit 63533459b0
5 changed files with 66 additions and 26 deletions

View File

@ -49,13 +49,7 @@ module.exports = Self => {
if (vnUser.twoFactor)
throw new ForbiddenError(null, 'REQUIRES_2FA');
}
const validateLogin = await Self.validateLogin(user, password);
await Self.app.models.SignInLog.create({
token: validateLogin.token,
userFk: vnUser.id,
ip: ctx.req.ip
});
return validateLogin;
return Self.validateLogin(user, password, ctx);
};
Self.passExpired = async vnUser => {

View File

@ -2,7 +2,7 @@ const {models} = require('vn-loopback/server/server');
describe('VnUser Sign-in()', () => {
const employeeId = 1;
const unauthCtx = {
const unAuthCtx = {
req: {
headers: {},
connection: {
@ -15,20 +15,21 @@ describe('VnUser Sign-in()', () => {
const {VnUser, AccessToken, SignInLog} = models;
describe('when credentials are correct', () => {
it('should return the token if user uses email', async() => {
let login = await VnUser.signIn(unauthCtx, 'salesAssistant@mydomain.com', 'nightmare');
let login = await VnUser.signIn(unAuthCtx, 'salesAssistant@mydomain.com', 'nightmare');
let accessToken = await AccessToken.findById(login.token);
let ctx = {req: {accessToken: accessToken}};
let signInLog = await SignInLog.find({where: {token: accessToken.id}});
expect(signInLog.length).toEqual(1);
expect(signInLog[0].userFk).toEqual(accessToken.userId);
expect(signInLog[0].owner).toEqual(true);
expect(login.token).toBeDefined();
await VnUser.logout(ctx.req.accessToken.id);
});
it('should return the token', async() => {
let login = await VnUser.signIn(unauthCtx, 'salesAssistant', 'nightmare');
let login = await VnUser.signIn(unAuthCtx, 'salesAssistant', 'nightmare');
let accessToken = await AccessToken.findById(login.token);
let ctx = {req: {accessToken: accessToken}};
@ -38,7 +39,7 @@ describe('VnUser Sign-in()', () => {
});
it('should return the token if the user doesnt exist but the client does', async() => {
let login = await VnUser.signIn(unauthCtx, 'PetterParker', 'nightmare');
let login = await VnUser.signIn(unAuthCtx, 'PetterParker', 'nightmare');
let accessToken = await AccessToken.findById(login.token);
let ctx = {req: {accessToken: accessToken}};
@ -53,7 +54,7 @@ describe('VnUser Sign-in()', () => {
let error;
try {
await VnUser.signIn(unauthCtx, 'IDontExist', 'TotallyWrongPassword');
await VnUser.signIn(unAuthCtx, 'IDontExist', 'TotallyWrongPassword');
} catch (e) {
error = e;
}
@ -74,7 +75,7 @@ describe('VnUser Sign-in()', () => {
const options = {transaction: tx};
await employee.updateAttribute('twoFactor', 'email', options);
await VnUser.signIn(unauthCtx, 'employee', 'nightmare', options);
await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options);
await tx.rollback();
} catch (e) {
await tx.rollback();
@ -99,7 +100,7 @@ describe('VnUser Sign-in()', () => {
const options = {transaction: tx};
await employee.updateAttribute('passExpired', yesterday, options);
await VnUser.signIn(unauthCtx, 'employee', 'nightmare', options);
await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options);
await tx.rollback();
} catch (e) {
await tx.rollback();

View File

@ -124,20 +124,43 @@ module.exports = function(Self) {
return email.send();
});
Self.signInValidate = (user, userToken) => {
/**
* Sign-in validate. *
* @param {Integer} user The user
* @param {Object} userToken Options
* @param {Object} token accessToken
* @param {Object} ctx context
*/
Self.signInValidate = async(user, userToken, token, ctx) => {
const [[key, value]] = Object.entries(Self.userUses(user));
if (userToken[key].toLowerCase().trim() !== value.toLowerCase().trim()) {
console.error('ERROR!!! - Signin with other user', userToken, user);
const isOwner = Self.rawSql(`SELECT ? = ? `, [userToken[key], value]);
await Self.app.models.SignInLog.create({
token: token.id,
userFk: userToken.id,
ip: ctx.req.ip,
owner: isOwner
});
if (!isOwner) {
console.error('ERROR!!! - SignIn with other user', userToken, user);
throw new UserError('Try again');
}
};
Self.validateLogin = async function(user, password) {
/**
* Validate login params*
* @param {String} user The user
* @param {String} password
* @param {Object} ctx context
*/
Self.validateLogin = async function(user, password, ctx) {
const loginInfo = Object.assign({password}, Self.userUses(user));
const token = await Self.login(loginInfo, 'user');
const userToken = await token.user.get();
Self.signInValidate(user, userToken);
if (ctx)
await Self.signInValidate(user, userToken, token, ctx);
try {
await Self.app.models.Account.sync(userToken.name, password);
@ -226,10 +249,12 @@ module.exports = function(Self) {
const env = process.env.NODE_ENV;
const liliumUrl = await Self.app.models.Url.findOne({
where: {and: [
where: {
and: [
{appName: 'lilium'},
{environment: env}
]}
]
}
});
class Mailer {

View File

@ -0,0 +1,15 @@
DROP TABLE IF EXISTS `account`.`signInLog`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `account`.`signInLog` (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`token` varchar(255) NOT NULL ,
`userFk` int(10) unsigned DEFAULT NULL,
`creationDate` timestamp NULL DEFAULT current_timestamp(),
`ip` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`owner` tinyint(1) DEFAULT 1,
KEY `userFk` (`userFk`),
CONSTRAINT `signInLog_ibfk_1` FOREIGN KEY (`userFk`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -26,6 +26,11 @@
},
"ip": {
"type": "string"
},
"owner": {
"type": "boolean",
"required": true,
"default": true
}
},
"relations": {