Skip to content
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
64 changes: 49 additions & 15 deletions ENV_LIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
The list of environment variables that can be set for this system is as follows.

## Basic Settings
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|-------------------------|----------|------------------------------------------|-------------------------------------------------|-----------------------------------------------------------|
| APP_ENV | False | Running environment | local / dev / live | local |
| APP_ENV | False | Running environment | local / dev / live | local |
| NETWORK | False | Running network | IBET / IBETFIN | IBET |
| WEB3_CHAINID | False | Blockchain network ID | 1010032 | IBET: 1500002, IBETFIN: 1010032 |
| WEB3_HTTP_PROVIDER | False | Web3 provider | http://localhost:8545 | http://localhost:8545 |
Expand All @@ -18,7 +18,7 @@ The list of environment variables that can be set for this system is as follows.
| APP_LOGFILE | False | Output location for application logs | /some/directory | /dev/stdout (standard output) |
| ACCESS_LOGFILE | False | Output location for access logs | /some/directory | /dev/stdout (standard output) |
| TZ | False | Time Zone | Europe/Berlin | Asia/Tokyo |
| DEFAULT_CURRENCY | False | Default currency code | EUR | JPY |
| DEFAULT_CURRENCY | False | Default currency code | EUR | JPY |


## API Server Settings
Expand All @@ -27,9 +27,9 @@ The following parameters can be set as environment variables as startup paramete

