api/mail: state the code window and stop logging credentials
The welcome and activation emails now state that the code expires in five minutes, so a code that no longer works reads as expired rather than as mistyped. The mail path no longer writes the user row or the job payload into the log, which also stops the reset token from accumulating there
Pedro Lucas Porcellis porcellis@eletrotupi.com · 24 days ago
bc71b93c4b3cd3b175782e5ea07ea419f9d94381 Browse filesParents
a812da8Changed files
5
Additions
+7
Deletions
-9
api/src/lib/queue/processors/mail.ts
1 1
import { Job } from "bullmq";
2 2
import {
3 3
MailJobName,
4 4
MailJobData,
5 5
WelcomeEmailPayload,
18 18
): Promise<void> {
19 19
// job.name is the discriminant
20 20
switch (job.name as MailJobName) {
21 21
case MailJobName.WelcomeEmail: {
22 22
const data = job.data as WelcomeEmailPayload;
23 -
console.log("Dispatching an welcome email", data);
23 +
console.log("Dispatching a welcome email for user", data.userId);
24 24
25 25
await sendWelcomeEmail(Number(data.userId), data.code);
26 26
27 27
break;
28 28
}
29 29
30 30
case MailJobName.ActivateAccountEmail: {
31 31
const data = job.data as ActivateAccountEmailPayload;
32 -
console.log("Dispatching an activate account email", data);
32 +
console.log("Dispatching an activation email for user", data.userId);
33 33
34 34
await sendActivateAccountEmail(Number(data.userId), data.code);
35 35
36 36
break;
37 37
}
38 38
39 39
case MailJobName.PasswordReset: {
40 40
const data = job.data as PasswordResetPayload;
41 -
console.log("Dispatching an welcome email", data);
41 +
console.log("Dispatching a password reset email for user", data.userId);
42 42
43 43
await sendResetPasswordEmail(data.userId, data.token);
44 44
45 45
break;
46 46
}
47 47
48 48
default:
49 49
throw new Error(`Unknown mail job: ${job.name}`);
50 50
}
51 51
}
api/src/services/mail/sendActivateAccountEmail.ts
1 1
import { findUserById } from '@app/services/user.service';
2 2
import { sendEmail } from '@app/lib/mail';
3 3
4 4
const email = (firstName: string, code: string) => {
5 5
return (`
6 6
Oi, ${firstName}.
7 7
8 8
Você criou sua conta no nexo. Porém, precisa ativar sua conta.
9 9
10 10
Aqui seu código de ativação: ${code}.
11 +
O código expira em cinco minutos.
11 12
12 13
Qualquer coisa prende o grito!
13 14
`)
14 15
}
15 16
16 17
export async function sendActivateAccountEmail(userId: number, code: string): Promise<void> {
17 18
const user = await findUserById(userId)!;
18 -
19 -
console.log("Email/activateAccount: ", user, code);
20 19
21 20
const { data, error } = await sendEmail({
22 21
to: user!.email,
23 22
subject: "Ative sua conta no nexo!",
24 23
text: email(user!.firstName, code)
29 28
}
30 29
31 30
console.log("Email sent successfully!");
32 31
console.log("Email ID:", data?.id);
33 32
}
api/src/services/mail/sendPasswordReset.ts
1 1
import { findUserById } from '@app/services/user.service';
2 2
import { sendEmail } from '@app/lib/mail';
3 3
4 4
const email = (firstName: string, token: string) => {
5 5
return (`
14 14
}
15 15
16 16
export async function sendResetPasswordEmail(userId: number, token: string): Promise<void> {
17 17
const user = await findUserById(userId)!;
18 18
19 -
console.log("Email/passwdReset: ", user);
20 -
21 19
const { data, error } = await sendEmail({
22 20
to: user!.email,
23 21
subject: "Esqueceu a senha do nexo?",
24 22
text: email(user!.firstName, token)
25 23
});
29 27
}
30 28
31 29
console.log("Email sent successfully!");
32 30
console.log("Email ID:", data?.id);
33 31
}
api/src/services/mail/welcome.ts
1 1
import { findUserById } from '@app/services/user.service';
2 2
import { sendEmail } from '@app/lib/mail';
3 3
4 4
const email = (firstName: string, code: string) => {
5 5
return (`
6 6
Oi! Seja bem vindo, ${firstName}.
7 7
8 8
Você criou sua conta com sucesso no nexo! Aqui seu código de ativação: ${code}.
9 +
O código expira em cinco minutos.
9 10
10 11
Qualquer coisa prende o grito!
11 12
`)
12 13
}
13 14
14 15
export async function sendWelcomeEmail(userId: number, code: string): Promise<void> {
15 16
const user = await findUserById(userId)!;
16 -
17 -
console.log("Email/welcome: ", user, code);
18 17
19 18
const { data, error } = await sendEmail({
20 19
to: user!.email,
21 20
subject: "Bem vindo ao nexo!",
22 21
text: email(user!.firstName, code)
27 26
}
28 27
29 28
console.log("Email sent successfully!");
30 29
console.log("Email ID:", data?.id);
31 30
}
api/tests/jobs/mail.test.ts
1 1
import { describe, it, expect, afterAll, beforeEach, vi } from 'vitest'
2 2
import { sendWelcomeEmail } from '@app/services/mail/welcome'
3 3
import { sendActivateAccountEmail } from '@app/services/mail/sendActivateAccountEmail'
4 4
import { sendResetPasswordEmail } from '@app/services/mail/sendPasswordReset'
5 5
import { mailProcessor } from '@app/lib/queue/processors/mail'
44 44
)
45 45
46 46
// The code itself is in the body so the user knows what to enter
47 47
const [call] = mockedSendEmail.mock.calls
48 48
expect(call[0].text).toContain('123456')
49 +
expect(call[0].text).toContain('expira em cinco minutos')
49 50
})
50 51
})
51 52
52 53
describe('sendActivateAccountEmail', () => {
53 54
it('sends to the correct address with the activation code', async () => {
65 66
text: expect.stringContaining('João'),
66 67
})
67 68
)
68 69
const [call] = mockedSendEmail.mock.calls
69 70
expect(call[0].text).toContain('654321')
71 +
expect(call[0].text).toContain('expira em cinco minutos')
70 72
})
71 73
})
72 74
73 75
describe('sendResetPasswordEmail', () => {
74 76
it('sends to the correct address with the reset token', async () => {
112 114
await expect(
113 115
mailProcessor({ name: 'mail:unknown', data: {} } as any)
114 116
).rejects.toThrow('Unknown mail job')
115 117
})
116 118
})