diff --git a/docker-compose-speckle.yml b/docker-compose-speckle.yml index 8dff4b04c..c5d45ee99 100644 --- a/docker-compose-speckle.yml +++ b/docker-compose-speckle.yml @@ -94,7 +94,8 @@ services: S3_REGION: '' # optional, defaults to 'us-east-1' FILE_SIZE_LIMIT_MB: 1000 EMAIL_FROM: 'no-reply@example.org' - EMAIL_SECURE: 'false' # If connecting to maildev server, do not use TLS + EMAIL_SECURE: 'false' # Force the use of SSL. If connecting to maildev server, do not use SSL. + EMAIL_REQUIRE_TLS: 'false' # Force the use of TLS. If your email server supports STARTTLS, you probably want this enabled instead of EMAIL_SECURE. If connecting to maildev server, do not use TLS. FRONTEND_ORIGIN: 'http://127.0.0.1' ONBOARDING_STREAM_URL: 'https://latest.speckle.systems/projects/843d07eb10' diff --git a/packages/server/.env.example b/packages/server/.env.example index 01584c39f..14e9bf574 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -75,7 +75,10 @@ EMAIL=true EMAIL_HOST="127.0.0.1" EMAIL_FROM="no-reply@example.org" EMAIL_PORT="1025" +# Email secure enables SSL. If your server supports STARTTLS, +# you probably want to set EMAIL_REQUIRE_TLS instead. EMAIL_SECURE="false" +EMAIL_REQUIRE_TLS="false" # EMAIL_HOST="-> FILL IN <-" # EMAIL_PORT="-> FILL IN <-" diff --git a/packages/server/modules/emails/utils/transporter.ts b/packages/server/modules/emails/utils/transporter.ts index 805c9ad5e..db421ecc3 100644 --- a/packages/server/modules/emails/utils/transporter.ts +++ b/packages/server/modules/emails/utils/transporter.ts @@ -6,8 +6,9 @@ import { getEmailPort, getEmailUsername, isEmailEnabled, - isSecureEmailEnabled, - isTestEnv + isSSLEmailEnabled, + isTestEnv, + isTLSEmailRequired } from '@/modules/shared/helpers/envHelper' import type { Transporter } from 'nodemailer' import { createTransport } from 'nodemailer' @@ -21,7 +22,8 @@ const initSmtpTransporter = async () => { const smtpTransporter = createTransport({ host: getEmailHost(), port: getEmailPort(), - secure: isSecureEmailEnabled(), + requireTLS: isTLSEmailRequired(), + secure: isSSLEmailEnabled(), auth: { user: getEmailUsername(), pass: getEmailPassword() diff --git a/packages/server/modules/shared/helpers/envHelper.ts b/packages/server/modules/shared/helpers/envHelper.ts index b86595f34..42003b9b8 100644 --- a/packages/server/modules/shared/helpers/envHelper.ts +++ b/packages/server/modules/shared/helpers/envHelper.ts @@ -3,6 +3,7 @@ import { has, trimEnd } from 'lodash-es' import * as Environment from '@speckle/shared/environment' import type { Nullable } from '@speckle/shared' import { ensureError } from '@speckle/shared' +import { logger } from '@/observability/logging' export function getStringFromEnv( envVarKey: string, @@ -383,8 +384,24 @@ export function getEmailPort() { return getIntFromEnv('EMAIL_PORT', '587') } -export function isSecureEmailEnabled() { - return getBooleanFromEnv('EMAIL_SECURE', true) // default to secure +export function isSSLEmailEnabled() { + const sslRequired = getBooleanFromEnv('EMAIL_SECURE', false) // see EMAIL_REQUIRE_TLS + if (sslRequired && isTLSEmailRequired()) { + throw new MisconfiguredEnvironmentError( + 'EMAIL_SECURE and EMAIL_REQUIRE_TLS cannot both be true. TLS would typically be preferred over SSL.' + ) + } + return sslRequired +} + +export function isTLSEmailRequired() { + const tlsRequired = getBooleanFromEnv('EMAIL_REQUIRE_TLS', true) // default to true + if (!tlsRequired && !isSSLEmailEnabled()) { + logger.warn( + 'Neither EMAIL_SECURE and EMAIL_REQUIRE_TLS are true. Client will attempt to upgrade to TLS on connect, but will default to whatever the server supports which may be insecure.' + ) + } + return tlsRequired } export function getEmailUsername() { diff --git a/utils/helm/speckle-server/templates/_helpers.tpl b/utils/helm/speckle-server/templates/_helpers.tpl index 097b3af1b..61fe87ade 100644 --- a/utils/helm/speckle-server/templates/_helpers.tpl +++ b/utils/helm/speckle-server/templates/_helpers.tpl @@ -985,6 +985,8 @@ Generate the environment variables for Speckle server and Speckle objects deploy value: {{ .Values.server.email.from | quote }} - name: EMAIL_SECURE value: {{ .Values.server.email.secure | quote }} +- name: EMAIL_REQUIRE_TLS + value: {{ .Values.server.email.requireTLS | quote }} - name: EMAIL_VERIFICATION_TIMEOUT_MINUTES value: {{ .Values.server.email.verificationTimeoutMinutes | quote }} {{- end }} diff --git a/utils/helm/speckle-server/values.schema.json b/utils/helm/speckle-server/values.schema.json index bb25fc0aa..e509cdc10 100644 --- a/utils/helm/speckle-server/values.schema.json +++ b/utils/helm/speckle-server/values.schema.json @@ -1309,7 +1309,12 @@ }, "secure": { "type": "boolean", - "description": "If true, will use TLS when connecting to the email server", + "description": "If true, will use SSL when connecting to the email server. requireTLS would be preferable if the server supports it. Both 'secure' and 'requireTLS' can be false if the email server does not support encryption, but this is not recommended. Both 'secure' and 'requireTLS' cannot be true at the same time.", + "default": false + }, + "requireTLS": { + "type": "boolean", + "description": "If true, will require TLS when connecting to the email server. This is preferable to 'secure' if the email server supports TLS. Both 'secure' and 'requireTLS' can be false if the email server does not support encryption, but this is not recommended. Both 'secure' and 'requireTLS' cannot be true at the same time.", "default": true }, "networkPolicy": { diff --git a/utils/helm/speckle-server/values.yaml b/utils/helm/speckle-server/values.yaml index 7cb0c8935..77aeed95a 100644 --- a/utils/helm/speckle-server/values.yaml +++ b/utils/helm/speckle-server/values.yaml @@ -800,9 +800,12 @@ server: ## @param server.email.password.secretKey The key within the Kubernetes Secret holding the email password as its value. ## secretKey: '' - ## @param server.email.secure If true, will use TLS when connecting to the email server + ## @param server.email.secure If true, will use SSL when connecting to the email server. requireTLS would be preferable if the server supports it. Both 'secure' and 'requireTLS' can be false if the email server does not support encryption, but this is not recommended. Both 'secure' and 'requireTLS' cannot be true at the same time. ## - secure: true + secure: false + ## @param server.email.requireTLS If true, will require TLS when connecting to the email server. This is preferable to 'secure' if the email server supports TLS. Both 'secure' and 'requireTLS' can be false if the email server does not support encryption, but this is not recommended. Both 'secure' and 'requireTLS' cannot be true at the same time. + ## + requireTLS: true ## @extra server.email.networkPolicy If networkPolicy is enabled for Speckle server, this provides the Network Policy with the necessary details to allow egress connections to the email server ## networkPolicy: