diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js --- a/keyserver/src/session/cookies.js +++ b/keyserver/src/session/cookies.js @@ -32,7 +32,7 @@ import { clearDeviceToken } from '../updaters/device-token-updaters'; import { updateThreadMembers } from '../updaters/thread-updaters'; import { assertSecureRequest } from '../utils/security-utils'; -import { type AppURLFacts } from '../utils/urls'; +import { type AppURLFacts, getAppURLFactsFromRequestURL } from '../utils/urls'; import { Viewer } from './viewer'; import type { AnonymousViewerData, UserViewerData } from './viewer'; @@ -369,6 +369,18 @@ }; } +function getRequestIPAddress(req: $Request) { + const { proxy } = getAppURLFactsFromRequestURL(req.originalUrl); + let ipAddress; + if (proxy === 'none') { + ipAddress = req.socket.remoteAddress; + } else if (proxy === 'apache') { + ipAddress = req.get('X-Forwarded-For'); + } + invariant(ipAddress, 'could not determine requesting IP address'); + return ipAddress; +} + function getSessionParameterInfoFromRequestBody( req: $Request, ): SessionParameterInfo { @@ -384,13 +396,11 @@ req.method === 'GET' || sessionID !== undefined ? sessionIdentifierTypes.BODY_SESSION_ID : sessionIdentifierTypes.COOKIE_ID; - const ipAddress = req.get('X-Forwarded-For'); - invariant(ipAddress, 'X-Forwarded-For header missing'); return { isSocket: false, sessionID, sessionIdentifierType, - ipAddress, + ipAddress: getRequestIPAddress(req), userAgent: req.get('User-Agent'), }; } @@ -423,8 +433,6 @@ assertSecureRequest(req); const { sessionIdentification } = clientMessage.payload; const { sessionID } = sessionIdentification; - const ipAddress = req.get('X-Forwarded-For'); - invariant(ipAddress, 'X-Forwarded-For header missing'); const sessionParameterInfo = { isSocket: true, sessionID, @@ -432,7 +440,7 @@ sessionID !== undefined ? sessionIdentifierTypes.BODY_SESSION_ID : sessionIdentifierTypes.COOKIE_ID, - ipAddress, + ipAddress: getRequestIPAddress(req), userAgent: req.get('User-Agent'), }; diff --git a/keyserver/src/utils/security-utils.js b/keyserver/src/utils/security-utils.js --- a/keyserver/src/utils/security-utils.js +++ b/keyserver/src/utils/security-utils.js @@ -5,8 +5,14 @@ import { getAppURLFactsFromRequestURL } from './urls'; function assertSecureRequest(req: $Request) { - const { https } = getAppURLFactsFromRequestURL(req.originalUrl); - if (https && req.get('X-Forwarded-SSL') !== 'on') { + const { https, proxy } = getAppURLFactsFromRequestURL(req.originalUrl); + if (!https) { + return; + } + if ( + (proxy === 'none' && req.protocol !== 'https') || + (proxy === 'apache' && req.get('X-Forwarded-SSL') !== 'on') + ) { throw new Error('insecure request'); } } diff --git a/keyserver/src/utils/urls.js b/keyserver/src/utils/urls.js --- a/keyserver/src/utils/urls.js +++ b/keyserver/src/utils/urls.js @@ -11,7 +11,9 @@ +basePath: string, +https: boolean, +baseRoutePath: string, + +proxy?: 'apache' | 'none', // defaults to apache }; +const validProxies = new Set(['apache', 'none']); const sitesObj = Object.freeze({ a: 'landing', b: 'commapp', @@ -26,10 +28,17 @@ if (existing !== undefined) { return existing; } - const urlFacts: ?AppURLFacts = await importJSON({ + let urlFacts: ?AppURLFacts = await importJSON({ folder: 'facts', name: `${site}_url`, }); + if (urlFacts) { + const { proxy } = urlFacts; + urlFacts = { + ...urlFacts, + proxy: validProxies.has(proxy) ? proxy : 'apache', + }; + } cachedURLFacts.set(site, urlFacts); return urlFacts; }