diff --git a/back/methods/account/login.js b/back/methods/account/login.js index 2f6a04893..2eeb5a1c4 100644 --- a/back/methods/account/login.js +++ b/back/methods/account/login.js @@ -44,7 +44,7 @@ module.exports = Self => { ? {email: user} : {name: user}; let account = await Self.findOne({ - fields: ['id', 'active', 'password', 'twoFactor'], + fields: ['id', 'active', 'email', 'password', 'twoFactor'], where }); @@ -80,10 +80,15 @@ module.exports = Self => { expires: Date.now() + maxTTL }); - ctx.args.code = code; + const params = { + recipientId: account.id, + recipient: account.email, + code: code + }; + ctx.args = {...ctx.args, ...params}; await Self.sendTemplate(ctx, 'auth-code'); - throw new ForbiddenError(); + throw new ForbiddenError('REQUIRES_2FA'); } } diff --git a/back/methods/account/specs/login.spec.js b/back/methods/account/specs/login.spec.js index a51f6b91e..9f6c0c17d 100644 --- a/back/methods/account/specs/login.spec.js +++ b/back/methods/account/specs/login.spec.js @@ -1,26 +1,35 @@ -const app = require('vn-loopback/server/server'); +const {models} = require('vn-loopback/server/server'); -describe('account login()', () => { - const unauthCtx = {}; +fdescribe('account login()', () => { + const employeeId = 1; + const unauthCtx = { + req: { + connection: { + remoteAddress: '127.0.0.1' + }, + getLocale: () => 'en' + }, + args: {} + }; describe('when credentials are correct', () => { it('should return the token', async() => { - let login = await app.models.Account.login(unauthCtx, 'salesAssistant', 'nightmare'); - let accessToken = await app.models.AccessToken.findById(login.token); + let login = await models.Account.login(unauthCtx, 'salesAssistant', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; expect(login.token).toBeDefined(); - await app.models.Account.logout(ctx); + await models.Account.logout(ctx); }); it('should return the token if the user doesnt exist but the client does', async() => { - let login = await app.models.Account.login(unauthCtx, 'PetterParker', 'nightmare'); - let accessToken = await app.models.AccessToken.findById(login.token); + let login = await models.Account.login(unauthCtx, 'PetterParker', 'nightmare'); + let accessToken = await models.AccessToken.findById(login.token); let ctx = {req: {accessToken: accessToken}}; expect(login.token).toBeDefined(); - await app.models.Account.logout(ctx); + await models.Account.logout(ctx); }); }); @@ -29,7 +38,7 @@ describe('account login()', () => { let error; try { - await app.models.Account.login(unauthCtx, 'IDontExist', 'TotallyWrongPassword'); + await models.Account.login(unauthCtx, 'IDontExist', 'TotallyWrongPassword'); } catch (e) { error = e; } @@ -39,4 +48,27 @@ describe('account login()', () => { expect(error.code).toBe('LOGIN_FAILED'); }); }); + + describe('when two-factor auth is required', () => { + it('should throw a 403 error', async() => { + let error; + const Account = models.Account; + + const employee = await Account.findById(employeeId); + + try { + await employee.updateAttribute('twoFactor', 'email'); + + await Account.login(unauthCtx, 'employee', 'nightmare'); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.statusCode).toBe(403); + expect(error.message).toBe('REQUIRES_2FA'); + + await employee.updateAttribute('twoFactor', null); + }); + }); }); diff --git a/print/templates/email/auth-code/auth-code.html b/print/templates/email/auth-code/auth-code.html index ea87e6c66..858390f1c 100644 --- a/print/templates/email/auth-code/auth-code.html +++ b/print/templates/email/auth-code/auth-code.html @@ -11,7 +11,7 @@
{{ code }}
-

{{$t('It expires in 5 minutes.')}}

+

{{$t('It expires in 5 minutes')}}

\ No newline at end of file diff --git a/print/templates/email/auth-code/locale/en.yml b/print/templates/email/auth-code/locale/en.yml new file mode 100644 index 000000000..5f63d280f --- /dev/null +++ b/print/templates/email/auth-code/locale/en.yml @@ -0,0 +1,5 @@ +subject: Verification code +title: Verification code +description: Somebody did request a verification code for login. If you didn't request it, please ignore this email. +Enter the following code to continue to your account: Enter the following code to continue to your account +It expires in 5 minutes: It expires in 5 minutes diff --git a/print/templates/email/auth-code/locale/es.yml b/print/templates/email/auth-code/locale/es.yml index b77937468..31952891b 100644 --- a/print/templates/email/auth-code/locale/es.yml +++ b/print/templates/email/auth-code/locale/es.yml @@ -2,4 +2,4 @@ subject: Código de verificación title: Código de verificación description: Alguien ha solicitado un código de verificación para poder iniciar sesión. Si no lo has solicitado tu, ignora este email. Enter the following code to continue to your account: Introduce el siguiente código para poder continuar con tu cuenta -It expires in 5 minutes.: Expira en 5 minutos +It expires in 5 minutes: Expira en 5 minutos diff --git a/print/templates/email/auth-code/locale/fr.yml b/print/templates/email/auth-code/locale/fr.yml index 34fee9d1e..e435a2487 100644 --- a/print/templates/email/auth-code/locale/fr.yml +++ b/print/templates/email/auth-code/locale/fr.yml @@ -2,4 +2,4 @@ subject: Code de vérification title: Code de vérification description: Quelqu'un a demandé un code de vérification pour se connecter. Si ce n'était pas toi, ignore cet email. Enter the following code to continue to your account: Entrez le code suivant pour continuer avec votre compte -It expires in 5 minutes.: Il expire dans 5 minutes. +It expires in 5 minutes: Il expire dans 5 minutes. diff --git a/print/templates/email/auth-code/locale/pt.yml b/print/templates/email/auth-code/locale/pt.yml index 9ffa1b2f6..940b03c4d 100644 --- a/print/templates/email/auth-code/locale/pt.yml +++ b/print/templates/email/auth-code/locale/pt.yml @@ -2,4 +2,4 @@ subject: Código de verificação title: Código de verificação description: Alguém solicitou um código de verificação para entrar. Se você não fez essa solicitação, ignore este e-mail. Enter the following code to continue to your account: Insira o seguinte código para continuar com sua conta. -It expires in 5 minutes.: Expira em 5 minutos. +It expires in 5 minutes: Expira em 5 minutos.