From 34e1da308da28c021210665e20f587004122ad1d Mon Sep 17 00:00:00 2001 From: Vladimir Y Date: Tue, 10 Nov 2020 13:01:23 +0300 Subject: [PATCH] fix: Unexpected "origin" value detected (value: "{"origin":"null"}") * the error could occur in some edge cases, like replying to the email with embedded images and enabled "Block non 'API entry point'-based network requests" feature (see #312 for details) --- src/electron-main/web-request/index.ts | 80 +++++++++++++++++--------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/src/electron-main/web-request/index.ts b/src/electron-main/web-request/index.ts index 6d8306c3c..411e01a51 100644 --- a/src/electron-main/web-request/index.ts +++ b/src/electron-main/web-request/index.ts @@ -49,6 +49,19 @@ const resolveFakeOrigin = (requestDetails: DeepReadonly { + // https://github.com/ProtonMail/proton-shared/blob/84c149ebd0419e13e9a1504404a1d1803c53500c/lib/helpers/image.ts#L171 + const nonSchemaLikePrefix = "cid:"; + + return (url: string): boolean => { + return ( + url.startsWith(nonSchemaLikePrefix) + && + url.substr(nonSchemaLikePrefix.length, 2) !== "//" // preventing "cid://"-like url schema use + ); + }; +})(); + export function initWebRequestListenersByAccount( ctx: DeepReadonly, { @@ -81,6 +94,8 @@ export function initWebRequestListenersByAccount( {urls: []}, (details, callback) => { const {url} = details; + const allowRequest = (): void => callback({}); + const banRequest = (): void => callback({cancel: true}); if ( // feature enabled @@ -92,6 +107,11 @@ export function initWebRequestListenersByAccount( // only image resources String(details.resourceType).toLowerCase() === "image" && + // TODO consider proxyfying only images with http/https schemes + // WARN: should be called before consequent "parseUrlOriginWithNullishCheck" call + // embedded/"cid:"-prefixed urls should not be processed/proxyfied (origin resolving for such urls returns "null") + !isProtonEmbeddedUrl(url) + && // resources served from "allowed origins" should not be proxified as those // are not external (proton's static resource & API, devtools, etc) !allowedOrigins.includes( @@ -121,36 +141,44 @@ export function initWebRequestListenersByAccount( return; } - const additionAllowedOrigin = requestProxyCache.get(details)?.additionAllowedOrigin; + if (!blockNonEntryUrlBasedRequests) { + allowRequest(); + return; + } + + if (isProtonEmbeddedUrl(url)) { + // embedded/"cid:"-prefixed urls get silently blocked (origin resolving for such urls returns "null") + banRequest(); + return; + } - const bannedUrlAccessMsg: null | string = blockNonEntryUrlBasedRequests - ? buildUrlOriginsFailedMsgTester([ - ...allowedOrigins, - ...( - additionAllowedOrigin - ? [additionAllowedOrigin] - : [] - ), - ])(url) - : null; - - if (typeof bannedUrlAccessMsg === "string") { - setTimeout(() => { // can be asynchronous (speeds up callback resolving) - const message - = `Access to the "${details.resourceType}" resource with "${url}" URL has been forbidden. ${bannedUrlAccessMsg}`; - logger.error(message); - IPC_MAIN_API_NOTIFICATION$.next( - IPC_MAIN_API_NOTIFICATION_ACTIONS.ErrorMessage({message}), - ); - }); - - requestProxyCache.remove(details); - - callback({cancel: true}); + const additionAllowedOrigin = requestProxyCache.get(details)?.additionAllowedOrigin; + const bannedUrlAccessMsg: null | string = buildUrlOriginsFailedMsgTester([ + ...allowedOrigins, + ...( + additionAllowedOrigin + ? [additionAllowedOrigin] + : [] + ), + ])(url); + + if (typeof bannedUrlAccessMsg !== "string") { + allowRequest(); return; } - callback({}); + setTimeout(() => { // can be asynchronous (speeds up callback resolving) + const message + = `Access to the "${details.resourceType}" resource with "${url}" URL has been forbidden. ${bannedUrlAccessMsg}`; + logger.error(message); + IPC_MAIN_API_NOTIFICATION$.next( + IPC_MAIN_API_NOTIFICATION_ACTIONS.ErrorMessage({message}), + ); + }); + + requestProxyCache.remove(details); + + banRequest(); }, );