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
|
├── start.sh # Startup script
|
||||||
├── nginx.conf # Reverse proxy
|
├── nginx.conf # Reverse proxy
|
||||||
├── supervisord.conf # Process management
|
├── supervisord.conf # Process management
|
||||||
├── oidc-middleware.js # Authentication (future)
|
├── env.sample # Configuration template
|
||||||
├── package.json # Dependencies
|
├── CONFIGURATION.md # User documentation
|
||||||
├── README.md # Documentation
|
├── README.md # Documentation
|
||||||
└── DEPLOYMENT.md # This file
|
└── DEPLOYMENT.md # This file
|
||||||
```
|
```
|
||||||
|
@@ -24,7 +24,6 @@ RUN mkdir -p /tmp/data /app/data && \
|
|||||||
|
|
||||||
# Copy startup scripts and configuration files
|
# Copy startup scripts and configuration files
|
||||||
COPY start.sh /app/code/
|
COPY start.sh /app/code/
|
||||||
COPY healthcheck.js /app/code/
|
|
||||||
COPY nginx.conf /etc/nginx/sites-available/default
|
COPY nginx.conf /etc/nginx/sites-available/default
|
||||||
COPY env.sample /app/code/env.sample
|
COPY env.sample /app/code/env.sample
|
||||||
COPY CONFIGURATION.md /app/code/CONFIGURATION.md
|
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
|
sed -i 's|access_log /var/log/nginx/access.log;|access_log /dev/stdout;|' /etc/nginx/nginx.conf
|
||||||
|
|
||||||
# Make scripts executable
|
# 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
|
# Install supervisord and netcat for process management and connectivity checks
|
||||||
RUN apt-get update && \
|
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