diff --git a/patches/protonmail/common-4.patch b/patches/protonmail/common-5.patch similarity index 81% rename from patches/protonmail/common-4.patch rename to patches/protonmail/common-5.patch index d6bf243ba..485c128a2 100644 --- a/patches/protonmail/common-4.patch +++ b/patches/protonmail/common-5.patch @@ -36,9 +36,9 @@ index 9aaa78a28..f3d24b47c 100644 +{ + const platform = String(navigator.platform); + const userAgents = { -+ linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36", -+ windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36", -+ macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36" ++ linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", ++ windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", ++ macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } as const; + uaParser.setUA( + platform.startsWith("Linux") @@ -107,7 +107,7 @@ index 36bd0c712..c2fb3681c 100644 } diff --git a/applications/mail/src/app/hooks/useShowUpsellBanner.ts b/applications/mail/src/app/hooks/useShowUpsellBanner.ts -index b76334920b..2501a4d4ad 100644 +index d203f913fa..178153c592 100644 --- a/applications/mail/src/app/hooks/useShowUpsellBanner.ts +++ b/applications/mail/src/app/hooks/useShowUpsellBanner.ts @@ -33,6 +33,7 @@ const useShowUpsellBanner = (labelID: string, otherBannerDisplayed: boolean) => @@ -116,7 +116,7 @@ index b76334920b..2501a4d4ad 100644 */ + /* */ const canDisplayUpsellBanner = - !user.hasPaidMail && + user.isFree && Date.now() > threeDaysAfterCreationDate && @@ -40,6 +41,7 @@ const useShowUpsellBanner = (labelID: string, otherBannerDisplayed: boolean) => needToShowUpsellBanner.current && @@ -138,18 +138,34 @@ index b76334920b..2501a4d4ad 100644 }; diff --git a/packages/components/containers/heading/PrivateHeader.tsx b/packages/components/containers/heading/PrivateHeader.tsx -index 399435457d..7cf035baca 100644 +index a7d2452313..73ad8a6828 100644 --- a/packages/components/containers/heading/PrivateHeader.tsx +++ b/packages/components/containers/heading/PrivateHeader.tsx -@@ -74,7 +74,10 @@ const PrivateHeader = ({ +@@ -49,7 +49,10 @@ const PrivateHeader = ({ + - {isNarrow && searchDropdown ? {searchDropdown} : null} -- {upsellButton !== undefined ? upsellButton : } +- {upsellButton !== undefined ? upsellButton : !hideUpsellButton && } + {___ELECTRON_MAIL_PROTON_SUPPRESS_UPSELL_ADS_PLACEHOLDER___ + ? null -+ : (upsellButton !== undefined ? upsellButton : ) ++ : (upsellButton !== undefined ? upsellButton : !hideUpsellButton && ) + } {feedbackButton ? {feedbackButton} : null} - {contactsButton ? {contactsButton} : null} - {settingsButton ? {settingsButton} : null} + {settingsButton ? ( + + +diff --git a/packages/components/containers/api/ApiProvider.js b/packages/components/containers/api/ApiProvider.js +index 3d1b81941c..6ac2f748fa 100644 +--- a/packages/components/containers/api/ApiProvider.js ++++ b/packages/components/containers/api/ApiProvider.js +@@ -120,7 +120,9 @@ const ApiProvider = ({ config, onLogout, children, UID, noErrorState }) => { + error.cancel = true; + reject(error); + }} +- /> ++ />, ++ // trying to force single instance, see https://github.com/vladimiry/ElectronMail/issues/621#issuecomment-1627389416 ++ "HumanVerificationModal_ID", + ); + }); + }; diff --git a/patches/protonmail/common-6.patch b/patches/protonmail/common-6.patch new file mode 100644 index 000000000..2d1d90209 --- /dev/null +++ b/patches/protonmail/common-6.patch @@ -0,0 +1,185 @@ +diff --git a/packages/components/containers/unleash/UnleashFlagProvider.tsx b/packages/components/containers/unleash/UnleashFlagProvider.tsx +index c3e007aa4b..f51a74683e 100644 +--- a/packages/components/containers/unleash/UnleashFlagProvider.tsx ++++ b/packages/components/containers/unleash/UnleashFlagProvider.tsx +@@ -18,7 +18,7 @@ const UnleashFlagProvider = ({ UID, config, children }: Props) => { + const authHeaders = UID ? getUIDHeaders(UID) : undefined; + const appVersionHeaders = getAppVersionHeaders(clientId, config.APP_VERSION); + const unleashConfig: IConfig = { +- url: `${window.location.origin}${config.API_URL}/feature/v2/frontend`, ++ url: `${config.API_URL}/feature/v2/frontend`, + clientKey: '-', // set by the server + appName: '-', // set by the server + refreshInterval: 600, // refreshInterval in seconds, 10 mins + +diff --git a/packages/pack/scripts/validate.sh b/packages/pack/scripts/validate.sh +index 1a2ea64..bae388c 100755 +--- a/packages/pack/scripts/validate.sh ++++ b/packages/pack/scripts/validate.sh +@@ -58,7 +58,7 @@ function main { + fi; + + if [ "$hasSourceMap" -eq 0 ]; then +- hasError=true; ++ #hasError=true; + echo "[error] no SourceMaps found inside the directory: $OUTPUT_DIR"; + fi; + +diff --git a/packages/pack/bin/protonPack.js b/packages/pack/bin/protonPack.js +index 55715b89d..c87879ad4 100755 +--- a/packages/pack/bin/protonPack.js ++++ b/packages/pack/bin/protonPack.js +@@ -81,7 +81,7 @@ addGlobalOptions(program.command('build').description('create an optimized produ + const outputPath = path.resolve('./dist'); + await commandWithLog(`rm -rf ${outputPath}`); + await commandWithLog( +- `${require.resolve('webpack-cli/bin/cli.js')} --progress --output-path=${outputPath} ${webpackArgs}`, ++ `${require.resolve('webpack-cli/bin/cli.js')} --output-path=${outputPath} ${webpackArgs}`, + { + stdio: 'inherit', + } + +diff --git a/packages/shared/lib/helpers/browser.ts b/packages/shared/lib/helpers/browser.ts +index 9aaa78a28..f3d24b47c 100644 +--- a/packages/shared/lib/helpers/browser.ts ++++ b/packages/shared/lib/helpers/browser.ts +@@ -1,6 +1,21 @@ + import UAParser from 'ua-parser-js'; + + const uaParser = new UAParser(); ++{ ++ const platform = String(navigator.platform); ++ const userAgents = { ++ linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", ++ windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", ++ macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" ++ } as const; ++ uaParser.setUA( ++ platform.startsWith("Linux") ++ ? userAgents.linux ++ : platform.startsWith("Win") ++ ? userAgents.windows ++ : userAgents.macos ++ ); ++} + const ua = uaParser.getResult(); + + export const hasModulesSupport = () => { +@@ -89,20 +104,10 @@ export const requireDirectAction = () => isSafari() || isFirefox() || isEdge(); + * @links { https://mathiasbynens.github.io/rel-noopener/} + */ + export const openNewTab = (url: string) => { +- if (isIE11()) { +- const otherWindow = window.open(); +- if (!otherWindow) { +- return; +- } +- otherWindow.opener = null; +- otherWindow.location.href = url; +- return; +- } +- const anchor = document.createElement('a'); +- +- anchor.setAttribute('rel', 'noreferrer nofollow noopener'); +- anchor.setAttribute('target', '_blank'); +- anchor.href = url; +- +- return anchor.click(); ++ window.dispatchEvent( ++ new CustomEvent( ++ "electron-mail:packages/shared/lib/helpers/browser.ts:openNewTab", ++ {detail: {url}}, ++ ), ++ ); + }; + +diff --git a/packages/components/components/link/SettingsLink.tsx b/packages/components/components/link/SettingsLink.tsx +index 5081c4003..cde37c0cb 100644 +--- a/packages/components/components/link/SettingsLink.tsx ++++ b/packages/components/components/link/SettingsLink.tsx +@@ -48,7 +48,7 @@ const SettingsLink = ({ path, app, children, ...rest }: Props, ref: Ref + {children} + +diff --git a/packages/components/helpers/earlyAccessDesynchronization.ts b/packages/components/helpers/earlyAccessDesynchronization.ts +index 36bd0c712..c2fb3681c 100644 +--- a/packages/components/helpers/earlyAccessDesynchronization.ts ++++ b/packages/components/helpers/earlyAccessDesynchronization.ts +@@ -42,6 +42,7 @@ export const handleEarlyAccessDesynchronization = ({ + earlyAccessScope: Feature | undefined; + appName: APP_NAMES; + }) => { ++ return; + if (doesNotSupportEarlyAccessVersion()) { + return; + } + +diff --git a/applications/mail/src/app/hooks/useShowUpsellBanner.ts b/applications/mail/src/app/hooks/useShowUpsellBanner.ts +index d203f913fa..178153c592 100644 +--- a/applications/mail/src/app/hooks/useShowUpsellBanner.ts ++++ b/applications/mail/src/app/hooks/useShowUpsellBanner.ts +@@ -33,6 +33,7 @@ const useShowUpsellBanner = (labelID: string, otherBannerDisplayed: boolean) => + - No other banner is shown in the message list + - If a value is found in the localStorage that should trigger a new display + */ ++ /* */ + const canDisplayUpsellBanner = + user.isFree && + Date.now() > threeDaysAfterCreationDate && +@@ -40,6 +41,7 @@ const useShowUpsellBanner = (labelID: string, otherBannerDisplayed: boolean) => + needToShowUpsellBanner.current && + !otherBannerDisplayed && + showAgain; ++ /* */ + + const handleDismissBanner = () => { + // Set the ref to false so that we hide the banner and update the localStorage value +@@ -72,6 +74,10 @@ const useShowUpsellBanner = (labelID: string, otherBannerDisplayed: boolean) => + } + }, []); + ++ if (___ELECTRON_MAIL_PROTON_SUPPRESS_UPSELL_ADS_PLACEHOLDER___) { ++ return { canDisplayUpsellBanner: false, needToShowUpsellBanner, handleDismissBanner }; ++ } ++ + return { canDisplayUpsellBanner, needToShowUpsellBanner, handleDismissBanner }; + }; + +diff --git a/packages/components/containers/heading/PrivateHeader.tsx b/packages/components/containers/heading/PrivateHeader.tsx +index a7d2452313..73ad8a6828 100644 +--- a/packages/components/containers/heading/PrivateHeader.tsx ++++ b/packages/components/containers/heading/PrivateHeader.tsx +@@ -49,7 +49,10 @@ const PrivateHeader = ({ + + + +- {upsellButton !== undefined ? upsellButton : !hideUpsellButton && } ++ {___ELECTRON_MAIL_PROTON_SUPPRESS_UPSELL_ADS_PLACEHOLDER___ ++ ? null ++ : (upsellButton !== undefined ? upsellButton : !hideUpsellButton && ) ++ } + {feedbackButton ? {feedbackButton} : null} + {settingsButton ? ( + + +diff --git a/packages/components/containers/api/ApiProvider.js b/packages/components/containers/api/ApiProvider.js +index 3d1b81941c..6ac2f748fa 100644 +--- a/packages/components/containers/api/ApiProvider.js ++++ b/packages/components/containers/api/ApiProvider.js +@@ -120,7 +120,9 @@ const ApiProvider = ({ config, onLogout, children, UID, noErrorState }) => { + error.cancel = true; + reject(error); + }} +- /> ++ />, ++ // trying to force single instance, see https://github.com/vladimiry/ElectronMail/issues/621#issuecomment-1627389416 ++ "HumanVerificationModal_ID", + ); + }); + }; diff --git a/patches/protonmail/drop-circular-dependency.patch b/patches/protonmail/drop-circular-dependency.patch deleted file mode 100644 index 4f983178c..000000000 --- a/patches/protonmail/drop-circular-dependency.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/packages/components/hooks/usePendingUserInvitations.ts b/packages/components/hooks/usePendingUserInvitations.ts -index 6044196e1..b35ae94f5 100644 ---- a/packages/components/hooks/usePendingUserInvitations.ts -+++ b/packages/components/hooks/usePendingUserInvitations.ts -@@ -2,11 +2,11 @@ import { useCallback } from 'react'; - - import { getInvitations } from '@proton/shared/lib/api/user'; - import { Api, PendingInvitation as PendingUserInvitation } from '@proton/shared/lib/interfaces'; --import { UserInvitationModel } from '@proton/shared/lib/models'; - - import useApi from './useApi'; - import useCache from './useCache'; - import useCachedModelResult from './useCachedModelResult'; -+import { UserInvitationModelKey } from '@proton/shared/lib/models/userInvitationModel.key'; - - export const fetchPendingUserInvitations = (api: Api) => - api<{ UserInvitations: PendingUserInvitation[] }>(getInvitations()).then(({ UserInvitations }) => { -@@ -18,7 +18,7 @@ const usePendingUserInvitations = (): [PendingUserInvitation[] | undefined, bool - const cache = useCache(); - - const miss = useCallback(() => fetchPendingUserInvitations(api), [api]); -- return useCachedModelResult(cache, UserInvitationModel.key, miss); -+ return useCachedModelResult(cache, UserInvitationModelKey, miss); - }; - - export default usePendingUserInvitations; -diff --git a/packages/shared/lib/models/userInvitationModel.js b/packages/shared/lib/models/userInvitationModel.js -index 1fa9690b7..a9035e06d 100644 ---- a/packages/shared/lib/models/userInvitationModel.js -+++ b/packages/shared/lib/models/userInvitationModel.js -@@ -1,9 +1,10 @@ - import { fetchPendingUserInvitations } from '@proton/components/hooks/usePendingUserInvitations'; - - import updateCollection from '../helpers/updateCollection'; -+import { UserInvitationModelKey as key } from './userInvitationModel.key'; - - export const UserInvitationModel = { -- key: 'UserInvitations', -+ key, - get: fetchPendingUserInvitations, - update: (model, events) => updateCollection({ model, events, itemKey: 'UserInvitation' }), - }; -diff --git a/packages/shared/lib/models/userInvitationModel.key.js b/packages/shared/lib/models/userInvitationModel.key.js -new file mode 100644 -index 000000000..c07ff03fa ---- /dev/null -+++ b/packages/shared/lib/models/userInvitationModel.key.js -@@ -0,0 +1 @@ -+export const UserInvitationModelKey = 'UserInvitations'; diff --git a/patches/protonmail/meta.json b/patches/protonmail/meta.json index fdc76b60c..8277c07a0 100644 --- a/patches/protonmail/meta.json +++ b/patches/protonmail/meta.json @@ -1,65 +1,67 @@ { "proton-mail": [ - "common-4.patch", - "drop-circular-dependency.patch", - "url-4.patch", + "common-5.patch", + "drop-circular-dependency-2.patch", + "url-5.patch", "constants-10.patch", - "sentry-12.patch", - "pack-api-arg-4.patch", - "pack-webpack-6.patch", + "sentry-15.patch", + "pack-api-arg-5.patch", + "pack-webpack-8.patch", "session-storage-5.patch", "link-handler-7.patch", "embedded-verification-3.patch", "proton-mail.patch" ], "proton-account": [ - "common-4.patch", + "common-6.patch", "drop-circular-dependency-2.patch", - "url-4.patch", + "url-6.patch", "constants-10.patch", - "sentry-12.patch", - "pack-api-arg-4.patch", - "pack-webpack-6.patch", + "sentry-16.patch", + "pack-api-arg-5.patch", + "pack-webpack-9.patch", "session-storage-5.patch", "link-handler-7.patch", "embedded-verification-3.patch", "proton-account.patch" ], "proton-calendar": [ - "common-4.patch", - "drop-circular-dependency.patch", - "url-4.patch", + "common-5.patch", + "drop-circular-dependency-2.patch", + "url-5.patch", "constants-10.patch", - "sentry-12.patch", - "pack-api-arg-4.patch", - "pack-webpack-6.patch", + "sentry-15.patch", + "pack-api-arg-5.patch", + "pack-webpack-8.patch", "session-storage-5.patch", "link-handler-7.patch", - "embedded-verification-3.patch" + "embedded-verification-3.patch", + "proton-calendar.patch" ], "proton-drive": [ - "common-4.patch", - "drop-circular-dependency.patch", - "url-4.patch", + "common-6.patch", + "drop-circular-dependency-2.patch", + "url-6.patch", "constants-10.patch", - "sentry-12.patch", - "pack-api-arg-4.patch", - "pack-webpack-6.patch", + "sentry-15.patch", + "pack-api-arg-5.patch", + "pack-webpack-8.patch", "session-storage-5.patch", "link-handler-7.patch", "embedded-verification-3.patch", "proton-drive.patch" ], "proton-vpn-settings": [ - "common-4.patch", + "common-6.patch", "drop-circular-dependency-2.patch", - "url-4.patch", + "url-6.patch", "constants-10.patch", - "sentry-12.patch", - "pack-api-arg-4.patch", - "pack-webpack-6.patch", + "sentry-16.patch", + "pack-api-arg-5.patch", + "pack-webpack-9.patch", "session-storage-5.patch", "link-handler-7.patch", - "embedded-verification-3.patch" + "embedded-verification-3.patch", + "proton-vpn-settings.patch" ] } diff --git a/patches/protonmail/pack-api-arg-4.patch b/patches/protonmail/pack-api-arg-5.patch similarity index 78% rename from patches/protonmail/pack-api-arg-4.patch rename to patches/protonmail/pack-api-arg-5.patch index 3a567ba8a..3eb65783d 100644 --- a/patches/protonmail/pack-api-arg-4.patch +++ b/patches/protonmail/pack-api-arg-5.patch @@ -1,13 +1,13 @@ diff --git a/packages/pack/lib/config.js b/packages/pack/lib/config.js -index b6484f719..a8ebc7fc0 100644 +index 5bb7fe50df..ff19c4f032 100644 --- a/packages/pack/lib/config.js +++ b/packages/pack/lib/config.js -@@ -129,7 +129,7 @@ const getConfigFile = ({ buildData, appData }) => { +@@ -131,7 +131,7 @@ const getConfigFile = ({ buildData, appData }) => { export const BRANCH = '${buildData.branch}'; export const DATE_VERSION = '${buildData.date}'; export const APP_NAME = '${appData.appName}'; - export const API_URL = '${(!appData.apiProxy && appData.api) || '/api'}'; + export const API_URL = '${appData.api}'; + export const SSO_URL = '${appData.sso || ''}'; export const LOCALES = ${JSON.stringify(LOCALES)}; export const VERSION_PATH = '${appData.publicPath}assets/version.json'; - export const SENTRY_DSN = '${appData.sentryDsn}'; diff --git a/patches/protonmail/pack-webpack-6.patch b/patches/protonmail/pack-webpack-6.patch deleted file mode 100644 index 6b0f2c9b4..000000000 --- a/patches/protonmail/pack-webpack-6.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/packages/pack/webpack.config.js b/packages/pack/webpack.config.js -index 9fdd56f70..3a7300257 100644 ---- a/packages/pack/webpack.config.js -+++ b/packages/pack/webpack.config.js -@@ -15,7 +15,7 @@ const getConfig = (env) => { - api: env.api, - appMode: env.appMode || 'standalone', - featureFlags: env.featureFlags || '', -- writeSRI: env.writeSri !== 'false', -+ writeSRI: false, - browserslist: isProduction - ? `> 0.5%, not IE 11, Firefox ESR, Safari 11` - : 'last 1 chrome version, last 1 firefox version, last 1 safari version', -@@ -33,7 +33,20 @@ const getConfig = (env) => { - logical: env.logical || false, - }; - -- return { -+ return (() => { -+ const file = path.resolve("./proton.config.js"); -+ if (require("fs").existsSync(file)) { -+ console.log( -+ /*reset:*/"\x1b[0m" + -+ /*yellow:*/"\x1b[33m" + -+ ">>>" + -+ /*reset:*/"\x1b[0m", + -+ `Found ${file}, extend the config`, -+ ) -+ return require(file); -+ } -+ return (value) => value; -+ })()({ - target: `browserslist:${options.browserslist}`, - mode: options.isProduction ? 'production' : 'development', - bail: options.isProduction, -@@ -120,7 +133,7 @@ const getConfig = (env) => { - }, - }), - }, -- }; -+ }); - }; - - module.exports = getConfig; diff --git a/patches/protonmail/pack-webpack-8.patch b/patches/protonmail/pack-webpack-8.patch new file mode 100644 index 000000000..436039980 --- /dev/null +++ b/patches/protonmail/pack-webpack-8.patch @@ -0,0 +1,51 @@ +diff --git a/packages/pack/webpack.config.ts b/packages/pack/webpack.config.ts +index 184720c4f9..e729826f79 100644 +--- a/packages/pack/webpack.config.ts ++++ b/packages/pack/webpack.config.ts +@@ -1,4 +1,5 @@ + import path from 'path'; ++import fs from 'fs'; + import webpack from 'webpack'; + import 'webpack-dev-server'; + // @ts-ignore +@@ -23,7 +24,7 @@ const getConfig = (env: any): webpack.Configuration => { + api: env.api, + appMode: env.appMode || 'standalone', + featureFlags: env.featureFlags || '', +- writeSRI: env.writeSri !== 'false', ++ writeSRI: false, + browserslist: isProduction + ? `> 0.5%, not IE 11, Firefox ESR, Safari 11` + : 'last 1 chrome version, last 1 firefox version, last 1 safari version', +@@ -44,7 +45,20 @@ const getConfig = (env: any): webpack.Configuration => { + + const version = options.buildData.version; + +- return { ++ return (() => { ++ const file = path.resolve("./proton.config.js"); ++ if (fs.existsSync(file)) { ++ console.log( ++ /*reset:*/"\x1b[0m" + ++ /*yellow:*/"\x1b[33m" + ++ ">>>" + ++ /*reset:*/"\x1b[0m", + ++ `Found ${file}, extend the config`, ++ ) ++ return eval("require")(file); ++ } ++ return (value: webpack.Configuration) => value; ++ })()({ + target: `browserslist:${options.browserslist}`, + mode: isProduction ? 'production' : 'development', + bail: isProduction, +@@ -162,7 +176,7 @@ const getConfig = (env: any): webpack.Configuration => { + ], + }), + }, +- }; ++ }); + }; + + export default getConfig; +-- diff --git a/patches/protonmail/pack-webpack-9.patch b/patches/protonmail/pack-webpack-9.patch new file mode 100644 index 000000000..49ca2df34 --- /dev/null +++ b/patches/protonmail/pack-webpack-9.patch @@ -0,0 +1,53 @@ +diff --git a/packages/pack/webpack.config.ts b/packages/pack/webpack.config.ts +index 3db6a71ef1..ed58652d81 100644 +--- a/packages/pack/webpack.config.ts ++++ b/packages/pack/webpack.config.ts +@@ -3,6 +3,7 @@ import { Configuration } from 'webpack'; + import 'webpack-dev-server'; + // @ts-ignore + import { parseResource } from 'webpack/lib/util/identifier'; ++import fs from 'fs'; + + const { getJsLoaders } = require('./webpack/js.loader'); + const getCssLoaders = require('./webpack/css.loader'); +@@ -23,7 +24,7 @@ const getConfig = (env: any): Configuration => { + api: env.api, + appMode: env.appMode || 'standalone', + featureFlags: env.featureFlags || '', +- writeSRI: env.writeSri !== 'false', ++ writeSRI: false, + browserslist: isProduction + ? `> 0.5%, not IE 11, Firefox ESR, Safari 11` + : 'last 1 chrome version, last 1 firefox version, last 1 safari version', +@@ -44,7 +45,20 @@ const getConfig = (env: any): Configuration => { + + const version = options.buildData.version; + +- return { ++ return ((): (value: Configuration) => Configuration => { ++ const file = path.resolve("./proton.config.js"); ++ if (fs.existsSync(file)) { ++ console.log( ++ /*reset:*/"\x1b[0m" + ++ /*yellow:*/"\x1b[33m" + ++ ">>>" + ++ /*reset:*/"\x1b[0m", + ++ `Found ${file}, extend the config`, ++ ) ++ return eval("require")(file); ++ } ++ return (value: Configuration) => value; ++ })()({ + target: `browserslist:${options.browserslist}`, + mode: isProduction ? 'production' : 'development', + bail: isProduction, +@@ -162,7 +176,7 @@ const getConfig = (env: any): Configuration => { + ], + }), + }, +- }; ++ }); + }; + + export default getConfig; + diff --git a/patches/protonmail/proton-account.patch b/patches/protonmail/proton-account.patch index 2046bee72..2c4dd3f73 100644 --- a/patches/protonmail/proton-account.patch +++ b/patches/protonmail/proton-account.patch @@ -1,3 +1,16 @@ +diff --git a/applications/account/package.json b/applications/account/package.json +index 3c5c6daff9..25828bb6b0 100644 +--- a/applications/account/package.json ++++ b/applications/account/package.json +@@ -6,7 +6,6 @@ + "author": "", + "main": "index.js", + "scripts": { +- "build": "cross-env NODE_ENV=production TS_NODE_PROJECT=\"../../tsconfig.webpack.json\" proton-pack build --appMode=sso", + "check-types": "tsc", + "i18n:upgrade": "proton-i18n extract --verbose && proton-i18n crowdin --verbose", + "i18n:validate": "proton-i18n validate lint-functions", + diff --git a/applications/account/src/app/Setup.tsx b/applications/account/src/app/Setup.tsx index 8f5e56ef0..a40d9dc17 100644 --- a/applications/account/src/app/Setup.tsx @@ -38,15 +51,15 @@ index 8f5e56ef0..a40d9dc17 100644 export default Setup; diff --git a/applications/account/src/app/content/MainContainer.tsx b/applications/account/src/app/content/MainContainer.tsx -index 32a57aa6d..472a7c9c9 100644 +index 575b59dcec..5e774e01a1 100644 --- a/applications/account/src/app/content/MainContainer.tsx +++ b/applications/account/src/app/content/MainContainer.tsx @@ -132,7 +132,7 @@ const MainContainer = () => { + const loadingFeatures = featuresFlags.some(({ loading }) => loading) || loadingDataRecovery; + const recoveryNotification = useRecoveryNotification(false); - useDeviceRecovery(); - -- const app = getAppFromPathnameSafe(location.pathname) || DEFAULT_APP; -+ const app = getAppFromPathnameSafe(window.location.pathname) || DEFAULT_APP; +- const appFromPathname = getAppFromPathnameSafe(location.pathname); ++ const appFromPathname = getAppFromPathnameSafe(window.location.pathname); + const app = appFromPathname || getToApp(undefined, user); const appSlug = getSlugFromApp(app); - /* diff --git a/patches/protonmail/proton-calendar.patch b/patches/protonmail/proton-calendar.patch new file mode 100644 index 000000000..ad43fc44f --- /dev/null +++ b/patches/protonmail/proton-calendar.patch @@ -0,0 +1,13 @@ +diff --git a/applications/calendar/package.json b/applications/calendar/package.json +index 6d44ef4129..8ff11b06cf 100644 +--- a/applications/calendar/package.json ++++ b/applications/calendar/package.json +@@ -6,7 +6,6 @@ + "author": "", + "main": "index.js", + "scripts": { +- "build": "cross-env NODE_ENV=production TS_NODE_PROJECT=\"../../tsconfig.webpack.json\" proton-pack build --appMode=sso", + "check-types": "tsc", + "i18n:upgrade": "proton-i18n extract --verbose && proton-i18n crowdin --verbose", + "i18n:validate": "proton-i18n validate lint-functions", + diff --git a/patches/protonmail/proton-drive.patch b/patches/protonmail/proton-drive.patch index 7808c17a7..f7eb1d749 100644 --- a/patches/protonmail/proton-drive.patch +++ b/patches/protonmail/proton-drive.patch @@ -1,3 +1,16 @@ +diff --git a/applications/drive/package.json b/applications/drive/package.json +index 1ff78a9928..d232854a68 100644 +--- a/applications/drive/package.json ++++ b/applications/drive/package.json +@@ -5,7 +5,6 @@ + "author": "", + "main": "index.ts", + "scripts": { +- "build": "cross-env NODE_ENV=production TS_NODE_PROJECT=\"../../tsconfig.webpack.json\" proton-pack build --appMode=sso", + "check-types": "tsc", + "i18n:getlatest": "proton-i18n upgrade", + "i18n:upgrade": "proton-i18n extract --verbose && proton-i18n crowdin -u --verbose", + diff --git a/applications/drive/src/app/store/_downloads/fileSaver/download.ts b/applications/drive/src/app/store/_downloads/fileSaver/download.ts index 7bef98525..0650e8019 100644 --- a/applications/drive/src/app/store/_downloads/fileSaver/download.ts @@ -14,14 +27,14 @@ index 7bef98525..0650e8019 100644 // initialize the download in the browser. The response has headers to diff --git a/applications/drive/src/app/store/_shares/shareUrl.ts b/applications/drive/src/app/store/_shares/shareUrl.ts -index 733cf9242..ab5781793 100644 +index 76b907e2a1..a267a2d50c 100644 --- a/applications/drive/src/app/store/_shares/shareUrl.ts +++ b/applications/drive/src/app/store/_shares/shareUrl.ts -@@ -40,6 +40,6 @@ export const getSharedLink = (sharedURL?: { +@@ -36,6 +36,6 @@ export const getSharedLink = (sharedURL?: { - const [generatedPassword] = splitGeneratedAndCustomPassword(sharedURL.Password, sharedURL); + const [generatedPassword] = splitGeneratedAndCustomPassword(sharedURL.password, sharedURL); -- const url = sharedURL.PublicUrl ? sharedURL.PublicUrl : `${window.location.origin}/urls/${sharedURL.Token}`; -+ const url = sharedURL.PublicUrl ? sharedURL.PublicUrl : `https://drive.protonmail.com/urls/${sharedURL.Token}`; +- const url = sharedURL.publicUrl ? sharedURL.publicUrl : `${window.location.origin}/urls/${sharedURL.token}`; ++ const url = sharedURL.publicUrl ? sharedURL.publicUrl : `https://drive.protonmail.com/urls/${sharedURL.token}`; return `${url}${generatedPassword !== '' ? `#${generatedPassword}` : ''}`; }; diff --git a/patches/protonmail/proton-mail.patch b/patches/protonmail/proton-mail.patch index 310b683c8..1b9f960ee 100644 --- a/patches/protonmail/proton-mail.patch +++ b/patches/protonmail/proton-mail.patch @@ -1,3 +1,16 @@ +diff --git a/applications/mail/package.json b/applications/mail/package.json +index 8087743d3a..ce4cf05ff1 100644 +--- a/applications/mail/package.json ++++ b/applications/mail/package.json +@@ -6,7 +6,6 @@ + "author": "", + "main": "index.js", + "scripts": { +- "build": "cross-env NODE_ENV=production TS_NODE_PROJECT=\"../../tsconfig.webpack.json\" proton-pack build --appMode=sso", + "check-types": "tsc", + "i18n:getlatest": "proton-i18n upgrade", + "i18n:upgrade": "proton-i18n extract --verbose && proton-i18n crowdin -u --verbose", + diff --git a/packages/shared/lib/api/events.ts b/packages/shared/lib/api/events.ts index 519a50349..819bdb911 100644 --- a/packages/shared/lib/api/events.ts @@ -15,17 +28,17 @@ index 519a50349..819bdb911 100644 }); diff --git a/applications/mail/src/app/containers/mailbox/MailboxContainer.tsx b/applications/mail/src/app/containers/mailbox/MailboxContainer.tsx -index 472046bb0..a818a7d21 100644 +index bbb73f6bc9..584e9324be 100644 --- a/applications/mail/src/app/containers/mailbox/MailboxContainer.tsx +++ b/applications/mail/src/app/containers/mailbox/MailboxContainer.tsx -@@ -304,6 +304,7 @@ const MailboxContainer = ({ +@@ -470,6 +470,7 @@ const MailboxContainer = ({ tabIndex={-1} className="flex-item-fluid flex flex-column flex-nowrap outline-none" data-testid="mailbox" + electron-mail-mailbox-container-component > - {showToolbar && ( - */ + + /** + * Sender public keys retrieved from API which can are not pinned + */ + senderPinnableKeys: PublicKeyReference[] | undefined; + ++ /* */ + /** * If the sender is in the list of contacts, whether its contact signature has been verified */ - senderVerified: boolean | undefined; + pinnedKeysVerified: boolean | undefined; + /* */ /** @@ -231,80 +253,6 @@ index 35d7a0aba..352f1c8a3 100644 export default useCache; -diff --git a/applications/mail/src/app/App.tsx b/applications/mail/src/app/App.tsx -index 50ae8f9a3..c79b724ee 100644 ---- a/applications/mail/src/app/App.tsx -+++ b/applications/mail/src/app/App.tsx -@@ -22,11 +22,6 @@ newVersionUpdater(config); - sentry({ config, uid: authentication.getUID(), sessionTracking: getSessionTrackingEnabled() }); - setVcalProdId(getProdId(config)); - --// If the browser is Chromium based, register automatically the mailto protocol handler --if ('chrome' in window) { -- registerMailToProtocolHandler(); --} -- - const App = () => { - const [hasInitialAuth] = useState(() => { - return !window.location.pathname.startsWith(G_OAUTH_REDIRECT_PATH); - -diff --git a/applications/mail/src/app/EOApp.tsx b/applications/mail/src/app/EOApp.tsx -index fa8ab5f17..2c5bd2d2c 100644 ---- a/applications/mail/src/app/EOApp.tsx -+++ b/applications/mail/src/app/EOApp.tsx -@@ -36,11 +36,6 @@ newVersionUpdater(config); - sentry({ config, sessionTracking: getSessionTrackingEnabled() }); - setVcalProdId(getProdId(config)); - --// If the browser is Chromium based, register automatically the mailto protocol handler --if ('chrome' in window) { -- registerMailToProtocolHandler(); --} -- - const App = () => { - const cacheRef = useRef>(); - if (!cacheRef.current) { - -diff --git a/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx b/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx -index bdabb99e0..a56b8cdcb 100644 ---- a/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx -+++ b/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx -@@ -4,13 +4,10 @@ import { Href } from '@proton/components/components/link'; - import { MAIL_APP_NAME } from '@proton/shared/lib/constants'; - import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url'; - --import { registerMailToProtocolHandler } from '../../helpers/url'; -- - const MailDefaultHandlerModal = (props: ModalProps) => { - const { onClose } = props; - - const handleAskForPermission = () => { -- registerMailToProtocolHandler(); - - onClose?.(); - }; - -diff --git a/applications/mail/src/app/components/header/MailHeader.tsx b/applications/mail/src/app/components/header/MailHeader.tsx -index d86dc9880..e75180b46 100644 ---- a/applications/mail/src/app/components/header/MailHeader.tsx -+++ b/applications/mail/src/app/components/header/MailHeader.tsx -@@ -38,7 +38,6 @@ import { setParamsInUrl } from '../../helpers/mailboxUrl'; - import { Breakpoints } from '../../models/utils'; - import MailOnboardingModal from '../onboarding/MailOnboardingModal'; - import ClearBrowserDataModal from './ClearBrowserDataModal'; --import MailDefaultHandlerModal from './MailDefaultHandlerModal'; - import MailSearch from './search/MailSearch'; - - interface Props { -@@ -192,7 +191,6 @@ const MailHeader = ({ labelID, elementID, breakpoints, expanded, onToggleExpand - - - -- - - - - diff --git a/applications/mail/src/app/helpers/url.ts b/applications/mail/src/app/helpers/url.ts index 2aaa779d3..487f54ff3 100644 --- a/applications/mail/src/app/helpers/url.ts @@ -328,22 +276,107 @@ index 2aaa779d3..487f54ff3 100644 + // NOOP }; +diff --git a/applications/mail/src/app/components/drawer/MailQuickSettings.tsx b/applications/mail/src/app/components/drawer/MailQuickSettings.tsx +index c0a72173cb..5baba25085 100644 +--- a/applications/mail/src/app/components/drawer/MailQuickSettings.tsx ++++ b/applications/mail/src/app/components/drawer/MailQuickSettings.tsx +@@ -31,7 +31,6 @@ import { useGetStartedChecklist } from 'proton-mail/containers/onboardingCheckli + + import { useEncryptedSearchContext } from '../../containers/EncryptedSearchProvider'; + import ClearBrowserDataModal from '../header/ClearBrowserDataModal'; +-import MailDefaultHandlerModal from '../header/MailDefaultHandlerModal'; + + interface QuickSettingsSelectOption { + value: any; +@@ -328,7 +327,6 @@ const MailQuickSettings = () => { + )} + + +- + + + + +diff --git a/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx b/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx +deleted file mode 100644 +index 0d29745777..0000000000 +--- a/applications/mail/src/app/components/header/MailDefaultHandlerModal.tsx ++++ /dev/null +@@ -1,41 +0,0 @@ +-import { c } from 'ttag'; +- +-import { Button, Href } from '@proton/atoms'; +-import { ModalProps, Prompt } from '@proton/components'; +-import { MAIL_APP_NAME } from '@proton/shared/lib/constants'; +-import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url'; +- +-import { registerMailToProtocolHandler } from '../../helpers/url'; +- +-const MailDefaultHandlerModal = (props: ModalProps) => { +- const { onClose } = props; +- +- const handleAskForPermission = () => { +- registerMailToProtocolHandler(); +- +- onClose?.(); +- }; +- +- return ( +- {c('Action').t`Set as default`}, +- , +- ]} +- {...props} +- > +- {c('Info') +- .t`Set ${MAIL_APP_NAME} as your default email application for this browser. ${MAIL_APP_NAME} will open automatically when you click an email link.`} +- +- {c('Info').t`Learn more`} +- +- +- ); +-}; +- +-export default MailDefaultHandlerModal; + diff --git a/applications/mail/src/app/components/header/search/MailSearch.tsx b/applications/mail/src/app/components/header/search/MailSearch.tsx -index 6318e40be..ebbce0086 100644 +index 1736085ad3..5f102e159e 100644 --- a/applications/mail/src/app/components/header/search/MailSearch.tsx +++ b/applications/mail/src/app/components/header/search/MailSearch.tsx -@@ -11,10 +11,7 @@ import { +@@ -3,7 +3,6 @@ import { useEffect, useState } from 'react'; + import { Location } from 'history'; + + import { +- FeatureCode, + TopNavbarListItemSearchButton, + generateUID, + useAddresses, +@@ -11,14 +10,11 @@ import { + useLabels, useMailSettings, usePopperAnchor, +- useProgressiveRollout, useToggle, - useUser, } from '@proton/components'; --import { isMobile } from '@proton/shared/lib/helpers/browser'; --import { isPaid } from '@proton/shared/lib/user/helpers'; import { ADVANCED_SEARCH_OVERLAY_CLOSE_EVENT } from '../../../constants'; import { useEncryptedSearchContext } from '../../../containers/EncryptedSearchProvider'; -@@ -40,7 +37,6 @@ const MailSearch = ({ breakpoints, labelID, location }: Props) => { +-import { isEncryptedSearchAvailable } from '../../../helpers/encryptedSearch/esUtils'; + import { extractSearchParameters } from '../../../helpers/mailboxUrl'; + import { useClickMailContent } from '../../../hooks/useClickMailContent'; + import { Breakpoints } from '../../../models/utils'; +@@ -39,11 +35,9 @@ interface Props { + + const MailSearch = ({ breakpoints, labelID, location, columnMode }: Props) => { + const [uid] = useState(generateUID('advanced-search-overlay')); +- const isESUserInterfaceAvailable = useProgressiveRollout(FeatureCode.ESUserInterface); const { anchorRef, isOpen, open, close } = usePopperAnchor(); const searchParams = extractSearchParameters(location); const [searchInputValue, setSearchInputValue] = useState(searchParams.keyword || ''); @@ -351,11 +384,11 @@ index 6318e40be..ebbce0086 100644 const [, loadingMailSettings] = useMailSettings(); const [, loadingLabels] = useLabels(); const [, loadingFolders] = useFolders(); -@@ -49,7 +45,7 @@ const MailSearch = ({ breakpoints, labelID, location }: Props) => { +@@ -51,7 +45,7 @@ const MailSearch = ({ breakpoints, labelID, location, columnMode }: Props) => { + const { getESDBStatus, cacheIndexedDB, closeDropdown } = useEncryptedSearchContext(); const { dropdownOpened } = getESDBStatus(); const esState = useEncryptedSearchToggleState(isOpen); - -- const showEncryptedSearch = !isMobile() && !!isPaid(user); +- const showEncryptedSearch = isEncryptedSearchAvailable(user, isESUserInterfaceAvailable); + const showEncryptedSearch = false; // Show more from inside AdvancedSearch to persist the state when the overlay is closed diff --git a/patches/protonmail/proton-vpn-settings.patch b/patches/protonmail/proton-vpn-settings.patch new file mode 100644 index 000000000..38319fc06 --- /dev/null +++ b/patches/protonmail/proton-vpn-settings.patch @@ -0,0 +1,60 @@ +diff --git a/applications/vpn-settings/package.json b/applications/vpn-settings/package.json +index 2232dbdee5..b12e610cf8 100644 +--- a/applications/vpn-settings/package.json ++++ b/applications/vpn-settings/package.json +@@ -6,7 +6,6 @@ + "author": "", + "main": "index.js", + "scripts": { +- "build": "cross-env NODE_ENV=production TS_NODE_PROJECT=\"../../tsconfig.webpack.json\" proton-pack build --appMode=standalone --logical", + "check-types": "tsc", + "i18n:upgrade": "proton-i18n extract --verbose && proton-i18n crowdin --verbose", + "i18n:validate": "proton-i18n validate lint-functions", + +diff --git a/packages/pack/webpack/css.loader.js b/packages/pack/webpack/css.loader.js +index 072d323cd4..4aed56dd87 100644 +--- a/packages/pack/webpack/css.loader.js ++++ b/packages/pack/webpack/css.loader.js +@@ -10,17 +10,22 @@ const handleUrlResolve = (url) => { + return true; + }; + ++// required by "resolve-url-loader", but get disabled by "disabling minimizing", so getting it back for styles ++const sourceMap = true; ++ + module.exports = ({ browserslist, logical }) => { + const sassLoaders = [ + { + loader: require.resolve('css-loader'), + options: { ++ sourceMap, + url: { filter: handleUrlResolve }, + }, + }, + { + loader: require.resolve('postcss-loader'), + options: { ++ sourceMap, + postcssOptions: { + plugins: [ + require('autoprefixer')({ +@@ -35,9 +40,11 @@ module.exports = ({ browserslist, logical }) => { + }, + { + loader: require.resolve('resolve-url-loader'), ++ options: {sourceMap}, + }, + { + loader: require.resolve('sass-loader'), ++ options: {sourceMap}, + }, + ].filter(Boolean); + +@@ -54,6 +61,7 @@ module.exports = ({ browserslist, logical }) => { + { + loader: require.resolve('css-loader'), + options: { ++ sourceMap, + importLoaders: 1, + url: { filter: handleUrlResolve }, + }, diff --git a/patches/protonmail/sentry-12.patch b/patches/protonmail/sentry-15.patch similarity index 58% rename from patches/protonmail/sentry-12.patch rename to patches/protonmail/sentry-15.patch index 8a8a8e851..a9b59f619 100644 --- a/patches/protonmail/sentry-12.patch +++ b/patches/protonmail/sentry-15.patch @@ -1,9 +1,10 @@ diff --git a/packages/shared/lib/helpers/sentry.ts b/packages/shared/lib/helpers/sentry.ts -index 731fc8566..6d6a3fb2a 100644 +index 503abd48a4..296afc18f4 100644 --- a/packages/shared/lib/helpers/sentry.ts +++ b/packages/shared/lib/helpers/sentry.ts -@@ -1,14 +1,9 @@ +@@ -1,15 +1,10 @@ import { + BrowserOptions, captureException, - configureScope, - init, @@ -17,7 +18,7 @@ index 731fc8566..6d6a3fb2a 100644 import { getUIDHeaders } from '../fetch/headers'; import { ProtonConfig } from '../interfaces'; -@@ -61,21 +56,6 @@ export const getContentTypeHeaders = (input: RequestInfo | URL): HeadersInit => +@@ -67,21 +62,6 @@ export const getContentTypeHeaders = (input: RequestInfo | URL): HeadersInit => return {}; }; @@ -39,10 +40,10 @@ index 731fc8566..6d6a3fb2a 100644 const isLocalhost = (host: string) => host.startsWith('localhost'); const isProduction = (host: string) => host.endsWith('.proton.me') || host === VPN_HOSTNAME; -@@ -94,143 +74,10 @@ function main({ - sessionTracking = false, - sentryConfig = getDefaultSentryConfig(config), +@@ -170,86 +150,10 @@ function main({ ignore = ({ host }) => isLocalhost(host), + denyUrls = getDefaultDenyUrls(), + ignoreErrors = getDefaultIgnoreErrors(), -}: SentryOptions) { - const { SENTRY_DSN, APP_VERSION } = config; - const { host, release, environment } = sentryConfig; @@ -77,8 +78,8 @@ index 731fc8566..6d6a3fb2a 100644 - return null; - } - -- // Not interested in uncaught API errors -- if (error instanceof ApiError) { +- // Not interested in uncaught API errors, or known errors +- if (error instanceof ApiError || error?.trace === false) { - return null; - } - @@ -105,65 +106,8 @@ index 731fc8566..6d6a3fb2a 100644 - }, - // Some ignoreErrors and denyUrls are taken from this gist: https://gist.github.com/Chocksy/e9b2cdd4afc2aadc7989762c4b8b495a - // This gist is suggested in the Sentry documentation: https://docs.sentry.io/clients/javascript/tips/#decluttering-sentry -- ignoreErrors: [ -- // Ignore random plugins/extensions -- 'top.GLOBALS', -- 'canvas.contentDocument', -- 'MyApp_RemoveAllHighlights', -- 'atomicFindClose', -- // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx -- 'conduitPage', -- // https://bugzilla.mozilla.org/show_bug.cgi?id=1678243 -- 'XDR encoding failure', -- 'Request timed out', -- 'No network connection', -- 'Failed to fetch', -- 'NetworkError when attempting to fetch resource.', -- 'webkitExitFullScreen', // Bug in Firefox for iOS. -- 'InactiveSession', -- 'UnhandledRejection', // Happens too often in extensions and we have lints for that, so should be safe to ignore. -- /chrome-extension/, -- /moz-extension/, -- 'TransferCancel', // User action to interrupt upload or download in Drive. -- 'UploadConflictError', // User uploading the same file again in Drive. -- 'UploadUserError', // Upload error on user's side in Drive. -- 'ValidationError', // Validation error on user's side in Drive. -- 'ChunkLoadError', // WebPack loading source code. -- /ResizeObserver loop/, // Chromium bug https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded -- // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html -- 'originalCreateNotification', -- 'http://tt.epicplay.com', -- "Can't find variable: ZiteReader", -- 'jigsaw is not defined', -- 'ComboSearch is not defined', -- 'http://loading.retry.widdit.com/', -- // Facebook borked -- 'fb_xd_fragment', -- // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha) -- // See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy -- 'bmi_SafeAddOnload', -- 'EBCallBackMessageReceived', -- // Avast extension error -- '_avast_submit', -- ], -- denyUrls: [ -- // Google Adsense -- /pagead\/js/i, -- // Facebook flakiness -- /graph\.facebook\.com/i, -- // Facebook blocked -- /connect\.facebook\.net\/en_US\/all\.js/i, -- // Woopra flakiness -- /eatdifferent\.com\.woopra-ns\.com/i, -- /static\.woopra\.com\/js\/woopra\.js/i, -- // Chrome extensions -- /extensions\//i, -- /^chrome:\/\//i, -- // Other plugins -- /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb -- /webappstoolbarba\.texthelp\.com\//i, -- /metrics\.itunes\.apple\.com\.edgesuite\.net\//i, -- ], +- ignoreErrors, +- denyUrls, - }); - - configureScope((scope) => { @@ -186,3 +130,4 @@ index 731fc8566..6d6a3fb2a 100644 +export const captureMessage = (...args: Parameters) => console.log(...args); export default main; +-- diff --git a/patches/protonmail/sentry-16.patch b/patches/protonmail/sentry-16.patch new file mode 100644 index 000000000..63abd1954 --- /dev/null +++ b/patches/protonmail/sentry-16.patch @@ -0,0 +1,140 @@ +diff --git a/packages/shared/lib/helpers/sentry.ts b/packages/shared/lib/helpers/sentry.ts +index 952bbe2061..8186ab1afc 100644 +--- a/packages/shared/lib/helpers/sentry.ts ++++ b/packages/shared/lib/helpers/sentry.ts +@@ -1,16 +1,9 @@ + import { + BrowserOptions, +- Integrations as SentryIntegrations, + captureException, +- configureScope, +- init, +- makeFetchTransport, +- captureMessage as sentryCaptureMessage, + } from '@sentry/browser'; +-import { BrowserTransportOptions } from '@sentry/browser/types/transports/types'; + + import { VPN_HOSTNAME } from '../constants'; +-import { ApiError } from '../fetch/ApiError'; + import { getUIDHeaders } from '../fetch/headers'; + import { ProtonConfig } from '../interfaces'; + +@@ -68,21 +61,6 @@ export const getContentTypeHeaders = (input: RequestInfo | URL): HeadersInit => + return {}; + }; + +-const sentryFetch = (input: RequestInfo | URL, init?: RequestInit) => { +- return globalThis.fetch(input, { +- ...init, +- headers: { +- ...init?.headers, +- ...getContentTypeHeaders(input), +- ...context.authHeaders, +- }, +- }); +-}; +- +-const makeProtonFetchTransport = (options: BrowserTransportOptions) => { +- return makeFetchTransport(options, sentryFetch); +-}; +- + const isLocalhost = (host: string) => host.startsWith('localhost'); + const isProduction = (host: string) => host.endsWith('.proton.me') || host === VPN_HOSTNAME; + +@@ -171,92 +149,10 @@ function main({ + ignore = ({ host }) => isLocalhost(host), + denyUrls = getDefaultDenyUrls(), + ignoreErrors = getDefaultIgnoreErrors(), +-}: SentryOptions) { +- const { SENTRY_DSN, APP_VERSION } = config; +- const { host, release, environment } = sentryConfig; +- +- // No need to configure it if we don't load the DSN +- if (!SENTRY_DSN || ignore(sentryConfig)) { +- return; +- } +- +- setUID(uid); +- +- // Assumes SENTRY_DSN is: https://111b3eeaaec34cae8e812df705690a36@sentry/11 +- // To get https://111b3eeaaec34cae8e812df705690a36@protonmail.com/api/core/v4/reports/sentry/11 +- const dsn = SENTRY_DSN.replace('sentry', `${host}/api/core/v4/reports/sentry`); +- +- init({ +- dsn, +- release, +- environment, +- normalizeDepth: 5, +- transport: makeProtonFetchTransport, +- autoSessionTracking: sessionTracking, +- // do not log calls to console.log, console.error, etc. +- integrations: [ +- new SentryIntegrations.Breadcrumbs({ +- console: false, +- }), +- ], +- // Disable client reports. Client reports are used by sentry to retry events that failed to send on visibility change. +- // Unfortunately Sentry does not use the custom transport for those, and thus fails to add the headers the API requires. +- sendClientReports: false, +- beforeSend(event, hint) { +- const error = hint?.originalException as any; +- const stack = typeof error === 'string' ? error : error?.stack; +- // Filter out broken ferdi errors +- if (stack && stack.match(/ferdi|franz/i)) { +- return null; +- } ++}: SentryOptions) {} + +- // Not interested in uncaught API errors, or known errors +- if (error instanceof ApiError || error?.trace === false) { +- return null; +- } ++export const traceError = (...args: Parameters) => console.error(...args); + +- if (!context.enabled) { +- return null; +- } +- +- // Remove the hash from the request URL and navigation breadcrumbs to avoid +- // leaking the search parameters of encrypted searches +- if (event.request && event.request.url) { +- [event.request.url] = event.request.url.split('#'); +- } +- if (event.breadcrumbs) { +- event.breadcrumbs = event.breadcrumbs.map((breadcrumb) => { +- if (breadcrumb.category === 'navigation' && breadcrumb.data) { +- [breadcrumb.data.from] = breadcrumb.data.from.split('#'); +- [breadcrumb.data.to] = breadcrumb.data.to.split('#'); +- } +- return breadcrumb; +- }); +- } +- +- return event; +- }, +- // Some ignoreErrors and denyUrls are taken from this gist: https://gist.github.com/Chocksy/e9b2cdd4afc2aadc7989762c4b8b495a +- // This gist is suggested in the Sentry documentation: https://docs.sentry.io/clients/javascript/tips/#decluttering-sentry +- ignoreErrors, +- denyUrls, +- }); +- +- configureScope((scope) => { +- scope.setTag('appVersion', APP_VERSION); +- }); +-} +- +-export const traceError = (...args: Parameters) => { +- if (!isLocalhost(window.location.host)) { +- captureException(...args); +- } +-}; +- +-export const captureMessage = (...args: Parameters) => { +- if (!isLocalhost(window.location.host)) { +- sentryCaptureMessage(...args); +- } +-}; ++export const captureMessage = (...args: Parameters) => console.log(...args); + + export default main; +-- diff --git a/patches/protonmail/url-4.patch b/patches/protonmail/url-5.patch similarity index 87% rename from patches/protonmail/url-4.patch rename to patches/protonmail/url-5.patch index f294f7cd6..201d51850 100644 --- a/patches/protonmail/url-4.patch +++ b/patches/protonmail/url-5.patch @@ -1,8 +1,8 @@ diff --git a/packages/shared/lib/helpers/url.ts b/packages/shared/lib/helpers/url.ts -index 11cd310f6..8019c07f5 100644 +index 0c21c0f042..8ccd5ce82b 100644 --- a/packages/shared/lib/helpers/url.ts +++ b/packages/shared/lib/helpers/url.ts -@@ -175,48 +175,16 @@ export const getSecondLevelDomain = (hostname: string) => { +@@ -183,48 +183,16 @@ export const getSecondLevelDomain = (hostname: string) => { return hostname.slice(hostname.indexOf('.') + 1); }; @@ -51,13 +51,13 @@ index 11cd310f6..8019c07f5 100644 - let cache = ''; export const getStaticURL = (path: string) => { - if (window.location.hostname === 'localhost' || getIsDohDomain(window.location.origin)) { + if ( diff --git a/packages/shared/lib/fetch/helpers.ts b/packages/shared/lib/fetch/helpers.ts -index f0b3e2e31..90995e1fc 100644 +index 666b9f56c6..246f0e03b4 100644 --- a/packages/shared/lib/fetch/helpers.ts +++ b/packages/shared/lib/fetch/helpers.ts -@@ -10,6 +10,7 @@ const appendQueryParams = (url: URL, params: { [key: string]: any }) => { +@@ -11,6 +11,7 @@ const appendQueryParams = (url: URL, params: { [key: string]: any }) => { }); }; @@ -65,7 +65,7 @@ index f0b3e2e31..90995e1fc 100644 export const createUrl = (urlString: string, params: { [key: string]: any } = {}) => { let url: URL; if (typeof window !== 'undefined') { -@@ -20,6 +21,7 @@ export const createUrl = (urlString: string, params: { [key: string]: any } = {} +@@ -21,6 +22,7 @@ export const createUrl = (urlString: string, params: { [key: string]: any } = {} appendQueryParams(url, params); return url; }; diff --git a/patches/protonmail/url-6.patch b/patches/protonmail/url-6.patch new file mode 100644 index 000000000..76eb1073e --- /dev/null +++ b/patches/protonmail/url-6.patch @@ -0,0 +1,90 @@ +diff --git a/packages/shared/lib/helpers/url.ts b/packages/shared/lib/helpers/url.ts +index 576f743891..1105a2ae62 100644 +--- a/packages/shared/lib/helpers/url.ts ++++ b/packages/shared/lib/helpers/url.ts +@@ -185,63 +185,16 @@ export const getSecondLevelDomain = (hostname: string) => { + return hostname.slice(hostname.indexOf('.') + 1); + }; + +-export const getRelativeApiHostname = (hostname: string) => { +- const idx = hostname.indexOf('.'); +- const first = hostname.slice(0, idx); +- const second = hostname.slice(idx + 1); +- return `${first}-api.${second}`; +-}; +- + export const getIsDohDomain = (origin: string) => { + return DOH_DOMAINS.some((dohDomain) => origin.endsWith(dohDomain)); + }; + +-const doesHostnameLookLikeIP = (hostname: string) => { +- // Quick helper function to tells us if hostname string seems to be IP address or DNS name. +- // Relies on a fact, that no TLD ever will probably end with a digit. So if last char is +- // a digit, it's probably an IP. +- // IPv6 addresses can end with a letter, so there's additional colon check also. +- // Probably no need ever to use slow & complicated IP regexes here, but feel free to change +- // whenever we have such util functions available. +- // Note: only works on hostnames (no port), not origins (can include port and protocol). +- return /\d$/.test(hostname) || hostname.includes(':'); +-}; +- + export const getApiSubdomainUrl = (pathname: string) => { +- const url = new URL('', window.location.origin); +- +- const usePathPrefix = +- url.hostname === 'localhost' || getIsDohDomain(url.origin) || doesHostnameLookLikeIP(url.hostname); +- if (usePathPrefix) { +- url.pathname = `/api${pathname}`; +- return url; +- } +- +- url.hostname = getRelativeApiHostname(url.hostname); ++ const url = new URL('/', '___ELECTRON_MAIL_PROTON_API_ENTRY_URL_PLACEHOLDER___'); + url.pathname = pathname; + return url; + }; + +-export const getAppUrlFromApiUrl = (apiUrl: string, appName: APP_NAMES) => { +- const { subdomain } = APPS_CONFIGURATION[appName]; +- const url = new URL(apiUrl); +- const { hostname } = url; +- const index = hostname.indexOf('.'); +- const tail = hostname.slice(index + 1); +- url.pathname = ''; +- url.hostname = `${subdomain}.${tail}`; +- return url; +-}; +- +-export const getAppUrlRelativeToOrigin = (origin: string, appName: APP_NAMES) => { +- const { subdomain } = APPS_CONFIGURATION[appName]; +- const url = new URL(origin); +- const segments = url.host.split('.'); +- segments[0] = subdomain; +- url.hostname = segments.join('.'); +- return url; +-}; +- + let cache = ''; + export const getStaticURL = (path: string) => { + if ( + +diff --git a/packages/shared/lib/fetch/helpers.ts b/packages/shared/lib/fetch/helpers.ts +index 666b9f56c6..246f0e03b4 100644 +--- a/packages/shared/lib/fetch/helpers.ts ++++ b/packages/shared/lib/fetch/helpers.ts +@@ -11,6 +11,7 @@ const appendQueryParams = (url: URL, params: { [key: string]: any }) => { + }); + }; + ++/* */ + export const createUrl = (urlString: string, params: { [key: string]: any } = {}) => { + let url: URL; + if (typeof window !== 'undefined') { +@@ -21,6 +22,7 @@ export const createUrl = (urlString: string, params: { [key: string]: any } = {} + appendQueryParams(url, params); + return url; + }; ++/* */ + + export const checkStatus = (response: Response, config: any) => { + const { status } = response; diff --git a/scripts/prepare-webclient/webclients.ts b/scripts/prepare-webclient/webclients.ts index 43ca01a23..eaabfaad7 100644 --- a/scripts/prepare-webclient/webclients.ts +++ b/scripts/prepare-webclient/webclients.ts @@ -35,22 +35,21 @@ async function configure( function resolveWebpackConfigPatchingCode( { webpackConfigVarName, - repoType, webpackIndexEntryItems, }: { webpackConfigVarName: string - repoType: keyof typeof PROVIDER_REPO_MAP, webpackIndexEntryItems?: unknown, }, ): string { const disableMangling = Boolean(webpackIndexEntryItems); + const disableMinimizing = true; // disable compression to workaround "heap out of memory" issue of the "github actions" job const result = ` ${webpackConfigVarName}.devtool = false; Object.assign( ${webpackConfigVarName}.optimization, { - minimize: ${!disableMangling /* eslint-disable-line @typescript-eslint/restrict-template-expressions */}, + minimize: ${!disableMinimizing /* eslint-disable-line @typescript-eslint/restrict-template-expressions */}, moduleIds: "named", // allows resolving individual modules from "window.webpackJsonp" @@ -81,20 +80,19 @@ function resolveWebpackConfigPatchingCode( if (!terserPluginInstance) { throw new Error("TerserPlugin instance resolving failed"); } - // terserPluginInstance.options.minify = false; + terserPluginInstance.options.minify = false; terserPluginInstance.options.parallel = false; - Object.assign( - ${repoType === "proton-drive" || repoType === "proton-vpn-settings" - ? 'terserPluginInstance.options.terserOptions' - : 'terserPluginInstance.options.minimizer.options'}, - { - // proton v4: needed to preserve original function names - // just "{keep_fnames: true, mangle: false}" is not sufficient - ...({keep_fnames: true, compress: false}), - }, - ); + const minimizerOptions = { + // proton v4: needed to preserve original function names + // just "{keep_fnames: true, mangle: false}" is not sufficient + ...({keep_fnames: true, compress: false}), + }; + [ + terserPluginInstance.options.terserOptions ?? (terserPluginInstance.options.terserOptions = {}), + (terserPluginInstance.options.minimizer ?? (terserPluginInstance.options.minimizer = {options: {}})), + ].forEach((value) => Object.assign(value, minimizerOptions)); ` - : `delete ${webpackConfigVarName}.optimization.minimizer;`} + : (disableMinimizing ? `${webpackConfigVarName}.optimization.minimizer = [];` : ``)} ${webpackIndexEntryItems ? `{ @@ -276,7 +274,7 @@ async function executeBuildFlow( ? `/${PROVIDER_REPO_MAP[repoType].basePath}/` : undefined; - if (repoType === "proton-mail" || repoType === "proton-calendar") { + { const webpackIndexEntryItems = repoType === "proton-mail" || repoType === "proton-calendar" ? PROVIDER_REPO_MAP[repoType].protonPack.webpackIndexEntryItems : undefined; @@ -289,7 +287,6 @@ async function executeBuildFlow( ${ resolveWebpackConfigPatchingCode({ webpackConfigVarName: "webpackConfig", - repoType, webpackIndexEntryItems, }) } @@ -325,6 +322,7 @@ async function executeBuildFlow( ...process.env, ...(publicPath && {PUBLIC_PATH: publicPath}), NODE_ENV: "production", + TS_NODE_PROJECT: "../../tsconfig.webpack.json", // picked "build" task of "applications//package.json" }, }, ], diff --git a/src/electron-preload/webview/primary/provider-api/index.ts b/src/electron-preload/webview/primary/provider-api/index.ts index 5e11119d3..7d5e483b5 100644 --- a/src/electron-preload/webview/primary/provider-api/index.ts +++ b/src/electron-preload/webview/primary/provider-api/index.ts @@ -208,7 +208,7 @@ export const initProviderApi = async (): Promise => { ): NoExtraProps => { const result = { senderPinnedKeys: encryptionPreferences.pinnedKeys, - senderVerified: Boolean(encryptionPreferences.isContactSignatureVerified), + pinnedKeysVerified: Boolean(encryptionPreferences.isContactSignatureVerified), } as const; // this proxy helps early detecting unexpected/not-yet-reviewed protonmail's "getDecryptedAttachment" behaviour // if/likely-when the behaviour gets changed by protonmail diff --git a/src/electron-preload/webview/primary/provider-api/model.ts b/src/electron-preload/webview/primary/provider-api/model.ts index 87a73c1e1..8645b0218 100644 --- a/src/electron-preload/webview/primary/provider-api/model.ts +++ b/src/electron-preload/webview/primary/provider-api/model.ts @@ -196,7 +196,7 @@ export interface MessageKeys { export interface MessageVerification { senderPinnedKeys: EncryptionPreferences["pinnedKeys"] | undefined; - senderVerified: boolean | undefined; + pinnedKeysVerified: boolean | undefined; } export type MessageExtended = NoExtraProps<{ diff --git a/src/shared/const/proton-apps.ts b/src/shared/const/proton-apps.ts index e27c6359a..12514cb22 100644 --- a/src/shared/const/proton-apps.ts +++ b/src/shared/const/proton-apps.ts @@ -23,7 +23,7 @@ export const PROVIDER_REPO_MAP = { basePath: "", apiSubdomain: "mail-api", repoRelativeDistDir: "./dist", - tag: "proton-mail@5.0.22.7", + tag: "proton-mail@5.0.28.10", protonPack: { webpackIndexEntryItems: [ // immediate @@ -49,14 +49,14 @@ export const PROVIDER_REPO_MAP = { basePath: "account", apiSubdomain: "account-api", repoRelativeDistDir: "./dist", - tag: "proton-account@5.0.31.3", + tag: "proton-account@5.0.52.0", protonPack: {} }, [PROVIDER_APP_NAMES[2]]: { basePath: "calendar", apiSubdomain: "calendar-api", repoRelativeDistDir: "./dist", - tag: "proton-calendar@5.0.10.15", + tag: "proton-calendar@5.0.14.6", protonPack: { webpackIndexEntryItems: [ // immediate @@ -69,14 +69,14 @@ export const PROVIDER_REPO_MAP = { basePath: "drive", apiSubdomain: "drive-api", repoRelativeDistDir: "./dist", - tag: "proton-drive@5.0.13.8", + tag: "proton-drive@5.0.15.3", protonPack: {}, }, [PROVIDER_APP_NAMES[4]]: { basePath: "account/vpn", apiSubdomain: "account-api", repoRelativeDistDir: "./dist", - tag: "proton-vpn-settings@5.0.30.2", + tag: "proton-vpn-settings@5.0.48.1", protonPack: {}, }, } as const;