mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-13 07:04:50 -06:00

- Added new environment variables for SSL configuration, including `SSL_CONF_PRIVKEY` and `SSL_CONF_FULLCHAIN`, to support secure connections. - Introduced additional webhook configuration options in the `.env.example` file, such as `WEBHOOK_REQUEST_TIMEOUT_MS`, `WEBHOOK_RETRY_MAX_ATTEMPTS`, and related retry settings to improve webhook resilience and error handling. - Updated the `bootstrap` function in `main.ts` to handle SSL certificate loading failures gracefully, falling back to HTTP if necessary. - Enhanced error handling and logging in the `BusinessStartupService` to ensure better traceability and robustness when processing messages. This commit focuses on improving the security and reliability of webhook interactions while ensuring that the application can handle SSL configurations effectively.
159 lines
4.9 KiB
TypeScript
159 lines
4.9 KiB
TypeScript
// Import this first from sentry instrument!
|
|
import '@utils/instrumentSentry';
|
|
|
|
// Now import other modules
|
|
import { ProviderFiles } from '@api/provider/sessions';
|
|
import { PrismaRepository } from '@api/repository/repository.service';
|
|
import { HttpStatus, router } from '@api/routes/index.router';
|
|
import { eventManager, waMonitor } from '@api/server.module';
|
|
import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config';
|
|
import { onUnexpectedError } from '@config/error.config';
|
|
import { Logger } from '@config/logger.config';
|
|
import { ROOT_DIR } from '@config/path.config';
|
|
import * as Sentry from '@sentry/node';
|
|
import { ServerUP } from '@utils/server-up';
|
|
import axios from 'axios';
|
|
import compression from 'compression';
|
|
import cors from 'cors';
|
|
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
|
import { join } from 'path';
|
|
|
|
function initWA() {
|
|
waMonitor.loadInstance();
|
|
}
|
|
|
|
async function bootstrap() {
|
|
const logger = new Logger('SERVER');
|
|
const app = express();
|
|
|
|
let providerFiles: ProviderFiles = null;
|
|
if (configService.get<ProviderSession>('PROVIDER').ENABLED) {
|
|
providerFiles = new ProviderFiles(configService);
|
|
await providerFiles.onModuleInit();
|
|
logger.info('Provider:Files - ON');
|
|
}
|
|
|
|
const prismaRepository = new PrismaRepository(configService);
|
|
await prismaRepository.onModuleInit();
|
|
|
|
app.use(
|
|
cors({
|
|
origin(requestOrigin, callback) {
|
|
const { ORIGIN } = configService.get<Cors>('CORS');
|
|
if (ORIGIN.includes('*')) {
|
|
return callback(null, true);
|
|
}
|
|
if (ORIGIN.indexOf(requestOrigin) !== -1) {
|
|
return callback(null, true);
|
|
}
|
|
return callback(new Error('Not allowed by CORS'));
|
|
},
|
|
methods: [...configService.get<Cors>('CORS').METHODS],
|
|
credentials: configService.get<Cors>('CORS').CREDENTIALS,
|
|
}),
|
|
urlencoded({ extended: true, limit: '136mb' }),
|
|
json({ limit: '136mb' }),
|
|
compression(),
|
|
);
|
|
|
|
app.set('view engine', 'hbs');
|
|
app.set('views', join(ROOT_DIR, 'views'));
|
|
app.use(express.static(join(ROOT_DIR, 'public')));
|
|
|
|
app.use('/store', express.static(join(ROOT_DIR, 'store')));
|
|
|
|
app.use('/', router);
|
|
|
|
app.use(
|
|
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
if (err) {
|
|
const webhook = configService.get<Webhook>('WEBHOOK');
|
|
|
|
if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) {
|
|
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
|
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
|
const now = localISOTime;
|
|
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
|
|
const serverUrl = configService.get<HttpServer>('SERVER').URL;
|
|
|
|
const errorData = {
|
|
event: 'error',
|
|
data: {
|
|
error: err['error'] || 'Internal Server Error',
|
|
message: err['message'] || 'Internal Server Error',
|
|
status: err['status'] || 500,
|
|
response: {
|
|
message: err['message'] || 'Internal Server Error',
|
|
},
|
|
},
|
|
date_time: now,
|
|
api_key: globalApiKey,
|
|
server_url: serverUrl,
|
|
};
|
|
|
|
logger.error(errorData);
|
|
|
|
const baseURL = webhook.EVENTS.ERRORS_WEBHOOK;
|
|
const httpService = axios.create({ baseURL });
|
|
|
|
httpService.post('', errorData);
|
|
}
|
|
|
|
return res.status(err['status'] || 500).json({
|
|
status: err['status'] || 500,
|
|
error: err['error'] || 'Internal Server Error',
|
|
response: {
|
|
message: err['message'] || 'Internal Server Error',
|
|
},
|
|
});
|
|
}
|
|
|
|
next();
|
|
},
|
|
(req: Request, res: Response, next: NextFunction) => {
|
|
const { method, url } = req;
|
|
|
|
res.status(HttpStatus.NOT_FOUND).json({
|
|
status: HttpStatus.NOT_FOUND,
|
|
error: 'Not Found',
|
|
response: {
|
|
message: [`Cannot ${method.toUpperCase()} ${url}`],
|
|
},
|
|
});
|
|
|
|
next();
|
|
},
|
|
);
|
|
|
|
const httpServer = configService.get<HttpServer>('SERVER');
|
|
|
|
ServerUP.app = app;
|
|
let server = ServerUP[httpServer.TYPE];
|
|
|
|
if (server === null) {
|
|
logger.warn('SSL cert load failed — falling back to HTTP.');
|
|
logger.info("Ensure 'SSL_CONF_PRIVKEY' and 'SSL_CONF_FULLCHAIN' env vars point to valid certificate files.");
|
|
|
|
httpServer.TYPE = 'http';
|
|
server = ServerUP[httpServer.TYPE];
|
|
}
|
|
|
|
eventManager.init(server);
|
|
|
|
if (process.env.SENTRY_DSN) {
|
|
logger.info('Sentry - ON');
|
|
|
|
// Add this after all routes,
|
|
// but before any and other error-handling middlewares are defined
|
|
Sentry.setupExpressErrorHandler(app);
|
|
}
|
|
|
|
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
|
|
|
|
initWA();
|
|
|
|
onUnexpectedError();
|
|
}
|
|
|
|
bootstrap();
|