8032-devToTest_2440 #3009
|
@ -33,7 +33,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const where = Self.userUses(user);
|
const where = Self.userUses(user);
|
||||||
const vnUser = await Self.findOne({
|
const vnUser = await Self.findOne({
|
||||||
fields: ['id', 'name', 'password', 'active', 'email', 'passExpired', 'twoFactor'],
|
fields: ['id', 'name', 'password', 'active', 'email', 'passExpired', 'twoFactorFk'],
|
||||||
where
|
where
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ module.exports = Self => {
|
||||||
await Self.sendTwoFactor(ctx, vnUser, myOptions);
|
await Self.sendTwoFactor(ctx, vnUser, myOptions);
|
||||||
await Self.passExpired(vnUser, myOptions);
|
await Self.passExpired(vnUser, myOptions);
|
||||||
|
|
||||||
if (vnUser.twoFactor)
|
if (vnUser.twoFactorFk)
|
||||||
throw new ForbiddenError(null, 'REQUIRES_2FA');
|
throw new ForbiddenError(null, 'REQUIRES_2FA');
|
||||||
}
|
}
|
||||||
return Self.validateLogin(user, password, ctx);
|
return Self.validateLogin(user, password, ctx);
|
||||||
|
@ -58,13 +58,13 @@ module.exports = Self => {
|
||||||
|
|
||||||
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) {
|
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) {
|
||||||
const err = new UserError('Pass expired', 'passExpired');
|
const err = new UserError('Pass expired', 'passExpired');
|
||||||
err.details = {userId: vnUser.id, twoFactor: vnUser.twoFactor ? true : false};
|
err.details = {userId: vnUser.id, twoFactorFk: vnUser.twoFactorFk ? true : false};
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self.sendTwoFactor = async(ctx, vnUser, myOptions) => {
|
Self.sendTwoFactor = async(ctx, vnUser, myOptions) => {
|
||||||
if (vnUser.twoFactor === 'email') {
|
if (vnUser.twoFactorFk === 'email') {
|
||||||
const $ = Self.app.models;
|
const $ = Self.app.models;
|
||||||
|
|
||||||
const min = 100000;
|
const min = 100000;
|
||||||
|
|
|
@ -70,7 +70,7 @@ describe('VnUser Sign-in()', () => {
|
||||||
let error;
|
let error;
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
await employee.updateAttribute('twoFactor', 'email', options);
|
await employee.updateAttribute('twoFactorFk', 'email', options);
|
||||||
|
|
||||||
await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options);
|
await VnUser.signIn(unAuthCtx, 'employee', 'nightmare', options);
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -25,8 +25,8 @@ module.exports = Self => {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'The user lang'
|
description: 'The user lang'
|
||||||
}, {
|
}, {
|
||||||
arg: 'twoFactor',
|
arg: 'twoFactorFk',
|
||||||
type: 'string',
|
type: 'any',
|
||||||
description: 'The user twoFactor'
|
description: 'The user twoFactor'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -36,8 +36,8 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.updateUser = async(ctx, id, name, nickname, email, lang, twoFactor) => {
|
Self.updateUser = async(ctx, id, name, nickname, email, lang, twoFactorFk) => {
|
||||||
await Self.userSecurity(ctx, id);
|
await Self.userSecurity(ctx, id);
|
||||||
await Self.upsertWithWhere({id}, {name, nickname, email, lang, twoFactor});
|
await Self.upsertWithWhere({id}, {name, nickname, email, lang, twoFactorFk});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,7 +55,7 @@ module.exports = Self => {
|
||||||
throw new UserError('Invalid or expired verification code');
|
throw new UserError('Invalid or expired verification code');
|
||||||
|
|
||||||
const user = await Self.findById(authCode.userFk, {
|
const user = await Self.findById(authCode.userFk, {
|
||||||
fields: ['name', 'twoFactor']
|
fields: ['name', 'twoFactorFk']
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
if (user.name.toLowerCase() !== username.toLowerCase())
|
if (user.name.toLowerCase() !== username.toLowerCase())
|
||||||
|
|
|
@ -58,9 +58,6 @@
|
||||||
},
|
},
|
||||||
"passExpired": {
|
"passExpired": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
},
|
|
||||||
"twoFactor": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
@ -89,6 +86,11 @@
|
||||||
"type": "hasOne",
|
"type": "hasOne",
|
||||||
"model": "UserConfig",
|
"model": "UserConfig",
|
||||||
"foreignKey": "userFk"
|
"foreignKey": "userFk"
|
||||||
|
},
|
||||||
|
"twoFactor": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "TwoFactorType",
|
||||||
|
"foreignKey": "twoFactorFk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
|
@ -165,7 +167,8 @@
|
||||||
"hasGrant",
|
"hasGrant",
|
||||||
"realm",
|
"realm",
|
||||||
"email",
|
"email",
|
||||||
"emailVerified"
|
"emailVerified",
|
||||||
|
"twoFactorFk"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
},
|
},
|
||||||
"vn": {
|
"vn": {
|
||||||
"view": {
|
"view": {
|
||||||
"expeditionPallet_Print": "ced2b84a114fcb99fce05f0c34f4fc03f3fa387bef92621be1bc306608a84345"
|
"expeditionPallet_Print": "99f75145ac2e7b612a6d71e74b6e55f194a465780fd9875a15eb01e6596b447e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ BEGIN
|
||||||
UPDATE vn.department_recalc SET isChanged = TRUE;
|
UPDATE vn.department_recalc SET isChanged = TRUE;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF !(OLD.twoFactor <=> NEW.twoFactor) THEN
|
IF !(OLD.twoFactorFk <=> NEW.twoFactorFk) THEN
|
||||||
UPDATE account.user u
|
UPDATE account.user u
|
||||||
JOIN vn.workerDepartment wd ON wd.workerFk = u.id
|
JOIN vn.workerDepartment wd ON wd.workerFk = u.id
|
||||||
SET u.twoFactor = NEW.twoFactor
|
SET u.twoFactorFk = NEW.twoFactorFk
|
||||||
WHERE wd.departmentFk = NEW.id;
|
WHERE wd.departmentFk = NEW.id;
|
||||||
END IF;
|
END IF;
|
||||||
END$$
|
END$$
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
CREATE OR REPLACE TABLE account.twoFactorType (
|
||||||
|
`code` varchar(20) NOT NULL,
|
||||||
|
`description` varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`code`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
||||||
|
ALTER TABLE account.user ADD twoFactorFk varchar(20) NULL;
|
||||||
|
ALTER TABLE account.user ADD CONSTRAINT user_twoFactor_fk FOREIGN KEY (twoFactorFk) REFERENCES account.twoFactorType(code) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE vn.department ADD twoFactorFk varchar(20) NULL;
|
||||||
|
ALTER TABLE vn.department ADD CONSTRAINT department_twoFactor_fk FOREIGN KEY (twoFactorFk) REFERENCES account.twoFactorType(code) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
INSERT INTO account.twoFactorType (code, description)
|
||||||
|
VALUES('email', 'Envia un código por email');
|
||||||
|
|
||||||
|
UPDATE account.`user` u
|
||||||
|
JOIN account.`user` u2 ON u.id = u2.id
|
||||||
|
SET u.twoFactorFk = u.twoFactor
|
||||||
|
WHERE u2.twoFactor IS NOT NULL;
|
||||||
|
|
||||||
|
UPDATE vn.`department` d
|
||||||
|
JOIN vn.`department` d2 ON d.id = d2.id
|
||||||
|
SET d.twoFactorFk = d.twoFactor
|
||||||
|
WHERE d2.twoFactor IS NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE account.user CHANGE twoFactor twoFactor__ enum('email') CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL COMMENT 'Deprecated 2024-09-09';
|
||||||
|
ALTER TABLE vn.department CHANGE twoFactor twoFactor__ enum('email') CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL COMMENT 'Deprecated 2024-09-09';
|
|
@ -22,7 +22,7 @@
|
||||||
autocomplete="false">
|
autocomplete="false">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
ng-if="$ctrl.$state.params.twoFactor == 'true'"
|
ng-if="$ctrl.$state.params.twoFactorFk == 'true'"
|
||||||
label="Verification code"
|
label="Verification code"
|
||||||
ng-model="$ctrl.code"
|
ng-model="$ctrl.code"
|
||||||
vn-name="code"
|
vn-name="code"
|
||||||
|
|
|
@ -37,13 +37,13 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const {VnUser} = Self.app.models;
|
const {VnUser} = Self.app.models;
|
||||||
const user = await VnUser.findById(userId, {fields: ['name', 'twoFactor']}, myOptions);
|
const user = await VnUser.findById(userId, {fields: ['name', 'twoFactorFk']}, myOptions);
|
||||||
await user.hasPassword(oldPassword);
|
await user.hasPassword(oldPassword);
|
||||||
|
|
||||||
if (oldPassword == newPassword)
|
if (oldPassword == newPassword)
|
||||||
throw new UserError(`You can not use the same password`);
|
throw new UserError(`You can not use the same password`);
|
||||||
|
|
||||||
if (user.twoFactor)
|
if (user.twoFactorFk)
|
||||||
await VnUser.validateCode(user.name, code, myOptions);
|
await VnUser.validateCode(user.name, code, myOptions);
|
||||||
|
|
||||||
await VnUser.changePassword(userId, oldPassword, newPassword, myOptions);
|
await VnUser.changePassword(userId, oldPassword, newPassword, myOptions);
|
||||||
|
|
|
@ -75,7 +75,7 @@ describe('account changePassword()', () => {
|
||||||
await models.VnUser.updateAll(
|
await models.VnUser.updateAll(
|
||||||
{id: 70},
|
{id: 70},
|
||||||
{
|
{
|
||||||
twoFactor: 'email',
|
twoFactorFk: 'email',
|
||||||
passExpired: yesterday
|
passExpired: yesterday
|
||||||
}
|
}
|
||||||
, options);
|
, options);
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
|
"Account": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"AccountConfig": {
|
"AccountConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -47,7 +50,7 @@
|
||||||
"SipConfig": {
|
"SipConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"Account": {
|
"TwoFactorType": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"UserLog": {
|
"UserLog": {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "TwoFactorType",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "account.twoFactorType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "string",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ fixtures:
|
||||||
- userPassword
|
- userPassword
|
||||||
- accountConfig
|
- accountConfig
|
||||||
- mailConfig
|
- mailConfig
|
||||||
|
- twoFactorType
|
||||||
salix:
|
salix:
|
||||||
- ACL
|
- ACL
|
||||||
- fieldAcl
|
- fieldAcl
|
||||||
|
@ -393,4 +394,4 @@ localFixtures:
|
||||||
- zoneExclusionGeo
|
- zoneExclusionGeo
|
||||||
- zoneGeo
|
- zoneGeo
|
||||||
- zoneIncluded
|
- zoneIncluded
|
||||||
- zoneWarehouse
|
- zoneWarehouse
|
||||||
|
|
Loading…
Reference in New Issue