diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index be416d2..30ef4c0 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -60,8 +60,8 @@ docmost-cloudron/ ├── start.sh # Startup script ├── nginx.conf # Reverse proxy ├── supervisord.conf # Process management -├── oidc-middleware.js # Authentication (future) -├── package.json # Dependencies +├── env.sample # Configuration template +├── CONFIGURATION.md # User documentation ├── README.md # Documentation └── DEPLOYMENT.md # This file ``` diff --git a/Dockerfile b/Dockerfile index 420fc0d..13ed75d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,6 @@ RUN mkdir -p /tmp/data /app/data && \ # Copy startup scripts and configuration files COPY start.sh /app/code/ -COPY healthcheck.js /app/code/ COPY nginx.conf /etc/nginx/sites-available/default COPY env.sample /app/code/env.sample COPY CONFIGURATION.md /app/code/CONFIGURATION.md @@ -34,7 +33,7 @@ RUN sed -i 's|error_log /var/log/nginx/error.log;|error_log /dev/stderr;|' /etc/ sed -i 's|access_log /var/log/nginx/access.log;|access_log /dev/stdout;|' /etc/nginx/nginx.conf # Make scripts executable -RUN chmod +x /app/code/start.sh /app/code/healthcheck.js +RUN chmod +x /app/code/start.sh # Install supervisord and netcat for process management and connectivity checks RUN apt-get update && \ diff --git a/healthcheck.js b/healthcheck.js deleted file mode 100644 index 864d275..0000000 --- a/healthcheck.js +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env node - -const http = require('http'); - -// Simple health check that attempts to connect to the app -const options = { - hostname: 'localhost', - port: 3001, - path: '/', - method: 'GET', - timeout: 5000 -}; - -const req = http.request(options, (res) => { - console.log(`Health check: ${res.statusCode}`); - if (res.statusCode === 200) { - process.exit(0); - } else { - process.exit(1); - } -}); - -req.on('error', (err) => { - console.error('Health check failed:', err.message); - process.exit(1); -}); - -req.on('timeout', () => { - console.error('Health check timeout'); - req.abort(); - process.exit(1); -}); - -req.end(); \ No newline at end of file diff --git a/oidc-middleware.js b/oidc-middleware.js deleted file mode 100644 index e5ad4ea..0000000 --- a/oidc-middleware.js +++ /dev/null @@ -1,145 +0,0 @@ -const express = require('express'); -const jwt = require('jsonwebtoken'); -const axios = require('axios'); - -class CloudronOIDCMiddleware { - constructor(options = {}) { - this.clientId = process.env.CLOUDRON_OIDC_CLIENT_ID; - this.clientSecret = process.env.CLOUDRON_OIDC_CLIENT_SECRET; - this.issuer = process.env.CLOUDRON_OIDC_ISSUER; - this.redirectUri = process.env.OIDC_REDIRECT_URI; - this.appOrigin = process.env.CLOUDRON_APP_ORIGIN; - } - - // Middleware to check authentication - authenticate() { - return async (req, res, next) => { - try { - // Check for existing session/token - const token = req.headers.authorization?.replace('Bearer ', '') || - req.cookies?.authToken || - req.session?.token; - - if (token && this.verifyToken(token)) { - req.user = jwt.decode(token); - return next(); - } - - // If no valid token, redirect to OIDC login - if (req.path.startsWith('/api/')) { - return res.status(401).json({ error: 'Authentication required' }); - } - - // Redirect to OIDC authorization - const authUrl = this.buildAuthUrl(); - res.redirect(authUrl); - } catch (error) { - console.error('Authentication error:', error); - res.status(500).json({ error: 'Authentication failed' }); - } - }; - } - - // Build OIDC authorization URL - buildAuthUrl() { - const params = new URLSearchParams({ - response_type: 'code', - client_id: this.clientId, - redirect_uri: this.redirectUri, - scope: 'openid profile email', - state: this.generateState() - }); - - return `${this.issuer}/auth?${params.toString()}`; - } - - // Handle OIDC callback - async handleCallback(req, res) { - try { - const { code, state } = req.query; - - if (!code) { - return res.status(400).json({ error: 'Authorization code required' }); - } - - // Exchange code for tokens - const tokenResponse = await this.exchangeCodeForTokens(code); - const { access_token, id_token } = tokenResponse.data; - - // Verify and decode the ID token - const userInfo = jwt.decode(id_token); - - // Create user session - const sessionToken = this.createSessionToken(userInfo); - - // Set cookie and redirect - res.cookie('authToken', sessionToken, { - httpOnly: true, - secure: true, - sameSite: 'lax', - maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days - }); - - res.redirect('/'); - } catch (error) { - console.error('OIDC callback error:', error); - res.status(500).json({ error: 'Authentication callback failed' }); - } - } - - // Exchange authorization code for tokens - async exchangeCodeForTokens(code) { - const params = new URLSearchParams({ - grant_type: 'authorization_code', - code, - redirect_uri: this.redirectUri, - client_id: this.clientId, - client_secret: this.clientSecret - }); - - return axios.post(`${this.issuer}/token`, params, { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - }); - } - - // Create session token - createSessionToken(userInfo) { - const payload = { - sub: userInfo.sub, - email: userInfo.email, - name: userInfo.name, - iat: Math.floor(Date.now() / 1000), - exp: Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60) // 30 days - }; - - return jwt.sign(payload, process.env.APP_SECRET); - } - - // Verify JWT token - verifyToken(token) { - try { - const decoded = jwt.verify(token, process.env.APP_SECRET); - return decoded.exp > Math.floor(Date.now() / 1000); - } catch (error) { - return false; - } - } - - // Generate random state for CSRF protection - generateState() { - return Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15); - } - - // Logout handler - logout() { - return (req, res) => { - res.clearCookie('authToken'); - res.redirect('/'); - }; - } -} - -module.exports = CloudronOIDCMiddleware; \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index f8c65f2..0000000 --- a/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "docmost-cloudron", - "version": "1.0.0", - "description": "Cloudron package for Docmost", - "scripts": { - "start": "./start.sh" - }, - "dependencies": { - "express": "^4.18.2", - "jsonwebtoken": "^9.0.2", - "axios": "^1.6.0", - "cookie-parser": "^1.4.6" - } -} \ No newline at end of file