Remove obsolete files and clean up repository structure
Removed unused files: - oidc-middleware.js (unused OIDC authentication code) - package.json (dependencies for unused middleware) - healthcheck.js (Cloudron uses manifest healthCheckPath instead) Updated Dockerfile to remove healthcheck.js references. Updated DEPLOYMENT.md to reflect current repository structure. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
@@ -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 && \
|
||||
|
@@ -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();
|
@@ -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;
|
14
package.json
14
package.json
@@ -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"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user