config.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import os
  2. import random
  3. import string
  4. import subprocess
  5. from urllib.parse import urlparse
  6. from dotenv import load_dotenv
  7. SHA1 = subprocess.getoutput("git rev-parse HEAD")
  8. ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
  9. def get_abs_path(file_path: str):
  10. """append ROOT_DIR for relative path"""
  11. # Already absolute path
  12. if file_path.startswith("/"):
  13. return file_path
  14. else:
  15. return os.path.join(ROOT_DIR, file_path)
  16. config_file = os.environ.get("CONFIG")
  17. if config_file:
  18. config_file = get_abs_path(config_file)
  19. print("load config file", config_file)
  20. load_dotenv(get_abs_path(config_file))
  21. else:
  22. load_dotenv()
  23. RESET_DB = "RESET_DB" in os.environ
  24. COLOR_LOG = "COLOR_LOG" in os.environ
  25. # Allow user to have 1 year of premium: set the expiration_date to 1 year more
  26. PROMO_CODE = "SIMPLEISBETTER"
  27. # Debug mode
  28. DEBUG = os.environ["DEBUG"] if "DEBUG" in os.environ else False
  29. # Server url
  30. URL = os.environ["URL"]
  31. print(">>> URL:", URL)
  32. # Calculate RP_ID for WebAuthn
  33. RP_ID = urlparse(URL).hostname
  34. SENTRY_DSN = os.environ.get("SENTRY_DSN")
  35. # can use another sentry project for the front-end to avoid noises
  36. SENTRY_FRONT_END_DSN = os.environ.get("SENTRY_FRONT_END_DSN") or SENTRY_DSN
  37. # Email related settings
  38. NOT_SEND_EMAIL = "NOT_SEND_EMAIL" in os.environ
  39. EMAIL_DOMAIN = os.environ["EMAIL_DOMAIN"].lower()
  40. SUPPORT_EMAIL = os.environ["SUPPORT_EMAIL"]
  41. SUPPORT_NAME = os.environ.get("SUPPORT_NAME", "Son from SimpleLogin")
  42. ADMIN_EMAIL = os.environ.get("ADMIN_EMAIL")
  43. try:
  44. MAX_NB_EMAIL_FREE_PLAN = int(os.environ["MAX_NB_EMAIL_FREE_PLAN"])
  45. except Exception:
  46. print("MAX_NB_EMAIL_FREE_PLAN is not set, use 5 as default value")
  47. MAX_NB_EMAIL_FREE_PLAN = 5
  48. # maximum number of directory a premium user can create
  49. MAX_NB_DIRECTORY = 50
  50. # transactional email sender
  51. SENDER = os.environ.get("SENDER")
  52. # the directory to store bounce emails
  53. SENDER_DIR = os.environ.get("SENDER_DIR")
  54. ENFORCE_SPF = "ENFORCE_SPF" in os.environ
  55. # allow to override postfix server locally
  56. POSTFIX_SERVER = os.environ.get("POSTFIX_SERVER", "240.0.0.1")
  57. DISABLE_REGISTRATION = "DISABLE_REGISTRATION" in os.environ
  58. # allow using a different postfix port, useful when developing locally
  59. POSTFIX_PORT = None
  60. if "POSTFIX_PORT" in os.environ:
  61. POSTFIX_PORT = int(os.environ["POSTFIX_PORT"])
  62. # Use port 587 instead of 25 when sending emails through Postfix
  63. # Useful when calling Postfix from an external network
  64. POSTFIX_SUBMISSION_TLS = "POSTFIX_SUBMISSION_TLS" in os.environ
  65. if "OTHER_ALIAS_DOMAINS" in os.environ:
  66. OTHER_ALIAS_DOMAINS = eval(
  67. os.environ["OTHER_ALIAS_DOMAINS"]
  68. ) # ["domain1.com", "domain2.com"]
  69. else:
  70. OTHER_ALIAS_DOMAINS = []
  71. # List of domains user can use to create alias
  72. if "ALIAS_DOMAINS" in os.environ:
  73. ALIAS_DOMAINS = eval(os.environ["ALIAS_DOMAINS"]) # ["domain1.com", "domain2.com"]
  74. else:
  75. ALIAS_DOMAINS = OTHER_ALIAS_DOMAINS + [EMAIL_DOMAIN]
  76. ALIAS_DOMAINS = [d.lower().strip() for d in ALIAS_DOMAINS]
  77. # the alias domain used when creating the first alias for user
  78. FIRST_ALIAS_DOMAIN = os.environ.get("FIRST_ALIAS_DOMAIN") or EMAIL_DOMAIN
  79. # list of (priority, email server)
  80. EMAIL_SERVERS_WITH_PRIORITY = eval(
  81. os.environ["EMAIL_SERVERS_WITH_PRIORITY"]
  82. ) # [(10, "email.hostname.")]
  83. # these emails are ignored when computing stats
  84. if os.environ.get("IGNORED_EMAILS"):
  85. IGNORED_EMAILS = eval(os.environ.get("IGNORED_EMAILS"))
  86. else:
  87. IGNORED_EMAILS = []
  88. # disable the alias suffix, i.e. the ".random_word" part
  89. DISABLE_ALIAS_SUFFIX = "DISABLE_ALIAS_SUFFIX" in os.environ
  90. # the email address that receives all unsubscription request
  91. UNSUBSCRIBER = os.environ.get("UNSUBSCRIBER")
  92. DKIM_PRIVATE_KEY_PATH = get_abs_path(os.environ["DKIM_PRIVATE_KEY_PATH"])
  93. DKIM_PUBLIC_KEY_PATH = get_abs_path(os.environ["DKIM_PUBLIC_KEY_PATH"])
  94. DKIM_SELECTOR = b"dkim"
  95. with open(DKIM_PRIVATE_KEY_PATH) as f:
  96. DKIM_PRIVATE_KEY = f.read()
  97. with open(DKIM_PUBLIC_KEY_PATH) as f:
  98. DKIM_DNS_VALUE = (
  99. f.read()
  100. .replace("-----BEGIN PUBLIC KEY-----", "")
  101. .replace("-----END PUBLIC KEY-----", "")
  102. .replace("\r", "")
  103. .replace("\n", "")
  104. )
  105. DKIM_HEADERS = [b"from", b"to"]
  106. # Database
  107. DB_URI = os.environ["DB_URI"]
  108. # Flask secret
  109. FLASK_SECRET = os.environ["FLASK_SECRET"]
  110. MAILBOX_SECRET = FLASK_SECRET + "mailbox"
  111. CUSTOM_ALIAS_SECRET = FLASK_SECRET + "custom_alias"
  112. # AWS
  113. AWS_REGION = "eu-west-3"
  114. BUCKET = os.environ.get("BUCKET")
  115. AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
  116. AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
  117. CLOUDWATCH_LOG_GROUP = CLOUDWATCH_LOG_STREAM = ""
  118. ENABLE_CLOUDWATCH = "ENABLE_CLOUDWATCH" in os.environ
  119. if ENABLE_CLOUDWATCH:
  120. CLOUDWATCH_LOG_GROUP = os.environ["CLOUDWATCH_LOG_GROUP"]
  121. CLOUDWATCH_LOG_STREAM = os.environ["CLOUDWATCH_LOG_STREAM"]
  122. # Paddle
  123. try:
  124. PADDLE_VENDOR_ID = int(os.environ["PADDLE_VENDOR_ID"])
  125. PADDLE_MONTHLY_PRODUCT_ID = int(os.environ["PADDLE_MONTHLY_PRODUCT_ID"])
  126. PADDLE_YEARLY_PRODUCT_ID = int(os.environ["PADDLE_YEARLY_PRODUCT_ID"])
  127. except:
  128. print("Paddle param not set")
  129. PADDLE_VENDOR_ID = -1
  130. PADDLE_MONTHLY_PRODUCT_ID = -1
  131. PADDLE_YEARLY_PRODUCT_ID = -1
  132. PADDLE_PUBLIC_KEY_PATH = get_abs_path(
  133. os.environ.get("PADDLE_PUBLIC_KEY_PATH", "local_data/paddle.key.pub")
  134. )
  135. PADDLE_AUTH_CODE = os.environ.get("PADDLE_AUTH_CODE")
  136. # OpenID keys, used to sign id_token
  137. OPENID_PRIVATE_KEY_PATH = get_abs_path(
  138. os.environ.get("OPENID_PRIVATE_KEY_PATH", "local_data/jwtRS256.key")
  139. )
  140. OPENID_PUBLIC_KEY_PATH = get_abs_path(
  141. os.environ.get("OPENID_PUBLIC_KEY_PATH", "local_data/jwtRS256.key.pub")
  142. )
  143. # Used to generate random email
  144. WORDS_FILE_PATH = get_abs_path(
  145. os.environ.get("WORDS_FILE_PATH", "local_data/words_alpha.txt")
  146. )
  147. # Used to generate random email
  148. if os.environ.get("GNUPGHOME"):
  149. GNUPGHOME = get_abs_path(os.environ.get("GNUPGHOME"))
  150. else:
  151. letters = string.ascii_lowercase
  152. random_dir_name = "".join(random.choice(letters) for _ in range(20))
  153. GNUPGHOME = f"/tmp/{random_dir_name}"
  154. if not os.path.exists(GNUPGHOME):
  155. os.mkdir(GNUPGHOME, mode=0o700)
  156. print("WARNING: Use a temp directory for GNUPGHOME", GNUPGHOME)
  157. # Github, Google, Facebook client id and secrets
  158. GITHUB_CLIENT_ID = os.environ.get("GITHUB_CLIENT_ID")
  159. GITHUB_CLIENT_SECRET = os.environ.get("GITHUB_CLIENT_SECRET")
  160. GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
  161. GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
  162. FACEBOOK_CLIENT_ID = os.environ.get("FACEBOOK_CLIENT_ID")
  163. FACEBOOK_CLIENT_SECRET = os.environ.get("FACEBOOK_CLIENT_SECRET")
  164. # in seconds
  165. AVATAR_URL_EXPIRATION = 3600 * 24 * 7 # 1h*24h/d*7d=1week
  166. # session key
  167. MFA_USER_ID = "mfa_user_id"
  168. FLASK_PROFILER_PATH = os.environ.get("FLASK_PROFILER_PATH")
  169. FLASK_PROFILER_PASSWORD = os.environ.get("FLASK_PROFILER_PASSWORD")
  170. # Job names
  171. JOB_ONBOARDING_1 = "onboarding-1"
  172. JOB_ONBOARDING_2 = "onboarding-2"
  173. JOB_ONBOARDING_3 = "onboarding-3"
  174. JOB_ONBOARDING_4 = "onboarding-4"
  175. # for pagination
  176. PAGE_LIMIT = 20
  177. # Upload to static/upload instead of s3
  178. LOCAL_FILE_UPLOAD = "LOCAL_FILE_UPLOAD" in os.environ
  179. UPLOAD_DIR = None
  180. # Greylisting features
  181. # nb max of activity (forward/reply) an alias can have during 1 min
  182. MAX_ACTIVITY_DURING_MINUTE_PER_ALIAS = 5
  183. # nb max of activity (forward/reply) a mailbox can have during 1 min
  184. MAX_ACTIVITY_DURING_MINUTE_PER_MAILBOX = 10
  185. if LOCAL_FILE_UPLOAD:
  186. print("Upload files to local dir")
  187. UPLOAD_DIR = os.path.join(ROOT_DIR, "static/upload")
  188. if not os.path.exists(UPLOAD_DIR):
  189. print("Create upload dir")
  190. os.makedirs(UPLOAD_DIR)
  191. LANDING_PAGE_URL = os.environ.get("LANDING_PAGE_URL") or "https://simplelogin.io"
  192. # Loading PGP keys when mail_handler runs. To be used locally when init_app is not called.
  193. LOAD_PGP_EMAIL_HANDLER = "LOAD_PGP_EMAIL_HANDLER" in os.environ
  194. DISPOSABLE_FILE_PATH = get_abs_path(
  195. os.environ.get("DISPOSABLE_FILE_PATH", "local_data/local_disposable_domains.txt")
  196. )
  197. with open(get_abs_path(DISPOSABLE_FILE_PATH), "r") as f:
  198. DISPOSABLE_EMAIL_DOMAINS = f.readlines()
  199. DISPOSABLE_EMAIL_DOMAINS = [d.strip().lower() for d in DISPOSABLE_EMAIL_DOMAINS]
  200. DISPOSABLE_EMAIL_DOMAINS = [
  201. d for d in DISPOSABLE_EMAIL_DOMAINS if not d.startswith("#")
  202. ]
  203. # Used when querying info on Apple API
  204. # for iOS App
  205. APPLE_API_SECRET = os.environ.get("APPLE_API_SECRET")
  206. # for Mac App
  207. MACAPP_APPLE_API_SECRET = os.environ.get("MACAPP_APPLE_API_SECRET")
  208. # <<<<< ALERT EMAIL >>>>
  209. # maximal number of alerts that can be sent to the same email in 24h
  210. MAX_ALERT_24H = 4
  211. # When a reverse-alias receives emails from un unknown mailbox
  212. ALERT_REVERSE_ALIAS_UNKNOWN_MAILBOX = "reverse_alias_unknown_mailbox"
  213. # When a forwarding email is bounced
  214. ALERT_BOUNCE_EMAIL = "bounce"
  215. # When a forwarding email is detected as spam
  216. ALERT_SPAM_EMAIL = "spam"
  217. ALERT_SPF = "spf"
  218. # <<<<< END ALERT EMAIL >>>>
  219. # Disable onboarding emails
  220. DISABLE_ONBOARDING = "DISABLE_ONBOARDING" in os.environ