refs #5762 feat: multiplatform recover-password and change-password
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2023-07-17 14:24:50 +02:00
parent 0d308ec8ad
commit d2120cdc3d
8 changed files with 35 additions and 40 deletions

View File

@ -7,6 +7,11 @@ module.exports = Self => {
type: 'string',
description: 'The user name or email',
required: true
},
{
arg: 'directory',
type: 'string',
description: 'The directory for mail'
}
],
http: {
@ -15,7 +20,7 @@ module.exports = Self => {
}
});
Self.recoverPassword = async function(user) {
Self.recoverPassword = async function(user, directory) {
const models = Self.app.models;
const usesEmail = user.indexOf('@') !== -1;
@ -29,7 +34,7 @@ module.exports = Self => {
}
try {
await Self.resetPassword({email: user, emailTemplate: 'recover-password'});
await Self.resetPassword({email: user, emailTemplate: 'recover-password', directory});
} catch (err) {
if (err.code === 'EMAIL_NOT_FOUND')
return;

View File

@ -53,19 +53,13 @@ module.exports = Self => {
return Self.validateLogin(user, password);
};
Self.passExpired = async(vnUser, myOptions) => {
Self.passExpired = async vnUser => {
const today = Date.vnNew();
today.setHours(0, 0, 0, 0);
if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) {
const $ = Self.app.models;
const changePasswordToken = await $.AccessToken.create({
scopes: ['changePassword'],
userId: vnUser.id
}, myOptions);
const err = new UserError('Pass expired', 'passExpired');
changePasswordToken.twoFactor = vnUser.twoFactor ? true : false;
err.details = {token: changePasswordToken};
err.details = {userId: vnUser.id, twoFactor: vnUser.twoFactor ? true : false};
throw err;
}
};

View File

@ -99,10 +99,13 @@ module.exports = function(Self) {
const origin = headers.origin;
const user = await Self.app.models.VnUser.findById(info.user.id);
let directory = info.options?.directory ?? '/#!/reset-password?access_token=$token$';
directory = directory.replace('$token$', info.accessToken.id);
const params = {
recipient: info.email,
lang: user.lang,
url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}`
url: origin + directory
};
const options = Object.assign({}, info.options);
@ -158,9 +161,9 @@ module.exports = function(Self) {
}
};
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');
// 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');
// FIXME: https://redmine.verdnatura.es/issues/5761
// Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => {

View File

@ -15,9 +15,6 @@ export default class Controller {
}
$onInit() {
if (!this.$state.params.id)
this.$state.go('login');
this.$http.get('UserPasswords/findOne')
.then(res => {
this.passRequirements = res.data;
@ -25,7 +22,7 @@ export default class Controller {
}
submit() {
const userId = this.$state.params.userId;
const userId = parseInt(this.$state.params.userId);
const oldPassword = this.oldPassword;
const newPassword = this.newPassword;
const repeatPassword = this.repeatPassword;
@ -36,18 +33,13 @@ export default class Controller {
if (newPassword != this.repeatPassword)
throw new UserError(`Passwords don't match`);
const headers = {
Authorization: this.$state.params.id
};
this.$http.patch('Accounts/change-password',
{
id: userId,
userId,
oldPassword,
newPassword,
code
},
{headers}
}
).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Password updated!'));
this.$state.go('login');

View File

@ -36,7 +36,7 @@ export default class Controller {
const err = req.data?.error;
if (err?.code == 'passExpired')
this.$state.go('change-password', err.details.token);
this.$state.go('change-password', err.details);
this.loading = false;
this.password = '';

View File

@ -45,7 +45,7 @@ function config($stateProvider, $urlRouterProvider) {
})
.state('change-password', {
parent: 'outLayout',
url: '/change-password?id&userId&twoFactor',
url: '/change-password?userId&twoFactor',
description: 'Change password',
template: '<vn-change-password></vn-change-password>'
})

View File

@ -1,12 +1,15 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('changePassword', {
Self.remoteMethod('changePassword', {
description: 'Changes the user password',
accessType: 'WRITE',
accessScopes: ['changePassword'],
accepts: [
{
arg: 'userId',
type: 'integer',
description: 'The user id',
required: true
}, {
arg: 'oldPassword',
type: 'string',
description: 'The old password',
@ -28,9 +31,7 @@ module.exports = Self => {
}
});
Self.changePassword = async function(ctx, oldPassword, newPassword, code, options) {
const userId = ctx.req.accessToken.userId;
Self.changePassword = async function(userId, oldPassword, newPassword, code, options) {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);

View File

@ -1,7 +1,7 @@
const {models} = require('vn-loopback/server/server');
describe('account changePassword()', () => {
const ctx = {req: {accessToken: {userId: 70}}};
const userId = 70;
const unauthCtx = {
req: {
headers: {},
@ -20,7 +20,7 @@ describe('account changePassword()', () => {
try {
const options = {transaction: tx};
await models.Account.changePassword(ctx, 'wrongPassword', 'nightmare.9999', null, options);
await models.Account.changePassword(userId, 'wrongPassword', 'nightmare.9999', null, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
@ -37,8 +37,8 @@ describe('account changePassword()', () => {
try {
const options = {transaction: tx};
await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options);
await models.Account.changePassword(ctx, 'nightmare.9999', 'nightmare.9999', null, options);
await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options);
await models.Account.changePassword(userId, 'nightmare.9999', 'nightmare.9999', null, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
@ -54,7 +54,7 @@ describe('account changePassword()', () => {
try {
const options = {transaction: tx};
await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options);
await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
@ -86,8 +86,8 @@ describe('account changePassword()', () => {
}
try {
const authCode = await models.AuthCode.findOne({where: {userFk: 70}}, options);
await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', authCode.code, options);
const authCode = await models.AuthCode.findOne({where: {userFk: userId}}, options);
await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', authCode.code, options);
await tx.rollback();
} catch (e) {
await tx.rollback();