Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spam form submissions #12

Merged
merged 2 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions src/controllers/accessibility-form-submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,41 @@ describe(handleAccessibilityFormSubmit.name, () => {
});

beforeEach(() => {
emailFormData = stubAccessibilityFormData({
name: "Henry Leroy Jennings",
email: "[email protected]",
phone: "1234567890",
comments: "The buttons are too close together!",
});
emailFormData = stubAccessibilityFormData();

emailTransport = { sendMail: jest.fn() } as unknown as nodemailer.Transporter;
mocked(buildEmailTransport).mockReturnValue(emailTransport);
});

test("sends form data to correct email address", async () => {
const response = await request(app).post("/accessibility-issues")
const ipAddress = "123.456.1.1";
const response = await request(app)
.post("/accessibility-issues")
.type("json")
.set("x-forwarded-for", ipAddress)
.send(JSON.stringify(emailFormData));

expect(emailTransport.sendMail).toHaveBeenCalledWith({
to: accessibilityIssueEmail,
subject: "Washtenaw ID Accessibility Issue Report",
text: `Accessibility report from ${emailFormData.name} <${emailFormData.email}> <tel: ${emailFormData.phone}>\n\n${emailFormData.comments}`,
text: `Accessibility report from ${emailFormData.name} <${emailFormData.email}> <tel: ${emailFormData.phone}>

${emailFormData.comments}

Honeypot: ${emailFormData.honeypotValue}
Time taken to fill out this form: ${emailFormData.timeToFillForm}
IP Address: ${ipAddress}`,
});

expect(response.statusCode).toEqual(200);
});

