Different keys for session and csrf checking middleware, some comments in compose yml and .env
This commit is contained in:
parent
edbf0233ba
commit
3b588d2da5
4 changed files with 39 additions and 23 deletions
5
.env
5
.env
|
@ -2,7 +2,10 @@ APP_HOST=0.0.0.0
|
||||||
APP_PORT=8000
|
APP_PORT=8000
|
||||||
|
|
||||||
# Generate a strong secret key
|
# Generate a strong secret key
|
||||||
# On Linux: openssl rand -hex 32
|
#
|
||||||
|
# On Linux: tr -dc A-Za-z0-9_- </dev/urandom | head -c 44
|
||||||
|
# With Python: import secrets; secrets.token_urlsafe(32)
|
||||||
|
#
|
||||||
# If this variable is not set,
|
# If this variable is not set,
|
||||||
# the key is generated automatically
|
# the key is generated automatically
|
||||||
#SECRET_KEY=secret
|
#SECRET_KEY=secret
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import secrets
|
import secrets
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from pydantic import BaseSettings
|
from pydantic import BaseSettings
|
||||||
|
@ -14,12 +15,16 @@ static_dir = str(file_dir.parent / 'static')
|
||||||
# Main configuration
|
# Main configuration
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
secret_key: str = 'secret'
|
session_key: str = 'secret'
|
||||||
|
csrf_key: str = 'secret'
|
||||||
app_host: str = '127.0.0.1'
|
app_host: str = '127.0.0.1'
|
||||||
app_port: int = 8000
|
app_port: int = 8000
|
||||||
|
|
||||||
|
|
||||||
# Instantiate Settings class
|
# Type alias for secret keys settings fields
|
||||||
|
SecretKey = Literal['session_key', 'csrf_key']
|
||||||
|
|
||||||
|
# Settings class instantiating
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
# Jinja templates handler
|
# Jinja templates handler
|
||||||
|
@ -28,26 +33,30 @@ templates = Jinja2Templates(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def secret_key_check() -> None:
|
def secret_key_check(name: SecretKey) -> None:
|
||||||
"""Generates a secret key automatically
|
"""Generates a secret key automatically
|
||||||
if the env var `secret_key` is not set
|
if an environment variable is not set
|
||||||
or contains text `secret`"""
|
or contains text `secret`"""
|
||||||
|
|
||||||
if settings.secret_key == 'secret':
|
settings_dict = settings.dict()
|
||||||
|
if settings_dict.get(name) != 'secret':
|
||||||
|
return
|
||||||
|
|
||||||
key_file = Path('/tmp/secret_key')
|
key_file = Path(f'/tmp/{name}')
|
||||||
|
|
||||||
if key_file.exists():
|
if key_file.exists():
|
||||||
with key_file.open('rt') as f:
|
with key_file.open('rt') as f:
|
||||||
secret_key = f.read()
|
key = f.read()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
secret_key = secrets.token_hex(32)
|
key = secrets.token_hex(32)
|
||||||
with key_file.open('wt') as f:
|
with key_file.open('wt') as f:
|
||||||
f.write(secret_key)
|
f.write(key)
|
||||||
|
|
||||||
settings.secret_key = secret_key
|
settings_dict[name] = key
|
||||||
|
|
||||||
|
|
||||||
# Call the function
|
# Calling the function
|
||||||
secret_key_check()
|
# for session and CSRF keys
|
||||||
|
secret_key_check('session_key')
|
||||||
|
secret_key_check('csrf_key')
|
||||||
|
|
|
@ -42,9 +42,9 @@ for p in paths:
|
||||||
# Add WTForms CSRF protection middlewares
|
# Add WTForms CSRF protection middlewares
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
SessionMiddleware,
|
SessionMiddleware,
|
||||||
secret_key=common.settings.secret_key,
|
secret_key=common.settings.session_key,
|
||||||
)
|
)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CSRFProtectMiddleware,
|
CSRFProtectMiddleware,
|
||||||
csrf_secret=common.settings.secret_key,
|
csrf_secret=common.settings.csrf_key,
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,20 +2,20 @@ version: "3"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
${REPO_NAME_SNAKE}:
|
app:
|
||||||
image: ${REPO_OWNER_LOWER}/${REPO_NAME_SNAKE}:latest
|
image: ${REPO_OWNER_LOWER}/${REPO_NAME_SNAKE}:latest
|
||||||
container_name: ${REPO_NAME_SNAKE}
|
container_name: ${REPO_NAME_SNAKE}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8000"
|
- "8080:8000"
|
||||||
links:
|
links:
|
||||||
- ${REPO_NAME_SNAKE}_db
|
- database
|
||||||
env_file: .env
|
env_file: .env
|
||||||
depends_on:
|
depends_on:
|
||||||
${REPO_NAME_SNAKE}_db:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
${REPO_NAME_SNAKE}_db:
|
database:
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
container_name: ${REPO_NAME_SNAKE}_db
|
container_name: ${REPO_NAME_SNAKE}_db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
@ -29,5 +29,9 @@ services:
|
||||||
timeout: 3s
|
timeout: 3s
|
||||||
retries: 20
|
retries: 20
|
||||||
|
|
||||||
|
# Comment or remove these lines and
|
||||||
|
# edit `volumes` in services->database
|
||||||
|
# if you are going to store
|
||||||
|
# your DB in a directory
|
||||||
volumes:
|
volumes:
|
||||||
db_data:
|
db_data:
|
||||||
|
|
Loading…
Reference in a new issue