Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/note.picotech.app/public_html/src/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const rateLimit = require('express-rate-limit');
const csrf = require('csurf');
const path = require('path');
const config = require('./config/config');
const { testConnection } = require('./config/database');
const { syncDatabase, DataDeletionRequest } = require('./models');
const {
globalErrorHandler,
handleNotFound,
handleUnhandledRejection,
handleUncaughtException,
handleGracefulShutdown,
} = require('./middleware/errorHandler');
// Import routes
const authRoutes = require('./routes/auth');
const meetingRoutes = require('./routes/meetings');
const noteRoutes = require('./routes/notes');
const recordingRoutes = require('./routes/recordings');
const transcriptRoutes = require('./routes/transcripts');
const summaryRoutes = require('./routes/summaries');
const labelRoutes = require('./routes/labels');
const apiProxyRoutes = require('./routes/apiProxy');
// Import WebSocket services
const LiveTranscriptionService = require('./services/liveTranscriptionService');
// Import job queue service
const { initialize: initializeJobQueue } = require('./services/jobQueue');
// Handle uncaught exceptions
handleUncaughtException();
const app = express();
// Trust proxy (for rate limiting and IP detection)
app.set('trust proxy', 1);
// Security middleware
app.use(helmet({
crossOriginResourcePolicy: { policy: 'cross-origin' },
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
connectSrc: ["'self'", "wss:", "https:"],
upgradeInsecureRequests: [],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
noSniff: true,
xssFilter: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
dnsPrefetchControl: { allow: false },
ieNoOpen: true,
frameguard: { action: 'deny' },
permittedCrossDomainPolicies: { permittedPolicies: 'none' }
}));
// CSRF Protection - disabled for API routes since JWT provides sufficient protection
// Keeping the middleware setup for potential future use with web clients
const csrfProtection = csrf({ cookie: true });
// Skip CSRF protection for all API routes - JWT tokens provide CSRF protection
app.use('/api/', (req, res, next) => {
return next();
});
// Add CSRF token to responses
app.use((req, res, next) => {
// Skip CSRF token for public auth routes
const publicAuthRoutes = [
'/api/auth/send-registration-otp',
'/api/auth/verify-otp',
'/api/auth/register',
'/api/auth/login',
'/api/auth/refresh-token',
'/api/auth/forgot-password',
'/api/auth/reset-password',
'/api/auth/verify-email'
];
if (publicAuthRoutes.some(route => req.path.startsWith(route))) {
return next();
}
// Only set CSRF token if csrfProtection middleware has been applied
if (req.csrfToken) {
res.locals.csrfToken = req.csrfToken();
// Expose CSRF token in header for AJAX requests
res.setHeader('X-CSRF-Token', req.csrfToken());
}
next();
});
// CORS configuration
app.use(cors({
origin: config.cors.origin,
credentials: config.cors.credentials,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
exposedHeaders: ['X-CSRF-Token'],
}));
// Compression middleware
app.use(compression());
// Rate limiting - general API
const limiter = rateLimit({
windowMs: config.rateLimit.windowMs,
max: config.rateLimit.max,
message: {
success: false,
message: 'Too many requests from this IP, please try again later.',
code: 'RATE_LIMIT_EXCEEDED',
},
standardHeaders: true,
legacyHeaders: false,
});
// Stricter rate limiting for authentication endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts per 15 minutes for auth endpoints
message: {
success: false,
message: 'Too many authentication attempts, please try again later.',
code: 'AUTH_RATE_LIMIT_EXCEEDED',
},
standardHeaders: true,
legacyHeaders: false,
skipSuccessfulRequests: true, // Don't count successful requests
});
// Stricter rate limiting for OTP endpoints
const otpLimiter = rateLimit({
windowMs: 5 * 60 * 1000, // 5 minutes
max: 3, // 3 OTP requests per 5 minutes
message: {
success: false,
message: 'Too many OTP requests, please try again later.',
code: 'OTP_RATE_LIMIT_EXCEEDED',
},
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
app.use('/api/auth/login', authLimiter);
app.use('/api/auth/register', authLimiter);
app.use('/api/auth/forgot-password', authLimiter);
app.use('/api/auth/send-otp', otpLimiter);
app.use('/api/auth/verify-otp', otpLimiter);
// Body parsing middleware (skip for multipart/form-data)
app.use((req, res, next) => {
if (req.headers['content-type'] && req.headers['content-type'].includes('multipart/form-data')) {
return next();
}
express.json({ limit: '10mb' })(req, res, next);
});
app.use((req, res, next) => {
if (req.headers['content-type'] && req.headers['content-type'].includes('multipart/form-data')) {
return next();
}
express.urlencoded({ extended: true, limit: '10mb' })(req, res, next);
});
// Static file serving for uploads
app.use('/uploads', express.static(path.join(__dirname, '../uploads')));
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
success: true,
message: 'PicoNote API is running',
timestamp: new Date().toISOString(),
version: '1.0.0',
environment: config.nodeEnv,
});
});
// Default HTML page for root URL
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PicoNote API</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
h1 { color: #333; }
p { color: #666; }
</style>
</head>
<body>
<h1>Welcome to PicoNote</h1>
<p>Your AI-powered meeting notes and transcription service.</p>
<p><a href="/api">API Documentation</a></p>
<p><a href="/health">Health Check</a></p>
</body>
</html>
`);
});
// Privacy policy page
app.get('/privacy', (req, res) => {
res.sendFile(path.join(__dirname, '../privacy.html'));
});
// Delete your data page
app.get('/delete-your-data', (req, res) => {
res.sendFile(path.join(__dirname, '../delete-data.html'));
});
// Handle delete data form submission
app.post('/delete-your-data', async (req, res) => {
try {
const { name, email, reason } = req.body;
if (!name || !email || !reason) {
return res.status(400).json({
success: false,
message: 'All fields are required.',
});
}
await DataDeletionRequest.create({
name,
email,
reason,
});
res.send(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Request Submitted - PicoNote</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
h1 { color: #333; }
p { color: #666; }
</style>
</head>
<body>
<h1>Request Submitted</h1>
<p>Your data deletion request has been submitted successfully. We will process it within 30 days.</p>
<p><a href="/">Back to Home</a></p>
</body>
</html>
`);
} catch (error) {
console.error('Error submitting deletion request:', error);
res.status(500).json({
success: false,
message: 'An error occurred while submitting your request.',
});
}
});
// API routes
app.use('/api/auth', authRoutes);
app.use('/api/meetings', meetingRoutes);
app.use('/api/notes', noteRoutes);
app.use('/api/recordings', recordingRoutes);
app.use('/api/transcripts', transcriptRoutes);
app.use('/api/summaries', summaryRoutes);
app.use('/api/labels', labelRoutes);
app.use('/api/proxy', apiProxyRoutes);
// API documentation endpoint
app.get('/api', (req, res) => {
res.json({
success: true,
message: 'PicoNote API v1.0.0',
documentation: {
auth: '/api/auth - Authentication endpoints',
meetings: '/api/meetings - Meeting management',
notes: '/api/notes - Note management',
recordings: '/api/recordings - Audio recording management',
transcripts: '/api/transcripts - Transcription management',
summaries: '/api/summaries - Meeting summary management',
labels: '/api/labels - Label management',
},
endpoints: {
health: 'GET /health - Health check',
docs: 'GET /api - This documentation',
},
});
});
// Handle 404 for unmatched routes
app.use(handleNotFound);
// Global error handling middleware
app.use(globalErrorHandler);
// Handle unhandled promise rejections
handleUnhandledRejection();
// Start server
const startServer = async () => {
try {
// Test database connection
await testConnection();
// Sync database models
// await syncDatabase({ alter: config.nodeEnv === 'development' });
const server = app.listen(config.port, () => {
console.log(`🚀 PicoNote API server running on port ${config.port}`);
console.log(`📝 Environment: ${config.nodeEnv}`);
console.log(`🔗 Health check: http://localhost:${config.port}/health`);
console.log(`📚 API docs: http://localhost:${config.port}/api`);
if (config.nodeEnv === 'development') {
console.log(`🎯 CORS enabled for: ${config.cors.origin.join(', ')}`);
}
});
// Initialize WebSocket services
const liveTranscriptionService = LiveTranscriptionService(server);
console.log('🔴 Live transcription WebSocket service initialized');
// Initialize job queue
await initializeJobQueue();
console.log('⚙️ Job queue initialized');
// Handle graceful shutdown
handleGracefulShutdown(server, () => {
liveTranscriptionService.cleanup();
});
return server;
} catch (error) {
console.error('❌ Failed to start server:', error);
process.exit(1);
}
};
// Start the server if this file is run directly
if (require.main === module) {
startServer();
}
module.exports = { app, startServer }; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0037 ]-- |