diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 1e41076e7..59d73c55f 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -65,6 +65,8 @@ import { AppReleasesModule } from './modules/app-releases/app-releases.module'; import { ConfigurableFareModule } from './modules/configurable-fare/configurable-fare.module'; import { SegmentFareSeeder } from './seed/segment-fare.seeder'; +import { EOtpType } from "@tria-plc/iamapi-common"; + @Module({ imports: [ ThrottlerModule.forRoot([ @@ -97,6 +99,16 @@ import { SegmentFareSeeder } from './seed/segment-fare.seeder'; TriaIamModule.forRoot({ applications: [EDR_PASSENGER_APPLICATION], permissions: EDR_PASSENGER_PERMISSIONS, + otpMessages: { + [EOtpType.MFA_LOGIN]: ({ otp }) => + `Your EDR Passenger login code is ${otp}. It will expire in 5 minutes.`, + [EOtpType.VERIFY_PHONE_NUMBER]: ({ otp }) => + `Your EDR Passenger phone verification code is ${otp}. It will expire in 5 minutes.`, + [EOtpType.RESET_PASSWORD]: ({ route }) => + `Reset your EDR Passenger password using this link: ${route}`, + [EOtpType.SET_PASSWORD]: ({ route }) => + `Set your EDR Passenger password using this link: ${route}`, + }, }), SharedAuthModule, PrismaModule, diff --git a/apps/edr-passenger-web/backoffice/src/features/support/useSupportSocket.ts b/apps/edr-passenger-web/backoffice/src/features/support/useSupportSocket.ts index c4014f8d2..503793d2f 100644 --- a/apps/edr-passenger-web/backoffice/src/features/support/useSupportSocket.ts +++ b/apps/edr-passenger-web/backoffice/src/features/support/useSupportSocket.ts @@ -37,7 +37,9 @@ export function useSupportSocket( `${SOCKET_ORIGIN}/${Passenger.PASSENGER_SUPPORT_WS_NAMESPACE}`, { auth: { token }, - transports: ['websocket'], + // Prefer WebSocket, fall back to HTTP long-polling if the proxy blocks + // the upgrade (polling rides normal HTTPS, already CSP-allowed). + transports: ['websocket', 'polling'], withCredentials: true, }, ); diff --git a/apps/edr-passenger-web/backoffice/src/middleware.ts b/apps/edr-passenger-web/backoffice/src/middleware.ts index db7af8568..5ad4e3407 100644 --- a/apps/edr-passenger-web/backoffice/src/middleware.ts +++ b/apps/edr-passenger-web/backoffice/src/middleware.ts @@ -35,8 +35,12 @@ function buildCsp(nonce: string): string { ? `'self' 'nonce-${nonce}' 'strict-dynamic'` : `'self' 'unsafe-inline' 'unsafe-eval'`; + // The Socket.IO WebSocket upgrade connects to wss://; under CSP a + // `https://host` source does NOT cover `wss://host`, so add it explicitly. + const wsOrigin = apiOrigin.replace(/^http/, 'ws'); // https→wss, http→ws + const connectSrc = isProd - ? `'self' ${apiOrigin}`.trim() + ? `'self' ${apiOrigin} ${wsOrigin}`.trim() : `'self' ${apiOrigin} ws: wss:`.trim(); const directives = [ diff --git a/apps/edr-passenger-web/portal/src/features/support/useSupportSocket.ts b/apps/edr-passenger-web/portal/src/features/support/useSupportSocket.ts index 3adee4c50..1bd21b7b8 100644 --- a/apps/edr-passenger-web/portal/src/features/support/useSupportSocket.ts +++ b/apps/edr-passenger-web/portal/src/features/support/useSupportSocket.ts @@ -26,7 +26,9 @@ export function useSupportSocket(enabled: boolean) { `${SOCKET_ORIGIN}/${Passenger.PASSENGER_SUPPORT_WS_NAMESPACE}`, { auth: { guestId: getDeviceId() }, - transports: ['websocket'], + // Prefer WebSocket, fall back to HTTP long-polling if the proxy blocks + // the upgrade (polling rides normal HTTPS, already CSP-allowed). + transports: ['websocket', 'polling'], withCredentials: true, }, ); diff --git a/apps/edr-passenger-web/portal/src/middleware.ts b/apps/edr-passenger-web/portal/src/middleware.ts index c7960a601..f5759b0bf 100644 --- a/apps/edr-passenger-web/portal/src/middleware.ts +++ b/apps/edr-passenger-web/portal/src/middleware.ts @@ -48,8 +48,12 @@ function buildCsp(nonce: string): string { ? `'self' 'nonce-${nonce}' 'strict-dynamic'` : `'self' 'unsafe-inline' 'unsafe-eval'`; + // The Socket.IO WebSocket upgrade connects to wss://; under CSP a + // `https://host` source does NOT cover `wss://host`, so add it explicitly. + const wsOrigin = apiOrigin.replace(/^http/, 'ws'); // https→wss, http→ws + const connectSrc = isProd - ? `'self' ${apiOrigin}`.trim() + ? `'self' ${apiOrigin} ${wsOrigin}`.trim() : `'self' ${apiOrigin} ws: wss:`.trim(); const directives = [