diff --git a/app/config.py b/app/config.py index d9e07f432..8d75f3864 100644 --- a/app/config.py +++ b/app/config.py @@ -205,7 +205,34 @@ def get_env_csv(env_var: str, default: Optional[str]) -> list[str]: # due to a typo, both UNSUBSCRIBER and OLD_UNSUBSCRIBER are supported OLD_UNSUBSCRIBER = os.environ.get("OLD_UNSUBSCRIBER") -DKIM_SELECTOR = b"dkim" +# Load DKIM_SELECTOR or use "dkim" as default +DKIM_SELECTOR = os.environ.get("DKIM_SELECTOR", "dkim") +if "DKIM_SELECTOR" in os.environ and "DKIM_VALID_SELECTORS_LIST" in os.environ: + # read DKIM_SELECTOR and the DKIM_VALID_SELECTORS_LIST from .env, if os.eniron.get fails, failback to the hardcoded values for to ensure SL production stablity. + DKIM_VALID_SELECTORS_LIST = os.environ.get("DKIM_VALID_SELECTORS_LIST", DKIM_SELECTOR) + if DKIM_SELECTOR not in [selector.strip() for selector in DKIM_VALID_SELECTORS_LIST.split(",")]: + raise RuntimeError( + f'"{DKIM_SELECTOR}" must be included in DKIM_VALID_SELECTORS_LIST if both are defined' + ) +elif "DKIM_SELECTOR" in os.environ and "DKIM_VALID_SELECTORS_LIST" not in os.environ: + # else, for single selector compatibility, if DKIM_VALID_SELECTORS_LIST is not defined, + # AND DKIM_SELECTOR is defined, + # in simplelogin.env; USE: the value of DKIM_SELECTOR as the only valid selector + DKIM_VALID_SELECTORS_LIST = DKIM_SELECTOR +elif "DKIM_SELECTOR" not in os.environ and "DKIM_VALID_SELECTORS_LIST" in os.environ: + DKIM_VALID_SELECTORS_LIST = os.environ.get("DKIM_VALID_SELECTORS_LIST") + if str("dkim") not in [selector.strip() for selector in DKIM_VALID_SELECTORS_LIST.split(",")]: + raise RuntimeError( + '"dkim", must be included in DKIM_VALID_SELECTORS_LIST if DKIM_SELECTOR is left to defaults' + ) +else: + # for backward compatibility, if neither DKIM_SELECTOR nor DKIM_VALID_SELECTORS_LIST is defined, use the hardcoded values + DKIM_VALID_SELECTORS_LIST = "dkim,dkim02,dkim03" + raise RuntimeWarning("WARNING: DKIM_SELECTOR and DKIM_VALID_SELECTORS_LIST are not defined in .env, using default values. " + "For better security, please define them in your .env file." + ) + + DKIM_PRIVATE_KEY = None if "DKIM_PRIVATE_KEY_PATH" in os.environ: @@ -213,6 +240,7 @@ def get_env_csv(env_var: str, default: Optional[str]) -> list[str]: with open(DKIM_PRIVATE_KEY_PATH) as f: DKIM_PRIVATE_KEY = f.read() + # Database DB_URI = os.environ["DB_URI"] DB_CONN_NAME = os.environ.get("DB_CONN_NAME", "webapp") diff --git a/app/custom_domain_validation.py b/app/custom_domain_validation.py index fc3ec153c..e9c1d59d9 100644 --- a/app/custom_domain_validation.py +++ b/app/custom_domain_validation.py @@ -141,7 +141,12 @@ def get_dkim_records( dkim_domains.insert(0, partner_domain) output = {} - for key in ("dkim", "dkim02", "dkim03"): + dkim_selectors = [ + s.strip() + for s in config.DKIM_VALID_SELECTORS_LIST.split(",") + if s.strip() + ] + for key in dkim_selectors: records = [ f"{key}._domainkey.{dkim_domain}" for dkim_domain in dkim_domains ] diff --git a/app/email_utils.py b/app/email_utils.py index 796a7b567..f63f3b5ab 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -551,7 +551,7 @@ def add_dkim_signature_with_header( if config.DKIM_PRIVATE_KEY: sig = dkim.sign( message_to_bytes(msg), - config.DKIM_SELECTOR, + config.DKIM_SELECTOR.encode(), email_domain.encode(), config.DKIM_PRIVATE_KEY.encode(), include_headers=dkim_headers, diff --git a/example.env b/example.env index b7a6a5b3b..65448559a 100644 --- a/example.env +++ b/example.env @@ -68,8 +68,20 @@ EMAIL_SERVERS_WITH_PRIORITY=[(10, "email.hostname.")] # By default, emails are sent using the the same Postfix server that receives emails # POSTFIX_SERVER=my-postfix.com -# the DKIM private key used to compute DKIM-Signature +# DKIM private key and selector used to compute DKIM-Signature (the selector is - +# the DNS bit before the period in the cname or txt record for the root domain (EMAIL_DOMAIN) +# for example simplelogin._domainkey.[sl.lan] rather than dkim._domainkey.[sl.lan]) # DKIM_PRIVATE_KEY_PATH=local_data/dkim.key +# DKIM_SELECTOR=simplelogin + +# The VALID DKIM selectors list is used to specify csv list of valid DKIM selectors used by +# other sl-email containers serving the same EMAIL_DOMAIN (setting a unique DKIM_SELECTOR above for each sl-email instances) +# DOES NOT ADD the default selector 'dkim' by default to the list IF, above, DKIM_SELECTOR has been set +# if your running WITHOUT setting DKIM_SELECTOR or DKIM_SELECTOR=dkim, DO specify `dkim` selector in the list. +# DKIM_VALID_SELECTORS_LIST=dkim,simplelogin,simplelogin2 + + + # DB Connection DB_URI=postgresql://myuser:mypassword@localhost:5432/simplelogin