Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cherrypick: v11.15.4 reset streams on prerender only for affected browser versions #24332

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [11.15.4]

## [11.15.3]
### Changed
- Smart transaction improvements ([#24340](https://github.com/MetaMask/metamask-extension/pull/24340))
Expand Down Expand Up @@ -4688,7 +4690,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c
- Added the ability to restore accounts from seed words.


[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.15.3...HEAD
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.15.4...HEAD
[11.15.4]: https://github.com/MetaMask/metamask-extension/compare/v11.15.3...v11.15.4
[11.15.3]: https://github.com/MetaMask/metamask-extension/compare/v11.15.2...v11.15.3
[11.15.2]: https://github.com/MetaMask/metamask-extension/compare/v11.15.1...v11.15.2
[11.15.1]: https://github.com/MetaMask/metamask-extension/compare/v11.15.0...v11.15.1
Expand Down
11 changes: 5 additions & 6 deletions app/scripts/contentscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import pump from 'pump';
import { obj as createThoughStream } from 'through2';
import browser from 'webextension-polyfill';
import { EXTENSION_MESSAGES } from '../../shared/constants/app';
import { checkForLastError } from '../../shared/modules/browser-runtime.utils';
import {
checkForLastError,
getIsBrowserPrerenderBroken,
} from '../../shared/modules/browser-runtime.utils';
import { isManifestV3 } from '../../shared/modules/mv3.utils';
import shouldInjectProvider from '../../shared/modules/provider-injection';

Expand Down Expand Up @@ -519,11 +522,7 @@ const start = () => {
if (shouldInjectProvider()) {
initStreams();

// https://bugs.chromium.org/p/chromium/issues/detail?id=1457040
// Temporary workaround for chromium bug that breaks the content script <=> background connection
// for prerendered pages. This resets potentially broken extension streams if a page transitions
// from the prerendered state to the active state.
if (document.prerendering) {
if (document.prerendering && getIsBrowserPrerenderBroken()) {
document.addEventListener('prerenderingchange', () => {
onDisconnectDestroyStreams(
new Error('Prerendered page has become active.'),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "metamask-crx",
"version": "11.15.3",
"version": "11.15.4",
"private": true,
"repository": {
"type": "git",
Expand Down
23 changes: 23 additions & 0 deletions shared/modules/browser-runtime.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
* Utility Functions to support browser.runtime JavaScript API
*/

import Bowser from 'bowser';
import browser from 'webextension-polyfill';
import log from 'loglevel';
import {
BROKEN_PRERENDER_BROWSER_VERSIONS,
FIXED_PRERENDER_BROWSER_VERSIONS,
} from '../../ui/helpers/constants/common';

/**
* Returns an Error if extension.runtime.lastError is present
Expand Down Expand Up @@ -53,3 +58,21 @@ export function checkForLastErrorAndWarn() {

return error;
}

/**
* Returns true if the browser is affected by a regression that causes the
* extension port stream established between the contentscript and background
* to be broken when a prerendered (eagerly rendered, hidden) page becomes active (visible to the user).
*
* @param {Bowser} bowser - optional Bowser instance to check against
* @returns {boolean} Whether the browser is affected by the prerender regression
*/
export function getIsBrowserPrerenderBroken(
bowser = Bowser.getParser(window.navigator.userAgent),
) {
return (
(bowser.satisfies(BROKEN_PRERENDER_BROWSER_VERSIONS) &&
!bowser.satisfies(FIXED_PRERENDER_BROWSER_VERSIONS)) ??
false
);
}
98 changes: 98 additions & 0 deletions shared/modules/browser-runtime.utils.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import sinon from 'sinon';
import Bowser from 'bowser';
import browser from 'webextension-polyfill';
import log from 'loglevel';
import * as BrowserRuntimeUtil from './browser-runtime.utils';
Expand Down Expand Up @@ -51,4 +52,101 @@ describe('Browser Runtime Utils', () => {
log.error.restore();
});
});

describe('getIsBrowserPrerenderBroken', () => {
it('should call Bowser.getParser when no parameter is passed', () => {
const spy = jest.spyOn(Bowser, 'getParser');
BrowserRuntimeUtil.getIsBrowserPrerenderBroken();
expect(spy).toHaveBeenCalled();
});
it.each([
['windows', '112.0.0.0', 'Windows NT 10.0; Win64; x64'],
['windows', '120.0.0.0', 'Windows NT 10.0; Win64; x64'],
['macos', '112.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['macos', '120.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['linux', '112.0.0.0', 'X11; Linux x86_64'],
['linux', '121.0.0.0', 'X11; Linux x86_64'],
])(
'should return false when given a chrome browser with working prerender in %s on version %s',
(_, version, os) => {
const bowser = Bowser.getParser(
`Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`,
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(false);
},
);
it.each([
['windows', '113.0.0.0', 'Windows NT 10.0; Win64; x64'],
['windows', '119.0.0.0', 'Windows NT 10.0; Win64; x64'],
['macos', '113.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['macos', '119.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['linux', '113.0.0.0', 'X11; Linux x86_64'],
['linux', '120.0.0.0', 'X11; Linux x86_64'],
])(
'should return true when given a chrome browser with broken prerender in %s on version %s',
(_, version, os) => {
const bowser = Bowser.getParser(
`Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`,
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(true);
},
);
it.each([
['windows', '112.0.0.0', 'Windows NT 10.0; Win64; x64'],
['windows', '120.0.0.0', 'Windows NT 10.0; Win64; x64'],
['macos', '112.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['macos', '120.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['linux', '112.0.0.0', 'X11; Linux x86_64'],
['linux', '121.0.0.0', 'X11; Linux x86_64'],
])(
'should return false when given an edge browser with working prerender in %s on version %s',
(_, version, os) => {
const bowser = Bowser.getParser(
`Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/i${version} Safari/537.36 Edg/${version}`,
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(false);
},
);
it.each([
['windows', '113.0.0.0', 'Windows NT 10.0; Win64; x64'],
['windows', '119.0.0.0', 'Windows NT 10.0; Win64; x64'],
['macos', '113.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['macos', '119.0.0.0', 'Macintosh; Intel Mac OS X 10_16_0'],
['linux', '113.0.0.0', 'X11; Linux x86_64'],
['linux', '120.0.0.0', 'X11; Linux x86_64'],
])(
'should return true when given an edge browser with broken prerender in %s on version %s',
(_, version, os) => {
const bowser = Bowser.getParser(
`Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/i${version} Safari/537.36 Edg/${version}`,
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(true);
},
);
it('should return false when given a firefox browser', () => {
const bowser = Bowser.getParser(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/91.0',
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(false);
});
it('should return false when given an opera browser', () => {
const bowser = Bowser.getParser(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.3578.98 Safari/537.36 OPR/76.0.3135.47',
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(false);
});
it('should return false when given an unknown browser', () => {
const bowser = Bowser.getParser(
'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/609.4 (KHTML, like Gecko) NF/6.0.2.21.3 NintendoBrowser/5.1.0.22474',
);
const result = BrowserRuntimeUtil.getIsBrowserPrerenderBroken(bowser);
expect(result).toStrictEqual(false);
});
});
});
34 changes: 34 additions & 0 deletions ui/helpers/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,37 @@ export const OUTDATED_BROWSER_VERSIONS = {
// See https://en.wikipedia.org/wiki/History_of_the_Opera_web_browser
opera: '<76',
};

/**
* Specifies the browser and their versions where a regression in the extension port
* stream established between the contentscript and background was breaking for
* prerendered pages.
*
* @see {@link https://issues.chromium.org/issues/40273420}
*/
export const BROKEN_PRERENDER_BROWSER_VERSIONS = {
chrome: '>=113',
edge: '>=113',
};

/**
* Specifies the browser and their versions on a specific OS where a fix for the
* prerender regression specified in BROKEN_PRERENDER_BROWSER_VERSIONS was resolved.
*
* @see {@link https://chromium.googlesource.com/chromium/src/+/a88eee8a2798c1dc4d69b255ccad24fea5ff2d8b}
*/
export const FIXED_PRERENDER_BROWSER_VERSIONS = {
// https://chromiumdash.appspot.com/commits?commit=a88eee8a2798c1dc4d69b255ccad24fea5ff2d8b&platform=Windows
windows: {
chrome: '>=120',
edge: '>=120',
},
// https://chromiumdash.appspot.com/commits?commit=a88eee8a2798c1dc4d69b255ccad24fea5ff2d8b&platform=Mac
macos: {
chrome: '>=120',
edge: '>=120',
},
// https://chromiumdash.appspot.com/commits?commit=a88eee8a2798c1dc4d69b255ccad24fea5ff2d8b&platform=Linux
chrome: '>=121',
edge: '>=121',
};