GHSA-8vh3-g2qg-2h2c (CVSS 9.1, CWE-306): POST /webhooks/nextcloud had no
authentication when WEBHOOK_SECRET was unset (the default). The receiver
trusted the attacker-supplied user.uid and fed it to Qdrant, letting an
unauthenticated network caller delete or re-index any user's vector
embeddings.
Webhooks now require WEBHOOK_SECRET end-to-end:
- app.py: the /webhooks/nextcloud route is only mounted when WEBHOOK_SECRET
is set; otherwise it 404s and a startup warning notes vector sync falls
back to the polling scanner.
- webhook_receiver.py: removed the warn-and-accept fallback. No secret -> 503,
missing/invalid bearer -> 401; the payload is never processed unauthenticated.
- webhook_routes.py / api/webhooks.py: webhook_auth_pair() raises
WebhookSecretNotConfigured instead of returning authMethod="none"; both
registration entry points return a clear 503 so no dead unauthenticated
webhooks are created.
Also expose webhooks availability to the Astrolabe UI via GET /api/v1/status
("webhooks_enabled": bool), set WEBHOOK_SECRET on the docker-compose
semantic-search dev services, and update env.sample + ADR-010 / ADR-018 /
webhook-management-guide docs.
Vector sync still works without a secret via the polling scanner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
260 lines
10 KiB
Plaintext
260 lines
10 KiB
Plaintext
# ============================================
|
|
# DEPLOYMENT MODE SELECTION
|
|
# ============================================
|
|
# Optional: Explicitly declare deployment mode (ADR-021)
|
|
# If not set, mode is auto-detected from other settings
|
|
# Valid values: single_user_basic, multi_user_basic, login_flow
|
|
#
|
|
# Note: `login_flow` is the renamed successor of the former
|
|
# `oauth_single_audience` mode (see ADR-022). The un-augmented OAuth path
|
|
# required unmerged Nextcloud user_oidc patches and is no longer supported.
|
|
# Setting MCP_DEPLOYMENT_MODE=login_flow is sufficient — the Login Flow v2
|
|
# browser-based app-password layer is derived from the mode automatically
|
|
# (the previous ENABLE_LOGIN_FLOW=true env var has been removed).
|
|
#
|
|
# Recommendation: Set this for clarity and to catch configuration errors early
|
|
#MCP_DEPLOYMENT_MODE=login_flow
|
|
|
|
# ============================================
|
|
# COMMON SETTINGS (Required for all modes)
|
|
# ============================================
|
|
# Your Nextcloud instance URL (without trailing slash)
|
|
NEXTCLOUD_HOST=
|
|
|
|
# Fernet key for encrypting refresh tokens / app passwords / browser
|
|
# sessions in SQLite. Required by every docker-compose profile that runs
|
|
# the MCP server (single-user, multi-user-basic, keycloak, login-flow).
|
|
# Generate one with:
|
|
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
# NEVER commit a real key. Each environment (dev / staging / prod) needs
|
|
# its own key.
|
|
TOKEN_ENCRYPTION_KEY=
|
|
|
|
# ============================================
|
|
# SINGLE-USER BASICAUTH MODE
|
|
# ============================================
|
|
# Simplest deployment - one user, credentials in environment
|
|
# Use for: Personal instances, local development, testing
|
|
#
|
|
# Required:
|
|
NEXTCLOUD_USERNAME=
|
|
NEXTCLOUD_PASSWORD=
|
|
#
|
|
# Optional features (semantic search, document processing):
|
|
# See "Optional Features" section below
|
|
|
|
# ============================================
|
|
# MULTI-USER BASICAUTH MODE
|
|
# ============================================
|
|
# Users provide credentials in request headers (pass-through)
|
|
# Use for: Multi-user without OAuth, simple shared deployments
|
|
#
|
|
# Required (sets the deployment mode; the legacy ENABLE_MULTI_USER_BASIC_AUTH
|
|
# env var was removed in the ADR-022 follow-up):
|
|
#MCP_DEPLOYMENT_MODE=multi_user_basic
|
|
#
|
|
# Optional - Background Operations (for semantic search, future features):
|
|
# Enable background token storage using app passwords (via Astrolabe)
|
|
# Required for semantic search in multi-user mode
|
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables this in multi-user modes
|
|
#ENABLE_BACKGROUND_OPERATIONS=true
|
|
#NEXTCLOUD_OIDC_CLIENT_ID=
|
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=
|
|
#TOKEN_ENCRYPTION_KEY=
|
|
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
|
#
|
|
# Optional features (semantic search, document processing):
|
|
# See "Optional Features" section below
|
|
|
|
# ============================================
|
|
# OAUTH SINGLE-AUDIENCE MODE (Recommended)
|
|
# ============================================
|
|
# Multi-user OAuth with single-audience tokens
|
|
# Use for: Multi-user production deployments, enhanced security
|
|
# Tokens work for both MCP server and Nextcloud APIs (pass-through)
|
|
#
|
|
# Required: None (uses Dynamic Client Registration if credentials not provided)
|
|
#
|
|
# Optional - Pre-registered OAuth Client:
|
|
# If you pre-register the client instead of using DCR:
|
|
#NEXTCLOUD_OIDC_CLIENT_ID=
|
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=
|
|
#
|
|
# Optional - Background Operations (for semantic search, future features):
|
|
# Enable refresh token storage for offline access
|
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables this in multi-user modes
|
|
#ENABLE_BACKGROUND_OPERATIONS=true
|
|
#TOKEN_ENCRYPTION_KEY=
|
|
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
|
#
|
|
# Optional - Custom OIDC Discovery:
|
|
# Auto-detected from NEXTCLOUD_HOST if not set
|
|
#NEXTCLOUD_OIDC_DISCOVERY_URL=
|
|
#
|
|
# Optional - Custom Scopes:
|
|
# Default: openid profile email offline_access notes:* calendar:* contacts:* tables:* webdav:* deck:* cookbook:*
|
|
#NEXTCLOUD_OIDC_SCOPES=openid profile email notes:* calendar:*
|
|
#
|
|
# MCP Server URL (for OAuth redirects):
|
|
#NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
|
#
|
|
# Optional features (semantic search, document processing):
|
|
# See "Optional Features" section below
|
|
|
|
# ============================================
|
|
# OAUTH CLIENT ALLOWLISTS (OAuth modes)
|
|
# ============================================
|
|
# Both env vars are FAIL-CLOSED: if unset/empty, the corresponding auth route
|
|
# rejects every request. There are no built-in defaults.
|
|
#
|
|
# Note: ALLOWED_MCP_CLIENTS and ALLOWED_MGMT_CLIENT are currently separate to
|
|
# keep the MCP-route and management-API auth surfaces independent. They may be
|
|
# consolidated into a single env var later.
|
|
|
|
# ===== ALLOWED_MCP_CLIENTS =====
|
|
# Clients allowed to use the OAuth AS proxy (/oauth/authorize, /oauth/token).
|
|
# Comma-separated. Each entry is either:
|
|
# - "client_id" → loopback redirect URIs (http://localhost:*, http://127.0.0.1:*)
|
|
# - "client_id|https://app/cb" → bind to a specific HTTPS callback
|
|
# HTTP redirect URIs are rejected unless the host is loopback (localhost/127.0.0.1/::1).
|
|
#ALLOWED_MCP_CLIENTS=claude-desktop, zed-editor, cloud-app|https://cloud.example.com/cb
|
|
|
|
# ===== ALLOWED_MGMT_CLIENT =====
|
|
# OIDC client_ids whose tokens are accepted by the management API
|
|
# (/api/management/*). Comma-separated. The token's `client_id` claim must
|
|
# match one of these entries. Typical value: the Astrolabe NC PHP app's
|
|
# OAuth client_id (ADR-018).
|
|
#ALLOWED_MGMT_CLIENT=astrolabe
|
|
|
|
# ============================================
|
|
# OPTIONAL FEATURES (All Deployment Modes)
|
|
# ============================================
|
|
|
|
# ===== SEMANTIC SEARCH =====
|
|
# AI-powered semantic search across Nextcloud content
|
|
# Requires: Qdrant vector database + embedding provider (Ollama, Bedrock, or Simple fallback)
|
|
#
|
|
# Enable semantic search:
|
|
#ENABLE_SEMANTIC_SEARCH=true
|
|
#
|
|
# Note for Multi-User Modes:
|
|
# ENABLE_SEMANTIC_SEARCH automatically enables background operations when needed
|
|
# No need to set ENABLE_BACKGROUND_OPERATIONS separately
|
|
# The server will automatically request refresh tokens and store them encrypted
|
|
#
|
|
# Vector Database - Choose ONE mode:
|
|
# 1. In-memory (default): Set neither QDRANT_URL nor QDRANT_LOCATION
|
|
# 2. Persistent local: Set QDRANT_LOCATION=/path/to/data
|
|
# 3. Network: Set QDRANT_URL=http://qdrant:6333
|
|
#
|
|
#QDRANT_URL=http://qdrant:6333
|
|
#QDRANT_LOCATION=:memory:
|
|
#QDRANT_API_KEY=
|
|
#QDRANT_COLLECTION=nextcloud_content
|
|
#
|
|
# Embedding Provider - Choose ONE:
|
|
# 1. Ollama (recommended for local deployment):
|
|
#OLLAMA_BASE_URL=http://ollama:11434
|
|
#OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
|
#OLLAMA_VERIFY_SSL=true
|
|
#
|
|
# 2. Amazon Bedrock (for AWS deployments):
|
|
#AWS_REGION=us-east-1
|
|
#BEDROCK_EMBEDDING_MODEL=amazon.titan-embed-text-v2:0
|
|
# Optional: AWS credentials (uses credential chain if not set)
|
|
#AWS_ACCESS_KEY_ID=
|
|
#AWS_SECRET_ACCESS_KEY=
|
|
#
|
|
# 3. Simple (automatic fallback, no configuration needed)
|
|
# Uses basic in-memory embeddings if no provider configured
|
|
#
|
|
# Document Chunking:
|
|
# Configure how documents are split before embedding (units are characters)
|
|
#DOCUMENT_CHUNK_SIZE=2048
|
|
#DOCUMENT_CHUNK_OVERLAP=200
|
|
# Page-aware chunking for PDFs: split on page boundaries first so no chunk spans
|
|
# a page (exact page numbers, clean snippets, ~1 chunk/page when chunk size >=
|
|
# the largest page). Set false to use the legacy char-based path. Default: true
|
|
#DOCUMENT_CHUNK_PAGE_AWARE=true
|
|
|
|
# ===== SEMANTIC SEARCH TUNING =====
|
|
# Advanced parameters for vector sync background operations
|
|
# Only modify if you understand the implications
|
|
#
|
|
# Document scan interval in seconds (default: 300 = 5 minutes)
|
|
#VECTOR_SYNC_SCAN_INTERVAL=300
|
|
#
|
|
# Concurrent indexing workers (default: 3)
|
|
#VECTOR_SYNC_PROCESSOR_WORKERS=3
|
|
#
|
|
# Max queued documents (default: 10000)
|
|
#VECTOR_SYNC_QUEUE_MAX_SIZE=10000
|
|
#
|
|
# Webhook receiver authentication (REQUIRED for webhook-driven sync).
|
|
# Security (GHSA-8vh3-g2qg-2h2c): the /webhooks/nextcloud receiver trusts the
|
|
# user id in the payload and feeds it to Qdrant, so it must be authenticated.
|
|
# When WEBHOOK_SECRET is unset the route is NOT mounted and vector sync falls
|
|
# back to the polling scanner. When set, the receiver requires
|
|
# `Authorization: Bearer <secret>` and webhook registration injects it.
|
|
# Generate one with: python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
#WEBHOOK_SECRET=
|
|
|
|
# ===== DOCUMENT PROCESSING =====
|
|
# Extract text from PDFs, images, DOCX, etc. for semantic search
|
|
# Disabled by default
|
|
#
|
|
#ENABLE_DOCUMENT_PROCESSING=false
|
|
#DOCUMENT_PROCESSOR=unstructured
|
|
#
|
|
# Unstructured.io Processor (recommended):
|
|
#ENABLE_UNSTRUCTURED=false
|
|
#UNSTRUCTURED_API_URL=http://unstructured:8000
|
|
#UNSTRUCTURED_TIMEOUT=120
|
|
#UNSTRUCTURED_STRATEGY=auto
|
|
#UNSTRUCTURED_LANGUAGES=eng,deu
|
|
#PROGRESS_INTERVAL=10
|
|
#
|
|
# Tesseract OCR (lightweight, images only):
|
|
#ENABLE_TESSERACT=false
|
|
#TESSERACT_CMD=/usr/bin/tesseract
|
|
#TESSERACT_LANG=eng
|
|
#
|
|
# Custom Processor (your own API):
|
|
#ENABLE_CUSTOM_PROCESSOR=false
|
|
#CUSTOM_PROCESSOR_NAME=my_ocr
|
|
#CUSTOM_PROCESSOR_URL=http://localhost:9000/process
|
|
#CUSTOM_PROCESSOR_API_KEY=
|
|
#CUSTOM_PROCESSOR_TIMEOUT=60
|
|
#CUSTOM_PROCESSOR_TYPES=application/pdf,image/jpeg,image/png
|
|
|
|
# ===== SSL/TLS =====
|
|
# For Nextcloud behind reverse proxies with self-signed or private CA certificates
|
|
#
|
|
# Disable TLS certificate verification (insecure, development only):
|
|
#NEXTCLOUD_VERIFY_SSL=false
|
|
#
|
|
# Use a custom CA bundle (path to PEM file):
|
|
#NEXTCLOUD_CA_BUNDLE=/etc/ssl/certs/my-ca.pem
|
|
#
|
|
# Docker example: mount the CA bundle as a volume
|
|
# docker run -v /path/to/ca.pem:/etc/ssl/certs/my-ca.pem:ro \
|
|
# -e NEXTCLOUD_CA_BUNDLE=/etc/ssl/certs/my-ca.pem ...
|
|
|
|
# ===== SECURITY & ADVANCED =====
|
|
# Cookie security (browser UI)
|
|
# Auto-detects from NEXTCLOUD_HOST protocol if not set
|
|
#COOKIE_SECURE=true
|
|
|
|
# ============================================
|
|
# DEPRECATED VARIABLES (Backward Compatibility)
|
|
# ============================================
|
|
# These variables still work but will be removed in v1.0.0
|
|
# Please migrate to new names:
|
|
#
|
|
# Old Name → New Name
|
|
# VECTOR_SYNC_ENABLED → ENABLE_SEMANTIC_SEARCH
|
|
# ENABLE_OFFLINE_ACCESS → ENABLE_BACKGROUND_OPERATIONS
|
|
#
|
|
# Migration is optional - both old and new names work
|
|
# Deprecation warnings will be logged when old names are used
|