From ba646279698143f88773b2759605d24f99015589 Mon Sep 17 00:00:00 2001 From: "Vladimir.Y" <1560781+vladimiry@users.noreply.github.com> Date: Mon, 21 Feb 2022 18:16:29 +0300 Subject: [PATCH] tweak "src/electron-main/web-request" code * mostly refactoring/renaming --- package.json | 2 +- src/electron-main/web-request/index.ts | 19 +++---- src/electron-main/web-request/service.ts | 65 ++++++++++++------------ 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index f6f6919cd..853e762ce 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "electron-mail", "description": "Unofficial ProtonMail Desktop App", - "version": "4.13.3", + "version": "4.13.4", "author": "Vladimir Yakovlev ", "license": "GPL-3.0", "homepage": "https://github.com/vladimiry/ElectronMail", diff --git a/src/electron-main/web-request/index.ts b/src/electron-main/web-request/index.ts index 6bdddfa8c..bde04d2bd 100644 --- a/src/electron-main/web-request/index.ts +++ b/src/electron-main/web-request/index.ts @@ -13,7 +13,7 @@ import { } from "src/shared/util"; import {Context} from "src/electron-main/model"; import {CorsProxy} from "./model"; -import {getHeader, patchResponseHeaders, resolveCorsProxy} from "./service"; +import {getHeader, patchCorsResponseHeaders, patchSameSiteCookieRecord, resolveCorsProxy} from "./service"; import {HEADERS} from "./const"; import {IPC_MAIN_API_NOTIFICATION$} from "src/electron-main/api/constants"; import {IPC_MAIN_API_NOTIFICATION_ACTIONS} from "src/shared/api/main-process/actions"; @@ -210,22 +210,23 @@ export function initWebRequestListenersByAccount( // according to electron docs "only the last attached listener will be used", so no need to unsubscribe previously registered handlers session.webRequest.onHeadersReceived( (details, callback) => { - const requestProxy = requestProxyCache.get(details); + const {responseHeaders} = details; + const corsProxy = requestProxyCache.get(details)?.corsProxy; - if (!requestProxy) { + requestProxyCache.remove(details); + + if (!responseHeaders) { callback({}); return; } - const {corsProxy} = requestProxy; - if (corsProxy) { - callback({responseHeaders: patchResponseHeaders({responseHeaders: details.responseHeaders, corsProxy})}); - } else { - callback({}); + patchCorsResponseHeaders(responseHeaders, corsProxy); } - requestProxyCache.remove(details); + patchSameSiteCookieRecord(responseHeaders); + + callback({responseHeaders}); }, ); diff --git a/src/electron-main/web-request/service.ts b/src/electron-main/web-request/service.ts index fd5ca928c..de9c68009 100644 --- a/src/electron-main/web-request/service.ts +++ b/src/electron-main/web-request/service.ts @@ -60,13 +60,10 @@ export function patchResponseHeader( // TODO consider doing initial preflight/OPTIONS call to https://mail.protonmail.com // and then pick all the "Access-Control-*" header names as a template instead of hardcoding the default headers // since over time the server may start giving other headers -export const patchResponseHeaders: ( - arg: { corsProxy: CorsProxy; responseHeaders: OnHeadersReceivedListenerDetails["responseHeaders"] } -) => OnHeadersReceivedListenerDetails["responseHeaders"] = ({corsProxy, responseHeaders}) => { - if (!responseHeaders) { - return responseHeaders; - } - +export const patchCorsResponseHeaders: ( + responseHeaders: Exclude, + corsProxy: CorsProxy, +) => void = (responseHeaders, corsProxy) => { patchResponseHeader( responseHeaders, { @@ -144,34 +141,38 @@ export const patchResponseHeaders: ( values: ["Date"], }, ); +}; - { - // starting from @electron v12 (more exactly from the respective @chromium version) - // the "set-cookie" records with "samesite=strict" get blocked by @chromium, for example the "/api/auth/cookies" request case - // so to workaround the issue we replace the "samesite=strict|lax"-like attribute with "samesite=none" - for (const cookieName of Object.keys(responseHeaders)) { - if (cookieName.toLowerCase() !== "set-cookie") { - continue; - } - const cookies = responseHeaders[cookieName]; - if (cookies) { - // TODO consider patching the "samesite" cookie attribute only for "/api/auth/cookies" request - responseHeaders[cookieName] = cookies.map((cookieValue) => { - if ((/samesite[\s]*=[\s]*(strict|lax|none)/i).test(cookieValue)) { - cookieValue = cookieValue.replace(/samesite[\s]*=[\s]*(strict|lax)/i, "samesite=none"); - } else { - cookieValue = `${cookieValue}; samesite=none`; - } - cookieValue = /(;[\s]*secure)|(secure[\s]*;)/i.test(cookieValue) - ? cookieValue - : `${cookieValue}; secure`; // "samesite=none" attribute requires "secure" attribute - return cookieValue; - }); - } +export const patchSameSiteCookieRecord = ( + responseHeaders: Exclude, +) => { + // starting from @electron v12 (more exactly from the respective @chromium version) + // the "set-cookie" records with "samesite=strict" get blocked by @chromium, for example the "/api/auth/cookies" request case + // so to workaround the issue we replace the "samesite=strict|lax"-like attribute with "samesite=none" + for (const headerName of Object.keys(responseHeaders)) { + if (headerName.toLowerCase() !== "set-cookie") { + continue; + } + + const headerValues = responseHeaders[headerName]; + + if (!headerValues) { + continue; } - } - return responseHeaders; + // TODO consider patching the "samesite" cookie attribute only for "/api/auth/cookies" request + responseHeaders[headerName] = headerValues.map((headerValue) => { + if ((/samesite[\s]*=[\s]*(strict|lax|none)/i).test(headerValue)) { + headerValue = headerValue.replace(/samesite[\s]*=[\s]*(strict|lax)/i, "samesite=none"); + } else { + headerValue = `${headerValue}; samesite=none`; + } + headerValue = /(;[\s]*secure)|(secure[\s]*;)/i.test(headerValue) + ? headerValue + : `${headerValue}; secure`; // "samesite=none" attribute requires "secure" attribute + return headerValue; + }); + } }; // TODO consider resolving/returning the proxy only for URLs with `entryApiUrl`-like origin