refactor: v0.5.3 - Zugangsdaten in .env auslagern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7e441a8ade
commit
ee361acf33
7
.env.example
Normal file
7
.env.example
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
AUTH_SECRET_KEY=change-this-secret-key-32bytes!!
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=465
|
||||
SMTP_USER=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_FROM=MeshDD-Bot <noreply@example.com>
|
||||
SMTP_APP_URL=http://localhost:8080
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## [0.5.3] - 2026-02-16
|
||||
### Changed
|
||||
- Zugangsdaten (AUTH_SECRET_KEY, SMTP-*) aus config.yaml in .env-Datei ausgelagert
|
||||
- Neuer `config.env()` Helper fuer Umgebungsvariablen
|
||||
- `.env.example` als Vorlage hinzugefuegt
|
||||
- E-Mail-Versand in gemeinsame `_send_email()` Hilfsfunktion refaktoriert
|
||||
|
||||
## [0.5.2] - 2026-02-16
|
||||
### Fixed
|
||||
- SMTP-Versand: TLS (Port 465) und STARTTLS (Port 587) automatisch anhand des Ports
|
||||
|
|
|
|||
11
config.yaml
11
config.yaml
|
|
@ -1,4 +1,4 @@
|
|||
version: "0.5.1"
|
||||
version: "0.5.3"
|
||||
|
||||
bot:
|
||||
name: "MeshDD-Bot"
|
||||
|
|
@ -16,13 +16,4 @@ database:
|
|||
path: "meshdd.db"
|
||||
|
||||
auth:
|
||||
secret_key: "change-this-secret-key-32bytes!!"
|
||||
session_max_age: 86400
|
||||
|
||||
smtp:
|
||||
host: ""
|
||||
port: 587
|
||||
user: ""
|
||||
password: ""
|
||||
from: "MeshDD-Bot <noreply@example.com>"
|
||||
app_url: "http://localhost:8080"
|
||||
|
|
|
|||
108
meshbot/auth.py
108
meshbot/auth.py
|
|
@ -27,7 +27,7 @@ def check_password(password: str, hashed: str) -> bool:
|
|||
# ── Session setup ────────────────────────────────────
|
||||
|
||||
def setup_session(app: web.Application):
|
||||
secret_key = config.get("auth.secret_key", "change-this-secret-key-32bytes!!")
|
||||
secret_key = config.env("AUTH_SECRET_KEY", "change-this-secret-key-32bytes!!")
|
||||
# EncryptedCookieStorage accepts a Fernet object directly
|
||||
key_bytes = secret_key.encode("utf-8")[:32].ljust(32, b"\0")
|
||||
fernet_key = Fernet(base64.urlsafe_b64encode(key_bytes))
|
||||
|
|
@ -87,8 +87,44 @@ def require_admin_api(request: web.Request):
|
|||
|
||||
# ── Email sending ────────────────────────────────────
|
||||
|
||||
async def _send_email(db, recipient: str, subject: str, html_body: str):
|
||||
smtp_host = config.env("SMTP_HOST")
|
||||
if not smtp_host:
|
||||
logger.info("SMTP not configured - email to %s not sent", recipient)
|
||||
await db.log_email(recipient, subject, "console", "SMTP not configured")
|
||||
return
|
||||
|
||||
try:
|
||||
import aiosmtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Subject"] = subject
|
||||
msg["From"] = config.env("SMTP_FROM", "MeshDD-Bot <noreply@example.com>")
|
||||
msg["To"] = recipient
|
||||
msg.attach(MIMEText(html_body, "html"))
|
||||
|
||||
smtp_port = int(config.env("SMTP_PORT", "465"))
|
||||
use_tls = smtp_port == 465
|
||||
await aiosmtplib.send(
|
||||
msg,
|
||||
hostname=smtp_host,
|
||||
port=smtp_port,
|
||||
username=config.env("SMTP_USER"),
|
||||
password=config.env("SMTP_PASSWORD"),
|
||||
use_tls=use_tls,
|
||||
start_tls=not use_tls,
|
||||
)
|
||||
await db.log_email(recipient, subject, "sent")
|
||||
logger.info("Email sent to %s: %s", recipient, subject)
|
||||
except Exception as e:
|
||||
logger.error("Failed to send email to %s: %s", recipient, e)
|
||||
await db.log_email(recipient, subject, "error", str(e))
|
||||
|
||||
|
||||
async def send_verification_email(db, email: str, token: str):
|
||||
app_url = config.get("smtp.app_url", "http://localhost:8080")
|
||||
app_url = config.env("SMTP_APP_URL", "http://localhost:8080")
|
||||
verify_url = f"{app_url}/auth/verify?token={token}"
|
||||
subject = "MeshDD-Bot - E-Mail verifizieren"
|
||||
html_body = f"""<html><body>
|
||||
|
|
@ -98,43 +134,14 @@ async def send_verification_email(db, email: str, token: str):
|
|||
<p>Der Link ist 24 Stunden gueltig.</p>
|
||||
</body></html>"""
|
||||
|
||||
smtp_host = config.get("smtp.host", "")
|
||||
if not smtp_host:
|
||||
if not config.env("SMTP_HOST"):
|
||||
logger.info("SMTP not configured - verification link: %s", verify_url)
|
||||
await db.log_email(email, subject, "console", "SMTP not configured")
|
||||
return
|
||||
|
||||
try:
|
||||
import aiosmtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Subject"] = subject
|
||||
msg["From"] = config.get("smtp.from", "MeshDD-Bot <noreply@example.com>")
|
||||
msg["To"] = email
|
||||
msg.attach(MIMEText(html_body, "html"))
|
||||
|
||||
smtp_port = config.get("smtp.port", 587)
|
||||
use_tls = smtp_port == 465
|
||||
await aiosmtplib.send(
|
||||
msg,
|
||||
hostname=smtp_host,
|
||||
port=smtp_port,
|
||||
username=config.get("smtp.user", ""),
|
||||
password=config.get("smtp.password", ""),
|
||||
use_tls=use_tls,
|
||||
start_tls=not use_tls,
|
||||
)
|
||||
await db.log_email(email, subject, "sent")
|
||||
logger.info("Verification email sent to %s", email)
|
||||
except Exception as e:
|
||||
logger.error("Failed to send email to %s: %s", email, e)
|
||||
await db.log_email(email, subject, "error", str(e))
|
||||
await _send_email(db, email, subject, html_body)
|
||||
|
||||
|
||||
async def send_reset_email(db, email: str, token: str):
|
||||
app_url = config.get("smtp.app_url", "http://localhost:8080")
|
||||
app_url = config.env("SMTP_APP_URL", "http://localhost:8080")
|
||||
reset_url = f"{app_url}/auth/reset-password?token={token}"
|
||||
subject = "MeshDD-Bot - Passwort zuruecksetzen"
|
||||
html_body = f"""<html><body>
|
||||
|
|
@ -144,39 +151,10 @@ async def send_reset_email(db, email: str, token: str):
|
|||
<p>Der Link ist 24 Stunden gueltig.</p>
|
||||
</body></html>"""
|
||||
|
||||
smtp_host = config.get("smtp.host", "")
|
||||
if not smtp_host:
|
||||
if not config.env("SMTP_HOST"):
|
||||
logger.info("SMTP not configured - reset link: %s", reset_url)
|
||||
await db.log_email(email, subject, "console", "SMTP not configured")
|
||||
return
|
||||
|
||||
try:
|
||||
import aiosmtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Subject"] = subject
|
||||
msg["From"] = config.get("smtp.from", "MeshDD-Bot <noreply@example.com>")
|
||||
msg["To"] = email
|
||||
msg.attach(MIMEText(html_body, "html"))
|
||||
|
||||
smtp_port = config.get("smtp.port", 587)
|
||||
use_tls = smtp_port == 465
|
||||
await aiosmtplib.send(
|
||||
msg,
|
||||
hostname=smtp_host,
|
||||
port=smtp_port,
|
||||
username=config.get("smtp.user", ""),
|
||||
password=config.get("smtp.password", ""),
|
||||
use_tls=use_tls,
|
||||
start_tls=not use_tls,
|
||||
)
|
||||
await db.log_email(email, subject, "sent")
|
||||
logger.info("Reset email sent to %s", email)
|
||||
except Exception as e:
|
||||
logger.error("Failed to send reset email to %s: %s", email, e)
|
||||
await db.log_email(email, subject, "error", str(e))
|
||||
await _send_email(db, email, subject, html_body)
|
||||
|
||||
|
||||
# ── Auth route handlers ──────────────────────────────
|
||||
|
|
|
|||
|
|
@ -7,12 +7,26 @@ import yaml
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
CONFIG_PATH = os.environ.get("CONFIG_PATH", os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.yaml"))
|
||||
ENV_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
|
||||
|
||||
_config = {}
|
||||
_mtime = 0.0
|
||||
_callbacks = []
|
||||
|
||||
|
||||
def _load_env():
|
||||
if not os.path.exists(ENV_PATH):
|
||||
return
|
||||
with open(ENV_PATH, "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
os.environ.setdefault(key.strip(), value.strip())
|
||||
logger.info("Environment loaded from %s", ENV_PATH)
|
||||
|
||||
|
||||
def _load():
|
||||
global _config, _mtime
|
||||
with open(CONFIG_PATH, "r") as f:
|
||||
|
|
@ -61,5 +75,10 @@ def get(key: str, default=None):
|
|||
return val
|
||||
|
||||
|
||||
def env(key: str, default: str = "") -> str:
|
||||
return os.environ.get(key, default)
|
||||
|
||||
|
||||
# Load on import
|
||||
_load_env()
|
||||
_load()
|
||||
|
|
|
|||
Loading…
Reference in a new issue