describe("when the user's name, email, or phone are missing", () => {
describe("when the optional values are missing", () => {
test("sends the body of the email correctly", async () => {
emailFormData.name = "";
emailFormData.phone = "";
emailFormData.email = "";
emailFormData.honeypotValue = "";

const response = await request(app).post("/accessibility-issues")
.type("json")
Expand Down Expand Up @@ -131,6 +136,7 @@ describe(handleAccessibilityFormSubmit.name, () => {
describe("when creating the email transporter fails", () => {
let response: request.Response;
beforeEach(async () => {
// @ts-ignore
mocked(buildEmailTransport).mockImplementation(() => {
throw new Error("Failed to build email transporter");
});
Expand Down
9 changes: 8 additions & 1 deletion src/controllers/accessibility-form-submit.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { RequestHandler } from "express";
import { buildEmailTransport } from "../utilities/email-transport";
import { ENV_KEYS } from "../utilities/environment";
import { HoneypotFormData } from "../utilities/types";

export type AccessibilityFormData = {
name?: string
email?: string
phone?: string
comments: string
}
} & HoneypotFormData;

export const handleAccessibilityFormSubmit: RequestHandler = async (request, response) => {
const formData: AccessibilityFormData = request.body;
Expand All @@ -26,6 +27,12 @@ export const handleAccessibilityFormSubmit: RequestHandler = async (request, res
emailBody = `${emailBody} <tel: ${formData.phone || "no phone number provided"}>`;
emailBody = `${emailBody}\n\n${formData.comments}`;

if (formData.honeypotValue !== "") {
emailBody = `${emailBody}\n\nHoneypot: ${formData.honeypotValue}`;
emailBody = `${emailBody}\nTime taken to fill out this form: ${formData.timeToFillForm}`;
emailBody = `${emailBody}\nIP Address: ${request.headers["x-forwarded-for"]}`;
}

await transport.sendMail({
to: process.env[ENV_KEYS.EMAIL_TO_ACCESSIBILITY],
subject: "Washtenaw ID Accessibility Issue Report",
Expand Down
21 changes: 13 additions & 8 deletions src/controllers/contact-form-submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,40 @@ describe(handleContactFormSubmit.name, () => {
});

beforeEach(() => {
emailFormData = stubContactFormData({
name: "Henry Leroy Jennings",
email: "[email protected]",
phone: "1234567890",
comments: "Hellooooooo!",
});
emailFormData = stubContactFormData();

emailTransport = { sendMail: jest.fn() } as unknown as nodemailer.Transporter;
mocked(buildEmailTransport).mockReturnValue(emailTransport);
});

test("sends form data to correct email address", async () => {
const ipAddress = "123.456.1.1";
const response = await request(app).post(endpoint)
.type("json")
.set("x-forwarded-for", ipAddress)
.send(JSON.stringify(emailFormData));

expect(emailTransport.sendMail).toHaveBeenCalledWith({
to: contactEmail,
subject: "Washtenaw ID General Contact",
text: `General contact from ${emailFormData.name} <${emailFormData.email}> <tel: ${emailFormData.phone}>\n\n${emailFormData.comments}`,
text: `General contact from ${emailFormData.name} <${emailFormData.email}> <tel: ${emailFormData.phone}>

${emailFormData.comments}

Honeypot: ${emailFormData.honeypotValue}
Time taken to fill out this form: ${emailFormData.timeToFillForm}
IP Address: ${ipAddress}`,
});

expect(response.statusCode).toEqual(200);
});

describe("when the user's name, email, or phone are missing", () => {
describe("when the optional values are missing", () => {
test("sends the body of the email correctly", async () => {
emailFormData.name = "";
emailFormData.phone = "";
emailFormData.email = "";
emailFormData.honeypotValue = "";

const response = await request(app).post(endpoint)
.type("json")
Expand Down Expand Up @@ -132,6 +136,7 @@ describe(handleContactFormSubmit.name, () => {
describe("when creating the email transporter fails", () => {
let response: request.Response;
beforeEach(async () => {
// @ts-ignore
mocked(buildEmailTransport).mockImplementation(() => {
throw new Error("Failed to build email transporter");
});
Expand Down
9 changes: 8 additions & 1 deletion src/controllers/contact-form-submit.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { RequestHandler } from "express";
import { buildEmailTransport } from "../utilities/email-transport";
import { ENV_KEYS } from "../utilities/environment";
import { HoneypotFormData } from "../utilities/types";

export type ContactFormData = {
name?: string
email?: string
phone?: string
comments: string
}
} & HoneypotFormData;

export const handleContactFormSubmit: RequestHandler = async (request, response) => {
const formData: ContactFormData = request.body;
Expand All @@ -26,6 +27,12 @@ export const handleContactFormSubmit: RequestHandler = async (request, response)
emailBody = `${emailBody} <tel: ${formData.phone || "no phone number provided"}>`;
emailBody = `${emailBody}\n\n${formData.comments}`;

if (formData.honeypotValue !== "") {
emailBody = `${emailBody}\n\nHoneypot: ${formData.honeypotValue}`;
emailBody = `${emailBody}\nTime taken to fill out this form: ${formData.timeToFillForm}`;
emailBody = `${emailBody}\nIP Address: ${request.headers["x-forwarded-for"]}`;
}

await transport.sendMail({
to: process.env[ENV_KEYS.EMAIL_TO_CONTACT],
subject: "Washtenaw ID General Contact",
Expand Down
10 changes: 9 additions & 1 deletion src/controllers/id-refused-form-submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ describe(handleIdRefusedFormSubmit.name, () => {
});

test("sends form data to correct email address", async () => {
const ipAddress = "123.456.1.1";
const response = await request(app).post("/id-refused")
.type("json")
.set("x-forwarded-for", ipAddress)
.send(JSON.stringify(emailFormData));

expect(emailTransport.sendMail).toHaveBeenCalledWith({
Expand All @@ -41,7 +43,11 @@ describe(handleIdRefusedFormSubmit.name, () => {

reports that ${emailFormData.businessName} on ${emailFormData.businessStreet} in ${emailFormData.businessCity} refused the ID ${emailFormData.whenRefused}.

${emailFormData.description}`,
${emailFormData.description}

Honeypot: ${emailFormData.honeypotValue}
Time taken to fill out this form: ${emailFormData.timeToFillForm}
IP Address: ${ipAddress}`,
});

expect(response.statusCode).toEqual(200);
Expand All @@ -55,6 +61,7 @@ ${emailFormData.description}`,
emailFormData.whenRefused = "";
emailFormData.ageRange = "";
emailFormData.description = "";
emailFormData.honeypotValue = "";

const response = await request(app).post("/id-refused")
.type("json")
Expand Down Expand Up @@ -123,6 +130,7 @@ reports that ${emailFormData.businessName} on ${emailFormData.businessStreet} in
describe("when creating the email transporter fails", () => {
let response: request.Response;
beforeEach(async () => {
// @ts-ignore
mocked(buildEmailTransport).mockImplementation(() => {
throw new Error("Failed to build email transporter");
});
Expand Down
9 changes: 8 additions & 1 deletion src/controllers/id-refused-form-submit.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RequestHandler } from "express";
import { buildEmailTransport } from "../utilities/email-transport";
import { ENV_KEYS } from "../utilities/environment";
import { HoneypotFormData } from "../utilities/types";

export type IdRefusedFormData = {
name?: string;
Expand All @@ -12,7 +13,7 @@ export type IdRefusedFormData = {
whenRefused?: string
ageRange?: string;
description?: string;
};
} & HoneypotFormData;

export const handleIdRefusedFormSubmit: RequestHandler = async (request, response) => {
const formData: IdRefusedFormData = request.body;
Expand All @@ -38,6 +39,12 @@ export const handleIdRefusedFormSubmit: RequestHandler = async (request, respons
emailBody = `${emailBody} refused the ID ${formData.whenRefused || "<no date or time given>"}.`;
emailBody = `${emailBody}\n\n${formData.description || "<no details given>"}`;

if (formData.honeypotValue !== "") {
emailBody = `${emailBody}\n\nHoneypot: ${formData.honeypotValue}`;
emailBody = `${emailBody}\nTime taken to fill out this form: ${formData.timeToFillForm}`;
emailBody = `${emailBody}\nIP Address: ${request.headers["x-forwarded-for"]}`;
}

await transport.sendMail({
to: process.env[ENV_KEYS.EMAIL_TO_CONTACT],
subject: `Washtenaw ID Refused by ${formData.businessName}`,
Expand Down
1 change: 1 addition & 0 deletions src/utilities/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type HoneypotFormData = { honeypotValue: string, timeToFillForm: string };
9 changes: 9 additions & 0 deletions test-helpers/test-factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export const stubIdRefusedFormData = (attributes: Partial<IdRefusedFormData> = {
ageRange: attributes.ageRange === undefined ? faker.helpers.arrayElement(["under 18", "over 55"]) : attributes.ageRange,

description: attributes.description === undefined ? faker.lorem.paragraph(3) : attributes.description,

honeypotValue: attributes.honeypotValue === undefined ? "Stub Honeypot Value" : attributes.honeypotValue,
timeToFillForm: attributes.timeToFillForm === undefined ? "Stub time to fill form" : attributes.timeToFillForm
};
};

Expand All @@ -56,6 +59,9 @@ export const stubAccessibilityFormData = (attributes: Partial<AccessibilityFormD
email: attributes.email === undefined ? "[email protected]" : attributes.email,
phone: attributes.phone === undefined ? "9999999999" : attributes.phone,
comments: attributes.comments === undefined ? "Stub Description" : attributes.comments,

honeypotValue: attributes.honeypotValue === undefined ? "Stub Honeypot Value" : attributes.honeypotValue,
timeToFillForm: attributes.timeToFillForm === undefined ? "Stub time to fill form" : attributes.timeToFillForm
};
};

Expand All @@ -65,6 +71,9 @@ export const stubContactFormData = (attributes: Partial<ContactFormData> = {}):
email: attributes.email === undefined ? "[email protected]" : attributes.email,
phone: attributes.phone === undefined ? "9999999999" : attributes.phone,
comments: attributes.comments === undefined ? "Stub Description" : attributes.comments,

honeypotValue: attributes.honeypotValue === undefined ? "Stub Honeypot Value" : attributes.honeypotValue,
timeToFillForm: attributes.timeToFillForm === undefined ? "Stub time to fill form" : attributes.timeToFillForm
};
};

Expand Down
Loading