diff --git a/back/methods/vn-user/validate-auth.js b/back/methods/vn-user/validate-auth.js index cc78e983e..8065932f9 100644 --- a/back/methods/vn-user/validate-auth.js +++ b/back/methods/vn-user/validate-auth.js @@ -32,7 +32,7 @@ module.exports = Self => { }); Self.validateAuth = async function(username, password, code) { - await Self.validateCode(code); + await Self.validateCode(username, code); return Self.validateLogin(username, password); }; @@ -52,7 +52,7 @@ module.exports = Self => { const user = await Self.findById(authCode.userFk, { fields: ['name', 'twoFactor'] }); - console.log(username, code); + if (user.name !== username) throw new UserError('Authentication failed'); diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 0448d70ea..da08a2a29 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -153,41 +153,10 @@ module.exports = function(Self) { } }; - // Self.sharedClass._methods.find(method => method.name == 'changePassword') - // .accessScopes = ['change-password']; Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls .filter(acl => acl.property != 'changePassword'); - const _changePassword = Self.prototype.ChangePassword; - Self.prototype.changePassword = async function(oldPassword, newPassword, options, cb) { - if (cb === undefined && typeof options === 'function') { - cb = options; - options = undefined; - } - - const myOptions = {}; - let tx; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - options = myOptions; - - try { - await _changePassword.call(this, oldPassword, newPassword, options); - tx && await tx.commit(); - cb && cb(); - } catch (err) { - tx && await tx.rollback(); - if (cb) cb(err); else throw err; - } - }; - // FIXME: https://redmine.verdnatura.es/issues/5761 // Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { // if (!ctx.args || !ctx.args.data.email) return; diff --git a/front/salix/components/change-password/index.html b/front/salix/components/change-password/index.html index 026374bca..c22c261f5 100644 --- a/front/salix/components/change-password/index.html +++ b/front/salix/components/change-password/index.html @@ -24,8 +24,8 @@ diff --git a/front/salix/components/change-password/index.js b/front/salix/components/change-password/index.js index 81a44d9d5..0067cbe8f 100644 --- a/front/salix/components/change-password/index.js +++ b/front/salix/components/change-password/index.js @@ -15,11 +15,6 @@ export default class Controller { } $onInit() { - this.oldPassword = 'nightmare'; - this.repeatPassword = 'test.1234'; - this.newPassword = 'test.1234'; - this.verificationCode = '1234'; - console.log(this.$state.params); if (!this.$state.params.id) this.$state.go('login'); @@ -34,7 +29,7 @@ export default class Controller { const oldPassword = this.oldPassword; const newPassword = this.newPassword; const repeatPassword = this.repeatPassword; - const verificationCode = this.verificationCode; + const code = this.code; if (!oldPassword || !newPassword || !repeatPassword) throw new UserError(`You must fill all the fields`); @@ -46,18 +41,13 @@ export default class Controller { const headers = { Authorization: this.$state.params.id }; - console.log({ - id: userId, - oldPassword, - newPassword, - verificationCode - }); + this.$http.patch('Accounts/change-password', { id: userId, oldPassword, newPassword, - verificationCode + code }, {headers} ).then(() => { diff --git a/front/salix/components/change-password/locale/es.yml b/front/salix/components/change-password/locale/es.yml index b0f183ce6..147966272 100644 --- a/front/salix/components/change-password/locale/es.yml +++ b/front/salix/components/change-password/locale/es.yml @@ -5,6 +5,7 @@ Repeat password: Repetir contraseña Passwords don't match: Las contraseñas no coinciden You must fill all the fields: Debes rellenar todos los campos You can't use the same password: No puedes usar la misma contraseña +Verification code: Código de verificación Password updated!: ¡Contraseña actualizada! Password requirements: > La contraseña debe tener al menos {{ length }} caracteres de longitud, diff --git a/modules/account/back/methods/account/change-password.js b/modules/account/back/methods/account/change-password.js index 9fbb5dd17..7ea38a221 100644 --- a/modules/account/back/methods/account/change-password.js +++ b/modules/account/back/methods/account/change-password.js @@ -16,27 +16,30 @@ module.exports = Self => { description: 'The new password', required: true }, { - arg: 'verificationCode', + arg: 'code', type: 'string', description: 'The 2FA code' } ], http: { - path: `/changePassword`, + path: `/change-password`, verb: 'PATCH' } }); - Self.changePassword = async function(ctx, oldPassword, newPassword, verificationCode) { + Self.changePassword = async function(ctx, oldPassword, newPassword, code, options) { const userId = ctx.req.accessToken.userId; - const {vnUser} = Self.app.models; + + const myOptions = {...(options || {})}; + + const {VnUser} = Self.app.models; if (oldPassword == newPassword) throw new UserError(`You can't use the same password`); - const user = await vnUser.findById(userId, {fields: ['name', 'twoFactor']}); + const user = await VnUser.findById(userId, {fields: ['name', 'twoFactor']}, myOptions); if (user.twoFactor) - await vnUser.validateCode(user.name, verificationCode); + await VnUser.validateCode(user.name, code, myOptions); - await vnUser.changePassword(userId, oldPassword, newPassword); + await VnUser.changePassword(userId, oldPassword, newPassword, myOptions); }; }; diff --git a/modules/account/back/methods/account/specs/change-password.spec.js b/modules/account/back/methods/account/specs/change-password.spec.js index 0fd6ecbd5..3c2166672 100644 --- a/modules/account/back/methods/account/specs/change-password.spec.js +++ b/modules/account/back/methods/account/specs/change-password.spec.js @@ -1,22 +1,81 @@ const {models} = require('vn-loopback/server/server'); -describe('account changePassword()', () => { - it('should throw an error when old password is wrong', async() => { - let error; - try { - await models.Account.changePassword(1, 'wrongPassword', 'nightmare.9999'); - } catch (e) { - error = e.message; - } +fdescribe('account changePassword()', () => { + let ctx = {req: {accessToken: {userId: 70}}}; - expect(error).toContain('Invalid current password'); + describe('Without 2FA', () => { + it('should throw an error when old password is wrong', async() => { + const tx = await models.Account.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + + await models.Account.changePassword(ctx, 'wrongPassword', 'nightmare.9999', null, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e.message; + } + + expect(error).toContain('Invalid current password'); + }); + + it('should change password', async() => { + const tx = await models.Account.beginTransaction({}); + + try { + const options = {transaction: tx}; + + await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + + expect(e).toBeUndefined(); + } + }); }); - it('should change password', async() => { - try { - await models.Account.changePassword(70, 'nightmare', 'nightmare.9999'); - } catch (e) { - expect(e).toBeUndefined(); - } + describe('With 2FA', () => { + it('should throw an error when code is incorrect', async() => { + const tx = await models.Account.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + await models.VnUser.updateAll( + {id: 70}, + {twoFactor: 'email'} + , options); + await models.Account.changePassword(ctx, 'wrongPassword', 'nightmare.9999', null, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e.message; + } + + expect(error).toContain('Invalid current password'); + }); + + it('should change password when code is correct', async() => { + const tx = await models.Account.beginTransaction({}); + + try { + const options = {transaction: tx}; + await models.VnUser.updateAll( + {id: 70}, + {twoFactor: 'email'} + , options); + await models.VnUser.signin('trainee', 'nightmare', options); + const authCode = await models.AuthCode.findOne({where: {userFk: 70}}, options); + await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', authCode.code, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + + expect(e).toBeUndefined(); + } + }); }); }); diff --git a/modules/account/back/models/account.json b/modules/account/back/models/account.json index b2cbd213b..8fe3e88f9 100644 --- a/modules/account/back/models/account.json +++ b/modules/account/back/models/account.json @@ -37,13 +37,6 @@ "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW" - }, - { - "property": "changePassword", - "accessType": "EXECUTE", - "principalType": "ROLE", - "principalId": "$everyone", - "permission": "ALLOW" - } + } ] } diff --git a/modules/client/back/methods/client/setPassword.js b/modules/client/back/methods/client/setPassword.js index e5b8949e7..68c11406d 100644 --- a/modules/client/back/methods/client/setPassword.js +++ b/modules/client/back/methods/client/setPassword.js @@ -28,7 +28,7 @@ module.exports = Self => { const isAccount = await models.Account.findById(id); if (isClient && !isAccount) - await models.Account.setPassword(id, newPassword); + await models.VnUser.setPassword(id, newPassword); else throw new UserError(`Modifiable password only via recovery or by an administrator`); }; diff --git a/package-lock.json b/package-lock.json index c190065b0..e8176bebf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "salix-back", - "version": "23.24.01", + "version": "23.26.01", "license": "GPL-3.0", "dependencies": { "axios": "^1.2.2", diff --git a/print/templates/email/auth-code/auth-code.js b/print/templates/email/auth-code/auth-code.js index 1606241be..362b307d8 100755 --- a/print/templates/email/auth-code/auth-code.js +++ b/print/templates/email/auth-code/auth-code.js @@ -15,7 +15,7 @@ module.exports = { type: String }, ip: { - type: Number + type: String } } };