refator(api): drop useless SES SDK (#65496)

This commit is contained in:
Mrugesh Mohapatra
2026-04-08 04:02:52 +05:30
committed by GitHub
parent 1fb20ded39
commit 7b8273e0e0
8 changed files with 89 additions and 990 deletions
-1
View File
@@ -4,7 +4,6 @@
"url": "https://github.com/freeCodeCamp/freeCodeCamp/issues"
},
"dependencies": {
"@aws-sdk/client-ses": "3.1019.0",
"@fastify/accepts": "5.0.4",
"@fastify/cookie": "11.0.2",
"@fastify/csrf-protection": "7.1.0",
+2 -6
View File
@@ -18,8 +18,7 @@ import addFormats from 'ajv-formats';
import prismaPlugin from './db/prisma.js';
import cookies from './plugins/cookies.js';
import cors from './plugins/cors.js';
import { NodemailerProvider } from './plugins/mail-providers/nodemailer.js';
import { SESProvider } from './plugins/mail-providers/ses.js';
import { createMailProvider } from './plugins/mail-providers/nodemailer.js';
import mailer from './plugins/mailer.js';
import redirectWithMessage from './plugins/redirect-with-message.js';
import security from './plugins/security.js';
@@ -36,7 +35,6 @@ import * as protectedRoutes from './routes/protected/index.js';
import {
API_LOCATION,
EMAIL_PROVIDER,
FCC_ENABLE_DEV_LOGIN_MODE,
FCC_ENABLE_SWAGGER_UI,
FCC_ENABLE_SHADOW_CAPTURE,
@@ -135,9 +133,7 @@ export const build = async (
clientKey: GROWTHBOOK_FASTIFY_CLIENT_KEY
});
const provider =
EMAIL_PROVIDER === 'ses' ? new SESProvider() : new NodemailerProvider();
void fastify.register(mailer, { provider });
void fastify.register(mailer, { provider: createMailProvider() });
// Swagger plugin
if (FCC_ENABLE_SWAGGER_UI ?? fastify.gb.isOn('swagger-ui')) {
+43 -16
View File
@@ -1,7 +1,21 @@
import nodemailer, { Transporter } from 'nodemailer';
import { MailProvider, SendEmailArgs } from '../mailer.js';
import { MAILPIT_HOST } from '../../utils/env.js';
import {
EMAIL_PROVIDER,
MAILPIT_HOST,
SES_SMTP_HOST,
SES_SMTP_USERNAME,
SES_SMTP_PASSWORD
} from '../../utils/env.js';
export type NodemailerConfig = {
host: string;
port: number;
secure: boolean;
auth: { user: string; pass: string };
tls?: { rejectUnauthorized: boolean };
};
/**
* NodemailerProvider is a wrapper around nodemailer that provides a clean
@@ -11,22 +25,12 @@ export class NodemailerProvider implements MailProvider {
private transporter: Transporter;
/**
* Sets up nodemailer, with hardcoded configuration. This is intended for
* use in development with Mailpit.
* Sets up nodemailer with the provided configuration.
*
* @param config - The nodemailer transport configuration.
*/
constructor() {
this.transporter = nodemailer.createTransport({
host: MAILPIT_HOST,
secure: false,
port: 1025,
auth: {
user: 'test',
pass: 'test'
},
tls: {
rejectUnauthorized: false
}
});
constructor(config: NodemailerConfig) {
this.transporter = nodemailer.createTransport(config);
}
/**
@@ -49,3 +53,26 @@ export class NodemailerProvider implements MailProvider {
});
}
}
/**
* Creates a mail provider based on the EMAIL_PROVIDER environment variable.
*/
export function createMailProvider(): NodemailerProvider {
return EMAIL_PROVIDER === 'ses'
? new NodemailerProvider({
host: SES_SMTP_HOST,
port: 465,
secure: true,
auth: {
user: SES_SMTP_USERNAME ?? '',
pass: SES_SMTP_PASSWORD ?? ''
}
})
: new NodemailerProvider({
host: MAILPIT_HOST,
port: 1025,
secure: false,
auth: { user: 'test', pass: 'test' },
tls: { rejectUnauthorized: false }
});
}
-67
View File
@@ -1,67 +0,0 @@
import {
SESClient,
SESClientConfig,
SendEmailCommand
} from '@aws-sdk/client-ses';
import { MailProvider, SendEmailArgs } from '../mailer.js';
import { SES_ID, SES_SECRET, SES_REGION } from '../../utils/env.js';
/**
* SESProvider is a wrapper around nodemailer that provides a clean interface
* for sending email.
*/
export class SESProvider implements MailProvider {
private client: SESClient;
/**
* Sets up SESClient and configures it with keys pulled from environment.
*/
constructor() {
if (!SES_ID || !SES_SECRET || !SES_REGION) {
throw new Error('Email service is set to SES but missing required keys.');
}
const awsConfig: SESClientConfig = {
credentials: {
accessKeyId: SES_ID,
secretAccessKey: SES_SECRET
},
region: SES_REGION
};
this.client = new SESClient(awsConfig);
}
/**
* Sends an email using the SES sdk.
*
* @param param Email options.
* @param param.to Email address to send to.
* @param param.from Email address to send from.
* @param param.subject Email subject.
* @param param.text Email body (raw text only).
* @param param.cc [Optional] Email address to CC.
*/
async send({ to, from, subject, text, cc }: SendEmailArgs) {
const opts = new SendEmailCommand({
Destination: {
ToAddresses: [to],
CcAddresses: cc ? [cc] : []
},
Message: {
Subject: {
Data: subject,
Charset: 'UTF-8'
},
Body: {
Text: {
Charset: 'UTF-8',
Data: text
}
}
},
Source: from
});
await this.client.send(opts);
}
}
+15 -8
View File
@@ -94,12 +94,18 @@ assert.ok(
);
if (process.env.FREECODECAMP_NODE_ENV !== 'development') {
assert.ok(process.env.SES_ID);
assert.ok(process.env.SES_SECRET);
assert.ok(
process.env.SES_SMTP_USERNAME,
'SES_SMTP_USERNAME is required in production.'
);
assert.ok(
process.env.SES_SMTP_PASSWORD,
'SES_SMTP_PASSWORD is required in production.'
);
assert.notEqual(
process.env.SES_SECRET,
'ses_secret_from_aws',
'The SES secret should be changed from the default value.'
process.env.SES_SMTP_PASSWORD,
'ses_smtp_password_from_aws',
'The SES SMTP password should be changed from the default value.'
);
assert.ok(process.env.COOKIE_DOMAIN);
assert.notEqual(process.env.COOKIE_SECRET, 'a_cookie_secret');
@@ -209,9 +215,10 @@ export const SENTRY_ENVIRONMENT =
export const COOKIE_DOMAIN = process.env.COOKIE_DOMAIN;
export const COOKIE_SECRET = process.env.COOKIE_SECRET;
export const JWT_SECRET = process.env.JWT_SECRET;
export const SES_ID = process.env.SES_ID;
export const SES_SECRET = process.env.SES_SECRET;
export const SES_REGION = process.env.SES_REGION || 'us-east-1';
export const SES_SMTP_USERNAME = process.env.SES_SMTP_USERNAME;
export const SES_SMTP_PASSWORD = process.env.SES_SMTP_PASSWORD;
export const SES_SMTP_HOST =
process.env.SES_SMTP_HOST || 'email-smtp.us-east-1.amazonaws.com';
export const SHOW_UPCOMING_CHANGES =
process.env.SHOW_UPCOMING_CHANGES === 'true';
export const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
+6
View File
@@ -34,6 +34,9 @@
"SES_ID",
"SES_REGION",
"SES_SECRET",
"SES_SMTP_HOST",
"SES_SMTP_PASSWORD",
"SES_SMTP_USERNAME",
"SHOW_UPCOMING_CHANGES",
"SOCRATES_API_KEY",
"SOCRATES_ENDPOINT",
@@ -73,6 +76,9 @@
"SES_ID",
"SES_REGION",
"SES_SECRET",
"SES_SMTP_HOST",
"SES_SMTP_PASSWORD",
"SES_SMTP_USERNAME",
"SHOW_UPCOMING_CHANGES",
"SOCRATES_API_KEY",
"SOCRATES_ENDPOINT",
+17 -886
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -70,13 +70,13 @@ FCC_API_LOG_LEVEL=info
FCC_API_LOG_TRANSPORT=pretty
# Email
# use ses in production
# use ses in production, nodemailer for local development (with Mailpit)
EMAIL_PROVIDER=nodemailer
# SES_ID needs to be empty for now, since the api-server will use SES in testing
# if it is set.
SES_ID=
SES_SECRET=ses_secret_from_aws
SES_REGION=us-east-1
# SES SMTP credentials (required in production)
# Generate these from AWS IAM: https://docs.aws.amazon.com/ses/latest/dg/smtp-credentials.html
SES_SMTP_USERNAME=
SES_SMTP_PASSWORD=ses_smtp_password_from_aws
SES_SMTP_HOST=email-smtp.us-east-1.amazonaws.com
# ---------------------
# Client