diff --git a/backend/config/__init__.py b/backend/config/__init__.py index 0325aebd6..0aed239ee 100644 --- a/backend/config/__init__.py +++ b/backend/config/__init__.py @@ -1,4 +1,5 @@ import os +import secrets from dotenv import load_dotenv load_dotenv() @@ -48,5 +49,8 @@ STEAMGRIDDB_API_KEY = os.environ.get("STEAMGRIDDB_API_KEY", "") # DB DRIVERS ROMM_DB_DRIVER = os.environ.get("ROMM_DB_DRIVER", "sqlite") -# SECRETS -SECRET_KEY = "9b9da8bfd88822ad708530bb36e61d02c130a74de7a8e84d5f456bf6fee5c518" +# AUTH +ROMM_AUTH_ENABLED = os.environ.get("ROMM_AUTH_ENABLED", "false") == "true" +ROMM_AUTH_USERNAME = os.environ.get("ROMM_AUTH_USERNAME", "admin") +ROMM_AUTH_PASSWORD = os.environ.get("ROMM_AUTH_PASSWORD", "admin") +ROMM_AUTH_SECRET_KEY = os.environ.get("ROMM_AUTH_SECRET_KEY", secrets.token_hex(32)) diff --git a/backend/endpoints/oauth.py b/backend/endpoints/oauth.py index a351bec4c..07b7f5bad 100644 --- a/backend/endpoints/oauth.py +++ b/backend/endpoints/oauth.py @@ -86,7 +86,10 @@ async def oauth(form_data: Annotated[OAuth2RequestForm, Depends()]): # TODO: Authentication via client_id/client_secret # Should also support specifying scopes elif form_data.grant_type == "client_credentials": - pass + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Client credentials are not yet supported", + ) else: # All other grant types are unsupported diff --git a/backend/main.py b/backend/main.py index 40e7f8dae..096e3b5db 100644 --- a/backend/main.py +++ b/backend/main.py @@ -7,7 +7,7 @@ from fastapi_pagination import add_pagination from starlette.middleware.authentication import AuthenticationMiddleware from starlette.middleware.sessions import SessionMiddleware -from config import DEV_PORT, DEV_HOST, SECRET_KEY +from config import DEV_PORT, DEV_HOST, ROMM_AUTH_SECRET_KEY from endpoints import search, platform, rom, identity, oauth, scan # noqa from utils.socket import socket_app from utils.auth import BasicAuthBackend, CustomCSRFMiddleware @@ -29,13 +29,13 @@ app.add_middleware( ) app.add_middleware( SessionMiddleware, - secret_key=SECRET_KEY, + secret_key=ROMM_AUTH_SECRET_KEY, same_site="strict", - https_only=False, # TODO: Set to True in production + https_only=False, ) app.add_middleware( CustomCSRFMiddleware, - secret=SECRET_KEY, + secret=ROMM_AUTH_SECRET_KEY, exempt_urls=[re.compile(r"^/oauth/.*"), re.compile(r"^/ws")], ) diff --git a/backend/utils/auth.py b/backend/utils/auth.py index 1e22fbd9a..cd885a6bb 100644 --- a/backend/utils/auth.py +++ b/backend/utils/auth.py @@ -12,7 +12,7 @@ from starlette_csrf import CSRFMiddleware from starlette.types import Receive, Scope, Send from handler import dbh -from config import SECRET_KEY +from config import ROMM_AUTH_SECRET_KEY from utils.cache import cache ALGORITHM = "HS256" @@ -51,7 +51,7 @@ def create_oauth_token(data: dict, expires_delta: timedelta | None = None): to_encode.update({"exp": expire}) - return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return jwt.encode(to_encode, ROMM_AUTH_SECRET_KEY, algorithm=ALGORITHM) credentials_exception = HTTPException( @@ -63,7 +63,7 @@ credentials_exception = HTTPException( async def get_current_active_user_from_token(token: str): try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + payload = jwt.decode(token, ROMM_AUTH_SECRET_KEY, algorithms=[ALGORITHM]) except (JWTError): raise credentials_exception diff --git a/env.template b/env.template index d96c71b7e..72da74ac6 100644 --- a/env.template +++ b/env.template @@ -1,11 +1,11 @@ ROMM_BASE_PATH=/path/to/romm_mock VITE_BACKEND_DEV_PORT=5000 -# IGDB auth +# IGDB credentials CLIENT_ID= CLIENT_SECRET= -# STEAMGRIDDB API KEY +# STEAMGRIDDB API key STEAMGRIDDB_API_KEY= # Database driver (mariadb, sqlite) @@ -22,3 +22,9 @@ DB_ROOT_PASSWD= # Redis config (optional) REDIS_HOST=127.0.0.1 REDIS_PORT=6379 + +# Authentication +ROMM_AUTH_ENABLED=true +ROMM_AUTH_USERNAME=admin +ROMM_AUTH_PASSWORD=admin +ROMM_AUTH_SECRET_KEY= diff --git a/examples/docker-compose.example.yml b/examples/docker-compose.example.yml index b0d3c7c3e..a6e7d39eb 100644 --- a/examples/docker-compose.example.yml +++ b/examples/docker-compose.example.yml @@ -6,17 +6,21 @@ services: image: zurdi15/romm:latest container_name: romm environment: - - ROMM_DB_DRIVER=mariadb # This variable can be set as: mariadb | sqlite. If it is not defined, sqlite will be the database by default - - DB_HOST=mariadb # [Optional] Only needed if ROMM_DB_DRIVER=mariadb - - DB_PORT=3306 # [Optional] Only needed if ROMM_DB_DRIVER=mariadb - - DB_USER=romm-user # [Optional] Only needed if ROMM_DB_DRIVER=mariadb - - DB_NAME=romm # [Optional] Only needed if ROMM_DB_DRIVER=mariadb. Can be optionally changed, and should match the MYSQL_DATABASE value in the mariadb container. - - DB_PASSWD= # [Optional] Only needed if ROMM_DB_DRIVER=mariadb - - REDIS_HOST=redis # [Optional][Experimental] Redis enables workers to run long tasks, like full library rescans, without having to wait on the main thread. Can be used with an already existent redis container - - REDIS_PORT=6379 # [Optional][Experimental] - - CLIENT_ID= - - CLIENT_SECRET= - - STEAMGRIDDB_API_KEY= # [Optional] + - ROMM_DB_DRIVER=mariadb # mariadb | sqlite (defaults to sqlite) + - DB_HOST=mariadb # [Optional] + - DB_PORT=3306 # [Optional] + - DB_USER=romm-user # [Optional] + - DB_NAME=romm # [Optional] Should match the MYSQL_DATABASE value in the mariadb container + - DB_PASSWD= # [Optional] + - REDIS_HOST=redis # [Optional] Enables running long tasks (full rescans) in the background + - REDIS_PORT=6379 # [Optional] + - CLIENT_ID= # [Optional] Required to fetch metadata from IGDB + - CLIENT_SECRET= # [Optional] + - STEAMGRIDDB_API_KEY= # [Optional] Only needed if you want to use SteamGridDB as a source for covers + - ROMM_AUTH_ENABLED=true # [Optional] Will enable user management and require authentication to access the interface (default to false) + - ROMM_AUTH_USERNAME=admin # [Optional] Username for default admin user + - ROMM_AUTH_PASSWORD= # [Optional] Password for default admin user (defaults to admin) + - ROMM_AUTH_SECRET_KEY= # [Optional] Used to encrypt user passwords, generate one with `openssl rand -hex 32` volumes: - '/path/to/library:/romm/library' - '/path/to/resources:/romm/resources' # [Optional] Path where roms metadata (covers) are stored @@ -44,7 +48,7 @@ services: - 3306:3306 restart: "unless-stopped" - # [Optional][Experimental] + # [Optional] Experimental support for Redis backend redis: image: redis:alpine container_name: redis