Skip to content

Commit

Permalink
fix: fixed auth issues, added DataPacket to subprocessor list
Browse files Browse the repository at this point in the history
  • Loading branch information
titanism committed Dec 16, 2024
1 parent 689e9ce commit 88aadc8
Show file tree
Hide file tree
Showing 32 changed files with 198 additions and 448 deletions.
14 changes: 7 additions & 7 deletions app/views/dpa/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@

## Key Terms

| Term | Value |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <strong class="text-monospace">Agreement</strong> | This DPA supplements the [Terms of Service](/terms) |
| <strong class="text-monospace">Approved Subprocessors</strong> | [Cloudflare](https://cloudflare.com) (US; DNS, networking, and security provider), [Vultr](https://www.vultr.com) (US; hosting provider), [Digital Ocean](https://digitalocean.com) (US; hosting provider), [Stripe](https://stripe.com) (US; payment processor), [PayPal](https://paypal.com) (US; payment processor) |
| <strong class="text-monospace">Provider Security Contact</strong> | <a href="mailto:security@forwardemail.net"><security@forwardemail.net></a> |
| <strong class="text-monospace">Security Policy</strong> | View [our Security Policy on GitHub](https://github.com/forwardemail/forwardemail.net/security/policy) |
| <strong class="text-monospace">Governing State</strong> | The State of Delaware, United States |
| Term | Value |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <strong class="text-monospace">Agreement</strong> | This DPA supplements the [Terms of Service](/terms) |
| <strong class="text-monospace">Approved Subprocessors</strong> | [Cloudflare](https://cloudflare.com) (US; DNS, networking, and security provider), [DataPacket](https://www.datapacket.com/) (US/UK; hosting provider), [Vultr](https://www.vultr.com) (US; hosting provider), [Digital Ocean](https://digitalocean.com) (US; hosting provider), [Stripe](https://stripe.com) (US; payment processor), [PayPal](https://paypal.com) (US; payment processor) |
| <strong class="text-monospace">Provider Security Contact</strong> | <a href="mailto:security@forwardemail.net"><security@forwardemail.net></a> |
| <strong class="text-monospace">Security Policy</strong> | View [our Security Policy on GitHub](https://github.com/forwardemail/forwardemail.net/security/policy) |
| <strong class="text-monospace">Governing State</strong> | The State of Delaware, United States |


## Changes to the Agreement
Expand Down
1 change: 1 addition & 0 deletions app/views/gdpr/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Listed below are our providers which we use to transfer data internationally and
| Provider | [Data Privacy Framework Program](https://www.dataprivacyframework.gov/) ("DPF") Certified | GDPR Compliance Page |
| ----------------------------------------- | :---------------------------------------------------------------------------------------: | ------------------------------------------------- |
| [Cloudflare](https://cloudflare.com) | :white_check_mark: Yes | <https://www.cloudflare.com/trust-hub/gdpr/> |
| [DataPacket](https://www.datapacket.com/) | :x: No | <https://www.datapacket.com/privacy-policy> |
| [Digital Ocean](https://digitalocean.com) | :x: No | <https://www.digitalocean.com/legal/gdpr> |
| [Vultr](https://www.vultr.com) | :x: No | <https://www.vultr.com/legal/eea-gdpr-privacy/> |
| [Stripe](https://stripe.com/) | :white_check_mark: Yes | <https://stripe.com/legal/privacy-center> |
Expand Down
2 changes: 1 addition & 1 deletion app/views/home.pug
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ block body
li
i.fa.fa-fw.fa-check-circle.text-success
= " "
!= t("SOC 2 Type 2 compliant bare metal servers from Vultr and Digital Ocean.")
!= t("SOC 2 Type 2 compliant bare metal servers from DataPacket, Vultr, and Digital Ocean.")
li
i.fa.fa-fw.fa-check-circle.text-success
= " "
Expand Down
2 changes: 2 additions & 0 deletions helpers/on-auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ async function onAuth(auth, session, fn) {
template: 'alert',
message: {
to,
bcc: config.email.message.from,
subject: i18n.translate(
'CONCURRENCY_EXCEEDED_SUBJECT',
locale,
Expand Down Expand Up @@ -594,6 +595,7 @@ async function onAuth(auth, session, fn) {
});
}

// TODO: we need to use rate limiting concept here where it's rolling as opposed to fix
// increase counter for alias by 1 (with ttl safeguard)
await this.client
.pipeline()
Expand Down
93 changes: 54 additions & 39 deletions helpers/on-connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
const os = require('node:os');
const punycode = require('node:punycode');

const POP3Server = require('wildduck/lib/pop3/server');
const isFQDN = require('is-fqdn');
const POP3Server = require('wildduck/lib/pop3/server');
const { IMAPServer } = require('wildduck/imap-core');

const SMTPError = require('#helpers/smtp-error');
const DenylistError = require('#helpers/denylist-error');
Expand All @@ -27,6 +28,9 @@ async function onConnect(session, fn) {

if (this.isClosing) return fn(new ServerShutdownError());

const isPOP = this.server instanceof POP3Server;
const isIMAP = this.server instanceof IMAPServer;

try {
// this is used for setting Date header if missing on SMTP submission
session.arrivalDate = new Date();
Expand Down Expand Up @@ -81,7 +85,7 @@ async function onConnect(session, fn) {
else if (config.denylist.has(session.remoteAddress))
isDenylisted = session.remoteAddress;

if (isDenylisted) {
if (isDenylisted && !isPOP && !isIMAP) {
const err = new DenylistError(
`The value ${isDenylisted} is denylisted by ${config.urls.web} ; To request removal, you must visit ${config.urls.web}/denylist?q=${isDenylisted} ;`,
550,
Expand All @@ -90,42 +94,59 @@ async function onConnect(session, fn) {
throw err;
}

//
// TODO: we need to do this for all other cloud providers (e.g. via a maintained list)
// <https://github.com/MISP/misp-warninglists>
// <https://github.com/dalisoft/awesome-hosting?tab=readme-ov-file#web-services-platform>
//
// NOTE: due to high amount of connections from AWS spammers on IMAP/POP3 we are preventing connection abuse
//
const isAWS =
session.resolvedClientHostname &&
session.resolvedClientHostname.endsWith('.compute.amazonaws.com');

//
// check if the connecting remote IP address is allowlisted
//
session.isAllowlisted = false;
if (session.resolvedClientHostname && session.resolvedRootClientHostname) {
// check the root domain
session.isAllowlisted = await isAllowlisted(
session.resolvedRootClientHostname,
this.client,
this.resolver
);
if (session.isAllowlisted) {
session.allowlistValue = session.resolvedRootClientHostname;
} else if (
session.resolvedRootClientHostname !== session.resolvedClientHostname
if (!isDenylisted && !isAWS) {
if (
session.resolvedClientHostname &&
session.resolvedRootClientHostname
) {
// if differed, check the sub-domain
// check the root domain
session.isAllowlisted = await isAllowlisted(
session.resolvedClientHostname,
session.resolvedRootClientHostname,
this.client,
this.resolver
);
if (session.isAllowlisted) {
session.allowlistValue = session.resolvedRootClientHostname;
} else if (
session.resolvedRootClientHostname !== session.resolvedClientHostname
) {
// if differed, check the sub-domain
session.isAllowlisted = await isAllowlisted(
session.resolvedClientHostname,
this.client,
this.resolver
);

if (session.isAllowlisted)
session.allowlistValue = session.resolvedClientHostname;
}
}

if (!session.isAllowlisted) {
session.isAllowlisted = await isAllowlisted(
session.remoteAddress,
this.client,
this.resolver
);
if (session.isAllowlisted)
session.allowlistValue = session.resolvedClientHostname;
session.allowlistValue = session.remoteAddress;
}
}

if (!session.isAllowlisted) {
session.isAllowlisted = await isAllowlisted(
session.remoteAddress,
this.client,
this.resolver
);
if (session.isAllowlisted) session.allowlistValue = session.remoteAddress;
}
} catch (err) {
return fn(refineAndLogError(err, session, false, this));
}
Expand All @@ -142,6 +163,7 @@ async function onConnect(session, fn) {
}

try {
// TODO: we need to use rate limiting concept here where it's rolling as opposed to fix
// NOTE: do not change this prefix unless you also change it in `helpers/on-close.js`
const prefix = `concurrent_${this.constructor.name.toLowerCase()}_${
config.env
Expand All @@ -154,25 +176,16 @@ async function onConnect(session, fn) {
if (count >= 50) {
const err = new TypeError(
`${HOSTNAME} detected 50+ connections from ${
session.resolvedClientHostname || session.remoteAddress
session.resolvedRootClientHostname ||
session.resolvedClientHostname ||
session.remoteAddress
} (${session.allowlistValue || 'not allowlisted'})`
);
err.isCodeBug = true;
err.session = session;
logger.fatal(err);
}

//
// TODO: we need to do this for all other cloud providers (e.g. via a maintained list)
// <https://github.com/MISP/misp-warninglists>
// <https://github.com/dalisoft/awesome-hosting?tab=readme-ov-file#web-services-platform>
//
// NOTE: due to high amount of connections from AWS spammers on IMAP/POP3 we are preventing connection abuse
//
const isAWS =
session.resolvedClientHostname &&
session.resolvedClientHostname.endsWith('.compute.amazonaws.com');

//
// NOTE: we do not check in onConnect for denylist/silent/backscatter in MX server
// because we need to let users know of a given email/sender that was rejected
Expand All @@ -185,8 +198,7 @@ async function onConnect(session, fn) {
// because AUTH is required for a user to access the SMTP server anyways
//

if (this.server instanceof POP3Server) return fn();
if (!isAWS && session.isAllowlisted) return fn();
if (!session.isAllowlisted) return fn();

//
// NOTE: until onConnect is available for IMAP and POP3 servers
Expand All @@ -196,6 +208,9 @@ async function onConnect(session, fn) {
// (see this same comment in `helpers/on-auth.js`)
//

// NOTE: auth is handled for POP3/IMAP in onAuth so we don't throw concurrency issue here
if (isPOP || isIMAP) return fn();

// do not allow more than 10 concurrent connections using constructor
if (count > 10) {
// const err = new TypeError(
Expand Down
6 changes: 5 additions & 1 deletion locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -10394,5 +10394,9 @@
"The reason we sent this email is because we detected that it did not have passing SPF nor DKIM and the sender's root domain did not match the From address root domain.": "السبب الذي جعلنا نرسل هذا البريد الإلكتروني هو أننا اكتشفنا أنه لا يحتوي على SPF أو DKIM ناجحين وأن نطاق الجذر الخاص بالمرسل لا يتطابق مع نطاق الجذر الخاص بعنوان المرسل.",
"Possible Phishing from <span class=\"notranslate\">%s</span>": "احتمالية حدوث تصيد احتيالي من <span class=\"notranslate\">%s</span>",
"Webhook request missing X-Signature-Header": "طلب Webhook مفقود X-Signature-Header",
"Invalid signature in webhook request": "توقيع غير صالح في طلب الويب هوك"
"Invalid signature in webhook request": "توقيع غير صالح في طلب الويب هوك",
"DataPacket": "حزمة البيانات",
"(US/UK; hosting provider),": "(الولايات المتحدة/المملكة المتحدة؛ مزود الاستضافة)،",
"https://www.datapacket.com/privacy-policy": "https://www.datapacket.com/privacy-policy",
"SOC 2 Type 2 compliant bare metal servers from DataPacket, Vultr, and Digital Ocean.": "خوادم معدنية متوافقة مع SOC 2 Type 2 من DataPacket وVultr وDigital Ocean."
}
6 changes: 5 additions & 1 deletion locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -10394,5 +10394,9 @@
"The reason we sent this email is because we detected that it did not have passing SPF nor DKIM and the sender's root domain did not match the From address root domain.": "Důvod, proč jsme poslali tento e-mail, je ten, že jsme zjistili, že neprošel SPF ani DKIM a kořenová doména odesílatele neodpovídá kořenové doméně adresy odesílatele.",
"Possible Phishing from <span class=\"notranslate\">%s</span>": "Možný phishing od <span class=\"notranslate\">%s</span>",
"Webhook request missing X-Signature-Header": "V požadavku webhooku chybí X-Signature-Header",
"Invalid signature in webhook request": "Neplatný podpis v požadavku webhooku"
"Invalid signature in webhook request": "Neplatný podpis v požadavku webhooku",
"DataPacket": "DataPacket",
"(US/UK; hosting provider),": "(USA/Velká Británie; poskytovatel hostingu),",
"https://www.datapacket.com/privacy-policy": "https://www.datapacket.com/privacy-policy",
"SOC 2 Type 2 compliant bare metal servers from DataPacket, Vultr, and Digital Ocean.": "Holé kovové servery vyhovující standardu SOC 2 Type 2 od společností DataPacket, Vultr a Digital Ocean."
}
6 changes: 5 additions & 1 deletion locales/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -7397,5 +7397,9 @@
"If you have any questions or comments, then please let us know.": "Hvis du har spørgsmål eller kommentarer, så lad os det vide.",
"Possible Phishing from <span class=\"notranslate\">%s</span>": "Muligt phishing fra <span class=\"notranslate\">%s</span>",
"Webhook request missing X-Signature-Header": "Webhook-anmodning mangler X-Signature-Header",
"Invalid signature in webhook request": "Ugyldig signatur i webhook-anmodning"
"Invalid signature in webhook request": "Ugyldig signatur i webhook-anmodning",
"DataPacket": "Datapakke",
"(US/UK; hosting provider),": "(USA/UK; hostingudbyder),",
"https://www.datapacket.com/privacy-policy": "https://www.datapacket.com/privacy-policy",
"SOC 2 Type 2 compliant bare metal servers from DataPacket, Vultr, and Digital Ocean.": "SOC 2 Type 2-kompatible bare metal-servere fra DataPacket, Vultr og Digital Ocean."
}
6 changes: 5 additions & 1 deletion locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -9433,5 +9433,9 @@
"The reason we sent this email is because we detected that it did not have passing SPF nor DKIM and the sender's root domain did not match the From address root domain.": "Wir haben diese E-Mail gesendet, weil wir festgestellt haben, dass sie weder SPF noch DKIM bestanden hat und die Stammdomäne des Absenders nicht mit der Stammdomäne der Absenderadresse übereinstimmte.",
"Possible Phishing from <span class=\"notranslate\">%s</span>": "Mögliches Phishing von <span class=\"notranslate\">%s</span>",
"Webhook request missing X-Signature-Header": "Webhook-Anfrage ohne X-Signature-Header",
"Invalid signature in webhook request": "Ungültige Signatur in der Webhook-Anforderung"
"Invalid signature in webhook request": "Ungültige Signatur in der Webhook-Anforderung",
"DataPacket": "Datenpaket",
"(US/UK; hosting provider),": "(USA/Großbritannien; Hosting-Anbieter),",
"https://www.datapacket.com/privacy-policy": "https://www.datapacket.com/privacy-policy",
"SOC 2 Type 2 compliant bare metal servers from DataPacket, Vultr, and Digital Ocean.": "SOC 2 Typ 2-kompatible Bare-Metal-Server von DataPacket, Vultr und Digital Ocean."
}
Loading

0 comments on commit 88aadc8

Please sign in to comment.