75 lines
3.1 KiB
JavaScript
75 lines
3.1 KiB
JavaScript
const express = require('express');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { requireAuth, requireAdmin } = require('../middleware/requireAuth');
|
|
|
|
const router = express.Router();
|
|
|
|
let pkg;
|
|
try { pkg = require('../package.json'); } catch { pkg = { version: '0.1.0' }; }
|
|
|
|
// Explicit allowlist of allowed files with resolved paths
|
|
const ALLOWED_FILES = {
|
|
'FUTURE.md': path.resolve(__dirname, '..', 'FUTURE.md'),
|
|
'DEVELOPMENT_LOG.md': path.resolve(__dirname, '..', 'DEVELOPMENT_LOG.md'),
|
|
};
|
|
|
|
/**
|
|
* Redact sensitive information from file content
|
|
* @param {string} content - The content to redact
|
|
* @returns {string} - The redacted content
|
|
*/
|
|
function redactSensitiveContent(content) {
|
|
if (!content) return content;
|
|
|
|
return content
|
|
// Redact internal IPs
|
|
.replace(/\b192\.168\.[0-9]{1,3}\.[0-9]{1,3}\b/g, '[REDACTED]')
|
|
.replace(/\b10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b/g, '[REDACTED]')
|
|
.replace(/\b172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3}\b/g, '[REDACTED]')
|
|
// Redact passwords, api_keys, secrets
|
|
.replace(/(password|api_key|secret)\s*=\s*[^\\\s]+/gi, '$1=[REDACTED]')
|
|
// Redact file paths (Unix-style: /home/, /etc/, /var/, /tmp/, /usr/, /opt/)
|
|
.replace(/\/(?:home|etc|var|tmp|usr|opt)\/[^\s"',;)]+/gi, '[REDACTED]')
|
|
// Redact Windows-style paths
|
|
.replace(/[A-Z]:\\(?:Users|Windows|Program Files)[\\\/][^\s"',;)]+/gi, '[REDACTED]')
|
|
// Redact connection strings
|
|
.replace(/(?:mongodb|postgres|mysql|redis|amqp):\/\/[^\s"']+/gi, '[REDACTED]')
|
|
// Redact env var values (KEY=value patterns where key contains secret/pass/key/token)
|
|
.replace(/([A-Z_]*(?:SECRET|KEY|TOKEN|PASS|PASSWORD|CREDENTIAL|AUTH)[A-Z_]*)\s*=\s*[^\s"']+/gi, '$1=[REDACTED]')
|
|
// Redact internal URLs
|
|
.replace(/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::\d+)?[^\s"']*/gi, '[REDACTED_URL]')
|
|
// Redact lines with security-sensitive patterns (CVE IDs, exploit details, attack vectors)
|
|
.replace(/\bCVE-\d{4}-\d+\b/gi, '[REDACTED]')
|
|
.replace(/\b(?:sql\s*injection|xss|csrf|csrf\s*token|race\s*condition|buffer\s*overflow|privilege\s*escalation)\b[^.]*\./gi, '[REDACTED_SECURITY_CONTENT].')
|
|
.replace(/\bpassword\s*=\s*['"][^'"\s]+['"]/gi, 'password=[REDACTED]')
|
|
}
|
|
|
|
// Admin-only endpoint to serve FUTURE.md and DEVELOPMENT_LOG.md content
|
|
router.get('/', requireAuth, requireAdmin, (req, res) => {
|
|
try {
|
|
// Read both files directly from the allowlist
|
|
const futureContent = fs.readFileSync(ALLOWED_FILES['FUTURE.md'], 'utf-8');
|
|
const devLogContent = fs.readFileSync(ALLOWED_FILES['DEVELOPMENT_LOG.md'], 'utf-8');
|
|
|
|
// Redact sensitive information
|
|
const sanitizedFutureContent = redactSensitiveContent(futureContent);
|
|
const sanitizedDevLogContent = redactSensitiveContent(devLogContent);
|
|
|
|
res.json({
|
|
version: pkg.version,
|
|
future: sanitizedFutureContent,
|
|
developmentLog: sanitizedDevLogContent
|
|
});
|
|
} catch (err) {
|
|
// Generic error message to prevent path disclosure
|
|
console.error('[aboutAdmin] Error reading files');
|
|
res.status(500).json({
|
|
error: 'Failed to read project documentation files',
|
|
code: 'FILE_READ_ERROR'
|
|
});
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|