One-Time Password (OTP) package added with comprehensive token management, including OTP verification for team account deletion and ownership transfer.
153 lines
3.5 KiB
TypeScript
153 lines
3.5 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
import { parse } from 'node-html-parser';
|
|
|
|
export class Mailbox {
|
|
constructor(private readonly page: Page) {}
|
|
|
|
async visitMailbox(
|
|
email: string,
|
|
params: {
|
|
deleteAfter: boolean;
|
|
subject?: string;
|
|
},
|
|
) {
|
|
const mailbox = email.split('@')[0];
|
|
|
|
console.log(`Visiting mailbox ${email} ...`);
|
|
|
|
if (!mailbox) {
|
|
throw new Error('Invalid email');
|
|
}
|
|
|
|
const json = await this.getEmail(mailbox, params);
|
|
|
|
if (!json?.body) {
|
|
throw new Error('Email body was not found');
|
|
}
|
|
|
|
console.log(`Email found for ${email}`, {
|
|
id: json.id,
|
|
subject: json.subject,
|
|
date: json.date,
|
|
});
|
|
|
|
const html = (json.body as { html: string }).html;
|
|
const el = parse(html);
|
|
|
|
const linkHref = el.querySelector('a')?.getAttribute('href');
|
|
|
|
if (!linkHref) {
|
|
throw new Error('No link found in email');
|
|
}
|
|
|
|
console.log(`Visiting ${linkHref} from mailbox ${email}...`);
|
|
|
|
return this.page.goto(linkHref);
|
|
}
|
|
|
|
/**
|
|
* Retrieves an OTP code from an email
|
|
* @param email The email address to check for the OTP
|
|
* @param deleteAfter Whether to delete the email after retrieving the OTP
|
|
* @returns The OTP code
|
|
*/
|
|
async getOtpFromEmail(email: string, deleteAfter: boolean = true) {
|
|
const mailbox = email.split('@')[0];
|
|
|
|
console.log(`Retrieving OTP from mailbox ${email} ...`);
|
|
|
|
if (!mailbox) {
|
|
throw new Error('Invalid email');
|
|
}
|
|
|
|
const json = await this.getEmail(mailbox, {
|
|
deleteAfter,
|
|
subject: `One-time password for Makerkit`,
|
|
});
|
|
|
|
if (!json?.body) {
|
|
throw new Error('Email body was not found');
|
|
}
|
|
|
|
const html = (json.body as { html: string }).html;
|
|
|
|
const text = html.match(
|
|
new RegExp(`Your one-time password is: (\\d{6})`),
|
|
)?.[1];
|
|
|
|
if (text) {
|
|
console.log(`OTP code found in text: ${text}`);
|
|
return text;
|
|
}
|
|
|
|
throw new Error('Could not find OTP code in email');
|
|
}
|
|
|
|
async getEmail(
|
|
mailbox: string,
|
|
params: {
|
|
deleteAfter: boolean;
|
|
subject?: string;
|
|
},
|
|
) {
|
|
const url = `http://127.0.0.1:54324/api/v1/mailbox/${mailbox}`;
|
|
|
|
const response = await fetch(url);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch emails: ${response.statusText}`);
|
|
}
|
|
|
|
const json = (await response.json()) as Array<{
|
|
id: string;
|
|
subject: string;
|
|
}>;
|
|
|
|
if (!json || !json.length) {
|
|
console.log(`No emails found for mailbox ${mailbox}`);
|
|
|
|
return;
|
|
}
|
|
|
|
const message = params.subject
|
|
? (() => {
|
|
const filtered = json.filter(
|
|
(item) => item.subject === params.subject,
|
|
);
|
|
|
|
console.log(
|
|
`Found ${filtered.length} emails with subject ${params.subject}`,
|
|
);
|
|
|
|
return filtered[filtered.length - 1];
|
|
})()
|
|
: json[0];
|
|
|
|
console.log(`Message: ${JSON.stringify(message)}`);
|
|
|
|
const messageId = message?.id;
|
|
const messageUrl = `${url}/${messageId}`;
|
|
|
|
const messageResponse = await fetch(messageUrl);
|
|
|
|
if (!messageResponse.ok) {
|
|
throw new Error(`Failed to fetch email: ${messageResponse.statusText}`);
|
|
}
|
|
|
|
// delete message
|
|
if (params.deleteAfter) {
|
|
console.log(`Deleting email ${messageId} ...`);
|
|
|
|
const res = await fetch(messageUrl, {
|
|
method: 'DELETE',
|
|
});
|
|
|
|
if (!res.ok) {
|
|
console.error(`Failed to delete email: ${res.statusText}`);
|
|
}
|
|
}
|
|
|
|
return await messageResponse.json();
|
|
}
|
|
}
|