Skip to content

Commit

Permalink
feat: bridge to send email
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustrb committed Aug 5, 2024
1 parent a30e298 commit 333901b
Showing 1 changed file with 19 additions and 68 deletions.
87 changes: 19 additions & 68 deletions apps/meteor/app/apps/server/bridges/email.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,32 @@
import type { IAppServerOrchestrator } from '@rocket.chat/apps';
import { Random } from '@rocket.chat/random';
import bcrypt from 'bcrypt';
import { EmailBridge } from '@rocket.chat/apps-engine/server/bridges/EmailBridge';

Check failure on line 2 in apps/meteor/app/apps/server/bridges/email.ts

View workflow job for this annotation

GitHub Actions / 🔎 Code Check / Code Lint

Unable to resolve path to module '@rocket.chat/apps-engine/server/bridges/EmailBridge'
import { settings } from '../../../settings/server';
import * as Mailer from '../../../mailer/server/api';
import { Accounts } from 'meteor/accounts-base';

import { i18n } from '../../../../server/lib/i18n';
import { addEmailCodeByContactEmail, findContactCodeFromChannelAndEmail, incrementInvalidEmailCodeAttemptByVerifyingMethod } from '../../../livechat/server/lib/Contacts';
import * as Mailer from '../../../mailer/server/api';
import { settings } from '../../../settings/server';

export class AppEmailBridge extends EmailBridge {
constructor(private readonly orch: IAppServerOrchestrator) {
super();
}

protected async sendOtpCodeThroughSMTP(email: string, channel: string, appId: string): Promise<any> {
this.orch.debugLog(`The app: ${appId} is requesting an OTP code to be sent to: ${email}`);
const random = Random._randomString(6, '0123456789');
const encriptedRandom = await bcrypt.hash(random, Accounts._bcryptRounds());
const expire = new Date();
const expirationInSeconds = parseInt(settings.get('Accounts_TwoFactorAuthentication_By_Email_Code_Expiration') as string, 10);

expire.setSeconds(expire.getSeconds() + expirationInSeconds);

await addEmailCodeByContactEmail(email, channel, encriptedRandom, expire);
await this.send2FAEmail(email, random);
}
protected async sendOtpCodeThroughSMTP(email: string, code: string, language: string, appId: string): Promise<void> {
this.orch.debugLog(`The app: ${appId} is requesting an OTP code to be sent to: ${email}`);
await this.send2FAEmail(email, code, language);
}

private async send2FAEmail(email: string, code: string): Promise<any> {
// TODO: Fetch the language from within the app's settings
const language = settings.get('Language') || 'en';
const t = (s: string): string => i18n.t(s, { lng: language });
private async send2FAEmail(email: string, code: string, language: string): Promise<void> {
const t = (s: string): string => i18n.t(s, { lng: language || 'en' });

await Mailer.send({
to: email,
from: settings.get('From_Email'),
subject: 'Authentication code',
replyTo: undefined,
data: {
await Mailer.send({
to: email,
from: settings.get('From_Email'),
subject: 'Authentication code',
replyTo: undefined,
data: {
code: code.replace(/^(\d{3})/, '$1-'),
},
headers: undefined,
},
headers: undefined,
text: `
${t('Here_is_your_authentication_code')}
Expand All @@ -56,42 +43,6 @@ ${t('If_you_didnt_try_to_login_in_your_account_please_ignore_this_email')}
<p>${t('Do_not_provide_this_code_to_anyone')}</p>
<p>${t('If_you_didnt_try_to_login_in_your_account_please_ignore_this_email')}</p>
`,
});
}

protected async verifyOTPCode(code: string, channel: string, email: string, appId: string): Promise<any> {
this.orch.debugLog(`The app: ${appId} is verifying an OTP code sent to: ${email}`);

const { code: actualCode, expiresAt, attempts } = await findContactCodeFromChannelAndEmail(channel, email);
const normalizedCode = code.replace(/([^\d])/g, '');
const maxAttempts = settings.get<number>('Accounts_TwoFactorAuthentication_Max_Invalid_Email_Code_Attempts');

if (attempts > maxAttempts) {
throw new Error('TODO: Max attempts exceeded, implement');
// TODO: return unverified and generate new code
return;
}

if (expiresAt < new Date()) {
throw new Error('TODO: code expired, implement');
// TODO: generate new code, since the old one has expired
// TODO: Return the info saying the code has expired
return;
}

if (await bcrypt.compare(normalizedCode, actualCode)) {
throw new Error('TODO: Correct code, implement');
// TODO: Remove the code from the channels list
// TODO: Return object saying the code is valid
return;
}

// Otherwise, the code is invalid, so we must increment the number of attempts
// and return the status
await incrementInvalidEmailCodeAttemptByVerifyingMethod(email, channel);
throw new Error('TODO: Invalid code, implement');

// TODO: Return object saying the attempt was wrong
return;
}
});
}
}

0 comments on commit 333901b

Please sign in to comment.