diff --git a/README.md b/README.md new file mode 100644 index 0000000..f559c94 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# ComfyUI Basic Auth + +A simple authentication middleware for ComfyUI that adds basic HTTP authentication to protect your ComfyUI instance. + +## Features + +- Basic HTTP Authentication protection for ComfyUI +- Simple username/password configuration +- Lightweight and easy to set up +- Compatible with all ComfyUI versions + +## Installation + +1. Navigate to your ComfyUI custom nodes folder: +```bash +cd ComfyUI/custom_nodes/ +``` + +2. Clone this repository: +```bash +git clone https://github.com/fofr/comfyui-basic-auth +``` + +## Configuration + +1. Create a `.env` file in the node directory: +```bash +COMFY_AUTH_USERNAME=your_username +COMFY_AUTH_PASSWORD=your_password +``` + +2. Restart ComfyUI for the changes to take effect. + +## Usage + +The authentication will automatically be active once the node is installed and configured. When accessing ComfyUI, you will be prompted for the username and password you specified in the `.env` file. + +## Security Note + +Basic authentication sends credentials encoded (not encrypted) in the HTTP header. While this provides a basic level of protection, it's recommended to: + +- Use strong passwords +- Access ComfyUI through HTTPS if exposed to the internet +- Consider additional security measures for production environments diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..5812c4a --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +from .basic_auth import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/basic_auth.py b/basic_auth.py new file mode 100644 index 0000000..8715d0a --- /dev/null +++ b/basic_auth.py @@ -0,0 +1,80 @@ +import os +import base64 +from aiohttp import web + +class BasicAuthMiddleware: + def __init__(self): + self.username = os.getenv('COMFYUI_USERNAME', '') + self.password = os.getenv('COMFYUI_PASSWORD', '') + self.enabled = bool(self.username and self.password) + + @web.middleware + async def handle(self, request, handler): + if not self.enabled: + return await handler(request) + + # Skip auth for WebSocket connections + if request.path == '/ws': + return await handler(request) + + # Get Authorization header + auth_header = request.headers.get('Authorization') + + if not auth_header: + return web.Response( + status=401, + headers={'WWW-Authenticate': 'Basic realm="ComfyUI Server"'} + ) + + try: + auth_type, auth_string = auth_header.split(' ', 1) + if auth_type.lower() != 'basic': + raise ValueError('Invalid auth type') + + decoded = base64.b64decode(auth_string).decode('utf-8') + provided_username, provided_password = decoded.split(':', 1) + + if provided_username == self.username and provided_password == self.password: + return await handler(request) + + except Exception: + pass + + return web.Response( + status=401, + headers={'WWW-Authenticate': 'Basic realm="ComfyUI Server"'} + ) + +class BasicAuthSetup: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "enabled": ("BOOLEAN", {"default": True}), + }, + } + + RETURN_TYPES = ("BASIC_AUTH",) + FUNCTION = "setup_auth" + CATEGORY = "utils" + OUTPUT_NODE = True + + def setup_auth(self, enabled): + return ({"enabled": enabled},) + +NODE_CLASS_MAPPINGS = { + "BasicAuthSetup": BasicAuthSetup +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "BasicAuthSetup": "Basic Auth Setup" +} + +# Register the middleware +try: + import server + app = server.PromptServer.instance.app + middleware = BasicAuthMiddleware() + app.middlewares.insert(0, middleware.handle) +except Exception as e: + print(f"Failed to register basic auth middleware: {e}")