See [Gunicorn's official documentation](https://docs.gunicorn.org/en/stable/run.html#commonly-used-arguments) for details.

| Variable Name | Required | Details | Default |
| Variable Name | Required | Details | Default |
|----------------------------|----------|--------------------------------------------------------------------------|---------|
| WORKER_COUNT | False | The number of worker processes. | 2 |
| WORKER_COUNT | False | The number of worker processes. | 2 |
| WORKER_TIMEOUT | False | Workers silent for more than this many seconds are killed and restarted. | 60 |
| WORKER_MAX_REQUESTS | False | The maximum number of requests a worker will process before restarting. | 0 |
| WORKER_MAX_REQUESTS_JITTER | False | The maximum jitter to add to the max_requests setting. | 0 |
Expand All @@ -38,7 +38,7 @@ See [Gunicorn's official documentation](https://docs.gunicorn.org/en/stable/run.
## Settings for each use case

### Token
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|--------------------------------|----------|--------------------------------------------------------------------|--------------------------------------------|---------|
| BOND_TOKEN_ENABLED | False | Using ibet Bond token (security token) | 0 (not using) / 1 (using) | 0 |
| SHARE_TOKEN_ENABLED | False | Using ibet Share token (security token) | 0 (not using) / 1 (using) | 0 |
Expand All @@ -52,42 +52,43 @@ See [Gunicorn's official documentation](https://docs.gunicorn.org/en/stable/run.
| TOKEN_SHORT_TERM_CACHE_TTL | False | Token attribute data cache (Short-Term) expiration time (seconds) | 60 | 40 |

### Token Escrow
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------------------------------|----------|---------------------------------------------|--------------------------------------------|---------|
| IBET_ESCROW_CONTRACT_ADDRESS | False | Ibet Escrow contract address | 0x0000000000000000000000000000000000000000 | -- |
| IBET_SECURITY_TOKEN_ESCROW_CONTRACT_ADDRESS | False | Ibet Security Token Escrow contract address | 0x0000000000000000000000000000000000000000 | -- |

### Token DVP

| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------------------------------|----------|---------------------------------------------|--------------------------------------------|---------|
| IBET_SECURITY_TOKEN_DVP_CONTRACT_ADDRESS | False | Ibet Security Token DVP contract address | 0x0000000000000000000000000000000000000000 | -- |

### On-chain Exchange (Only for utility tokens)
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------------------------------|----------|--------------------------------------------------------------------------|--------------------------------------------|---------|
| PAYMENT_GATEWAY_CONTRACT_ADDRESS | False | PaymentGateway contract address | 0x0000000000000000000000000000000000000000 | -- |
| IBET_MEMBERSHIP_EXCHANGE_CONTRACT_ADDRESS | False | IbetExchange contract address for Membership tokens | 0x0000000000000000000000000000000000000000 | -- |
| IBET_COUPON_EXCHANGE_CONTRACT_ADDRESS | False | IbetExchange contract address for Coupon tokens | 0x0000000000000000000000000000000000000000 | -- |
| EXCHANGE_NOTIFICATION_ENABLED | True* | Use of exchange-related notification (*Set only if you use IbetExchange) | 0 (not using) / 1 (using) | -- |

### Blockchain Explorer
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------|----------|-----------------------------------------------------|---------------------------|---------|
| BC_EXPLORER_ENABLED | False | Parameter for starting the Blockchain Explorer | 0 (not using) / 1 (using) | 0 |

### Email
Common

| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------------------|----------|--------------------------------------------|---------------------------------|---------|
| SMTP_METHOD | False | Email sending method | 0:SMTP server, 1:Amazon SES | 0 |
| SMTP_AUTH_METHOD | False | Authentication method | 0:PASSWORD, 1:XOAUTH2 | 0 |
| SMTP_SENDER_NAME | False | Sender name | | -- |
| SMTP_SENDER_EMAIL | False | Sender email address | example@example.com | -- |

SMTP server

| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|-------------------------------|----------|-------------------------------------------|---------------------------------|---------|
| SMTP_SERVER_HOST | False | SMTP server name | smtp.office365.com | -- |
| SMTP_SERVER_PORT | False | SMTP server port | 587 | -- |
Expand All @@ -96,13 +97,21 @@ SMTP server

Amazon SES

| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|---------------------|----------|-----------------|-----------|---------|
| AWS_SES_REGION_NAME | False | AWS region name | us-east-1 | -- |

SMTP XOAUTH2 (Microsoft)

| Variable Name | Required | Details | Example | Default |
|-----------------------|----------|-------------------------|---------|---------|
| SMTP_MS_TENANT_ID | True | Microsoft Entra ID (Azure AD) Tenant ID | | -- |
| SMTP_MS_CLIENT_ID | True | Microsoft Entra ID (Azure AD) Client ID | | -- |
| SMTP_MS_CLIENT_SECRET | True* | Microsoft Entra ID (Azure AD) Client Secret (*Required if Client Certificate is unused) | | -- |

Send settings

| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|--------------------------------------------|----------|---------------------------------------------------------------------------------|-------------------------------|---------|
| ALLOWED_EMAIL_DESTINATION_DOMAIN_LIST | False | Domains allowed to send email. Not set if all domains are allowed. | example.com,example.net | -- |
| DISALLOWED_DESTINATION_EMAIL_ADDRESS_REGEX | False | Regular expression for destination email addresses that are not allowed to send | ^[a-zA-Z0-9_.+-]+@example.com | -- |
Expand All @@ -111,6 +120,31 @@ Send settings


### Chat Webhook
| Variable Name | Required | Details | Example | Default |
| Variable Name | Required | Details | Example | Default |
|-------------------|----------|------------------|--------------------------------------------------------------------------------|---------|
| CHAT_WEBHOOK_URL | False | Chat webhook url | https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX | -- |


## Appendix

### Email Configuration Matrix

| Variable / Pattern | SMTP Password | SMTP XOAUTH2 | Amazon SES | Details |
| :--- | :---: | :---: | :---: | :--- |
| **BASE SETTINGS** | | | | |
| `SMTP_METHOD` | `0` | `0` | `1` | 0:SMTP, 1:SES |
| `SMTP_SENDER_EMAIL` | Required | Required | Required | Sender definition |
| `SMTP_SENDER_NAME` | Optional | Optional | Optional | Sender display name |
| **SMTP AUTH** | | | | |
| `SMTP_AUTH_METHOD` | `0` | `1` | - | 0:Password, 1:XOAUTH2 |
| **SMTP SERVER** | | | | |
| `SMTP_SERVER_HOST` | Required | Required | - | e.g. smtp.office365.com |
| `SMTP_SERVER_PORT` | Required | Required | - | e.g. 587 |
| `SMTP_SERVER_ENCRYPTION_METHOD`| Optional | Optional | - | 0:STARTTLS (Default), 1:SSL, 2:None |
| `SMTP_SENDER_PASSWORD` | Required | - | - | For SMTP Auth |
| **MICROSOFT OAUTH** | | | | |
| `SMTP_MS_TENANT_ID` | - | Required | - | |
| `SMTP_MS_CLIENT_ID` | - | Required | - | |
| `SMTP_MS_CLIENT_SECRET` | - | Required | - | |
| **AMAZON SES** | | | | |
| `AWS_SES_REGION_NAME` | - | - | Required | |
14 changes: 14 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import configparser
import os
from email.policy import HTTP, SMTP, SMTPUTF8
from typing import Literal

from dotenv import load_dotenv

Expand Down Expand Up @@ -358,6 +359,19 @@
# Amazon SES
AWS_SES_REGION_NAME = os.environ.get("AWS_SES_REGION_NAME")

# SMTP Auth Method (0:PASSWORD, 1:XOAUTH2)
SMTP_AUTH_METHOD: int = int(os.environ.get("SMTP_AUTH_METHOD", 0))
Comment thread
YoshihitoAso marked this conversation as resolved.
# Token Provider (microsoft fixed)
SMTP_AUTH_PROVIDER: Literal["microsoft"] = "microsoft"

# Microsoft OAuth settings
# - Tenant ID: Microsoft Entra ID (Azure AD) Tenant ID
SMTP_MS_TENANT_ID: str | None = os.environ.get("SMTP_MS_TENANT_ID")
# - Client ID: Microsoft Entra ID (Azure AD) Client ID
SMTP_MS_CLIENT_ID: str | None = os.environ.get("SMTP_MS_CLIENT_ID")
# - Client Secret: Microsoft Entra ID (Azure AD) Client Secret
SMTP_MS_CLIENT_SECRET: str | None = os.environ.get("SMTP_MS_CLIENT_SECRET")

# Send settings
ALLOWED_EMAIL_DESTINATION_DOMAIN_LIST = (
os.environ.get("AUTHORIZED_EMAIL_DESTINATION_DOMAIN_LIST").split(",")
Expand Down
2 changes: 1 addition & 1 deletion app/model/db/messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Mail(Base):
# file name
file_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
# file content
file_content: Mapped[str | None] = mapped_column(
file_content: Mapped[bytes | None] = mapped_column(
LargeBinary().with_variant(LONGBLOB, "mysql"), nullable=True
)

Expand Down
46 changes: 39 additions & 7 deletions app/model/mail/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
SPDX-License-Identifier: Apache-2.0
"""

import base64
import mimetypes
import smtplib
import ssl
Expand All @@ -30,6 +31,8 @@

from app.config import (
AWS_SES_REGION_NAME,
SMTP_AUTH_METHOD,
SMTP_AUTH_PROVIDER,
SMTP_METHOD,
SMTP_POLICY,
SMTP_SENDER_EMAIL,
Expand All @@ -39,6 +42,7 @@
SMTP_SERVER_HOST,
SMTP_SERVER_PORT,
)
from app.model.mail.token_provider import MicrosoftTokenProvider


class File:
Expand All @@ -59,13 +63,20 @@ def __init__(
html_content: str,
file: File | None,
):
if SMTP_SENDER_EMAIL is None:
raise RuntimeError("SMTP sender email is not set.")
self.sender_email = SMTP_SENDER_EMAIL
self.to_email = to_email

if SMTP_METHOD == 0: # SMTP server
if SMTP_SERVER_HOST is None or SMTP_SERVER_PORT is None:
raise RuntimeError("SMTP server host or port is not set.")
self.server_host = SMTP_SERVER_HOST
self.server_port = SMTP_SERVER_PORT
self.sender_password = SMTP_SENDER_PASSWORD
if SMTP_AUTH_METHOD == 0: # PASSWORD
self.sender_password = SMTP_SENDER_PASSWORD
elif SMTP_AUTH_METHOD == 1: # XOAUTH2
pass
elif SMTP_METHOD == 1: # Amazon SES
self.aws_region_name = AWS_SES_REGION_NAME
self.msg = MIMEMultipart("alternative", policy=SMTP_POLICY)
Expand Down Expand Up @@ -94,22 +105,43 @@ def send_mail(self):
if SMTP_METHOD == 0: # SMTP server
# Initialize a new smtp client
if SMTP_SERVER_ENCRYPTION_METHOD == 0: # STARTTLS
smtp_client = smtplib.SMTP(host=self.server_host, port=self.server_port)
smtp_client = smtplib.SMTP(
host=self.server_host, port=int(self.server_port)
)
smtp_client.ehlo()
smtp_client.starttls()
smtp_client.ehlo()
elif SMTP_SERVER_ENCRYPTION_METHOD == 1: # SSL
smtp_client = smtplib.SMTP_SSL(
host=self.server_host,
port=self.server_port,
port=int(self.server_port),
context=ssl.create_default_context(),
)
else: # NO-ENCRYPT
smtp_client = smtplib.SMTP(host=self.server_host, port=self.server_port)

smtp_client = smtplib.SMTP(
host=self.server_host, port=int(self.server_port)
)
# LOGIN
if self.sender_password is not None:
smtp_client.login(self.sender_email, self.sender_password)
if SMTP_AUTH_METHOD == 0: # PASSWORD
if self.sender_password is not None:
smtp_client.login(self.sender_email, self.sender_password)
elif SMTP_AUTH_METHOD == 1: # XOAUTH2
# Get Access Token
match SMTP_AUTH_PROVIDER:
case "microsoft":
token_provider = MicrosoftTokenProvider()
case _:
raise ValueError(
f"Unknown SMTP_AUTH_PROVIDER: {SMTP_AUTH_PROVIDER}"
)
access_token = token_provider.get_access_token()

# Auth
auth_str = (
f"user={self.sender_email}\x01auth=Bearer {access_token}\x01\x01"
)
auth_b64 = base64.b64encode(auth_str.encode("utf-8")).decode("utf-8")
smtp_client.docmd("AUTH", "XOAUTH2 " + auth_b64)

# Send mail
try:
Expand Down
Loading