refactor(vnUser): refs #7792 use twoFactorFk and add foreignKey
gitea/salix/pipeline/pr-dev Build queued... Details

This commit is contained in:
Alex Moreno 2024-09-09 09:58:20 +02:00
parent 05b75c1f0d
commit 71eb44d083
14 changed files with 83 additions and 23 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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});
}; };
}; };

View File

@ -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())

View File

@ -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"
] ]
} }
} }

View File

@ -9,7 +9,7 @@
}, },
"vn": { "vn": {
"view": { "view": {
"expeditionPallet_Print": "ced2b84a114fcb99fce05f0c34f4fc03f3fa387bef92621be1bc306608a84345" "expeditionPallet_Print": "99f75145ac2e7b612a6d71e74b6e55f194a465780fd9875a15eb01e6596b447e"
} }
} }
} }

View File

@ -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$$

View File

@ -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';

View File

@ -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"

View File

@ -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);

View File

@ -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);

View File

@ -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": {

View File

@ -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"
}
]
}

View File

@ -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