mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Enhance Twilio Call Provider and Nginx Configuration
- Updated TwilioCallProvider to support X-Forwarded-Proto and X-Forwarded-Host headers for improved webhook signature validation when behind proxies. - Enabled trust proxy in StartServer to ensure correct interpretation of forwarded headers. - Removed outdated incoming call policy documentation. - Added Nginx configuration to handle X-Forwarded-Proto and X-Forwarded-Host headers, ensuring proper proxy behavior and preventing crashes when services are unavailable.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import CallProviderFactory from "../Providers/CallProviderFactory";
|
||||
import { NotificationWebhookHost } from "../Config";
|
||||
import {
|
||||
DialStatusData,
|
||||
ICallProvider,
|
||||
@@ -33,6 +32,7 @@ import IncomingCallLogItem from "Common/Models/DatabaseModels/IncomingCallLogIte
|
||||
import ProjectCallSMSConfig from "Common/Models/DatabaseModels/ProjectCallSMSConfig";
|
||||
import User from "Common/Models/DatabaseModels/User";
|
||||
import Phone from "Common/Types/Phone";
|
||||
import { Host, HttpProtocol } from "Common/Server/EnvironmentConfig";
|
||||
|
||||
const router: ExpressRouter = Express.getRouter();
|
||||
|
||||
@@ -289,7 +289,7 @@ router.post(
|
||||
"Please wait while we connect you to the on-call engineer.";
|
||||
|
||||
// Construct status callback URL
|
||||
const statusCallbackUrl: string = `${NotificationWebhookHost}/notification/incoming-call/dial-status/${createdCallLog.id?.toString()}/${createdCallLogItem.id?.toString()}`;
|
||||
const statusCallbackUrl: string = `${HttpProtocol}${Host}/notification/incoming-call/dial-status/${createdCallLog.id?.toString()}/${createdCallLogItem.id?.toString()}`;
|
||||
|
||||
// Generate greeting + dial TwiML
|
||||
const twiml: string = generateGreetingAndDialTwiml(
|
||||
@@ -737,7 +737,7 @@ async function dialNextUser(
|
||||
});
|
||||
|
||||
// Construct status callback URL
|
||||
const statusCallbackUrl: string = `${NotificationWebhookHost}/notification/incoming-call/dial-status/${callLog.id?.toString()}/${createdCallLogItem.id?.toString()}`;
|
||||
const statusCallbackUrl: string = `${HttpProtocol}${Host}/notification/incoming-call/dial-status/${callLog.id?.toString()}/${createdCallLogItem.id?.toString()}`;
|
||||
|
||||
// Generate dial TwiML with escalation message
|
||||
const escalationMessage: string = `Connecting you to the next available engineer.`;
|
||||
|
||||
@@ -3,7 +3,9 @@ import Email from "Common/Types/Email";
|
||||
import EmailServer from "Common/Types/Email/EmailServer";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import { AdminDashboardClientURL } from "Common/Server/EnvironmentConfig";
|
||||
import {
|
||||
AdminDashboardClientURL,
|
||||
} from "Common/Server/EnvironmentConfig";
|
||||
import GlobalConfigService from "Common/Server/Services/GlobalConfigService";
|
||||
import GlobalConfig, {
|
||||
EmailServerType,
|
||||
|
||||
@@ -255,8 +255,18 @@ export default class TwilioCallProvider implements ICallProvider {
|
||||
const authToken: string = this.config.authToken;
|
||||
|
||||
// Build the full URL that Twilio used to generate the signature
|
||||
const protocol: string = request.protocol || "https";
|
||||
const host: string = request.get("host") || "";
|
||||
// When behind a proxy, use X-Forwarded-Proto and X-Forwarded-Host headers
|
||||
// These headers are set by reverse proxies (nginx, load balancers, etc.)
|
||||
const forwardedProto: string | undefined = request.get(
|
||||
"x-forwarded-proto",
|
||||
) as string | undefined;
|
||||
const forwardedHost: string | undefined = request.get(
|
||||
"x-forwarded-host",
|
||||
) as string | undefined;
|
||||
|
||||
// Use forwarded headers if available, otherwise fall back to request properties
|
||||
const protocol: string = forwardedProto || request.protocol || "https";
|
||||
const host: string = forwardedHost || request.get("host") || "";
|
||||
const url: string = `${protocol}://${host}${request.originalUrl}`;
|
||||
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
@@ -45,6 +45,9 @@ const app: ExpressApplication = Express.getExpressApp();
|
||||
app.disable("x-powered-by");
|
||||
app.set("port", process.env["PORT"]);
|
||||
app.set("view engine", "ejs");
|
||||
// Enable trust proxy to correctly interpret X-Forwarded-* headers from reverse proxies
|
||||
// This is needed for req.protocol, req.ip to be correct when behind nginx/load balancers
|
||||
app.set("trust proxy", true);
|
||||
app.use(CookieParser());
|
||||
|
||||
const jsonBodyParserMiddleware: RequestHandler = ExpressJson({
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -545,12 +545,19 @@ ${PROVISION_SSL_CERTIFICATE_KEY_DIRECTIVE}
|
||||
}
|
||||
|
||||
location /notification {
|
||||
# This is for nginx not to crash when service is not available.
|
||||
# This is for nginx not to crash when service is not available.
|
||||
resolver 127.0.0.1 valid=30s;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# Use upstream X-Forwarded-Proto if available (for webhook signature validation behind proxies like ngrok)
|
||||
# Falls back to $scheme if not set
|
||||
set $forwarded_proto $http_x_forwarded_proto;
|
||||
if ($forwarded_proto = '') {
|
||||
set $forwarded_proto $scheme;
|
||||
}
|
||||
proxy_set_header X-Forwarded-Proto $forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
|
||||
# enable WebSockets (for ws://sockjs not connected error in the accounts source: https://stackoverflow.com/questions/41381444/websocket-connection-failed-error-during-websocket-handshake-unexpected-respon)
|
||||
proxy_http_version 1.1;
|
||||
|
||||
Reference in New Issue
Block a user