diff --git a/browser/extensions/webcompat/about-compat/AboutCompat.jsm b/browser/extensions/webcompat/about-compat/AboutCompat.jsm index 2993bf46d6e6..125239e9f639 100644 --- a/browser/extensions/webcompat/about-compat/AboutCompat.jsm +++ b/browser/extensions/webcompat/about-compat/AboutCompat.jsm @@ -6,6 +6,10 @@ var EXPORTED_SYMBOLS = ["AboutCompat"]; +const Services = + globalThis.Services || + ChromeUtils.import("resource://gre/modules/Services.jsm").Services; + const addonID = "webcompat@mozilla.org"; const addonPageRelativeURL = "/about-compat/aboutCompat.html"; diff --git a/browser/extensions/webcompat/about-compat/aboutPage.js b/browser/extensions/webcompat/about-compat/aboutPage.js index f639242e0dc5..0f2e7c4ad465 100644 --- a/browser/extensions/webcompat/about-compat/aboutPage.js +++ b/browser/extensions/webcompat/about-compat/aboutPage.js @@ -6,6 +6,10 @@ /* global ExtensionAPI, XPCOMUtils */ +const Services = + globalThis.Services || + ChromeUtils.import("resource://gre/modules/Services.jsm").Services; + XPCOMUtils.defineLazyServiceGetter( this, "resProto", diff --git a/browser/extensions/webcompat/data/injections.js b/browser/extensions/webcompat/data/injections.js index ac1f19b36275..aee055470f95 100644 --- a/browser/extensions/webcompat/data/injections.js +++ b/browser/extensions/webcompat/data/injections.js @@ -569,6 +569,30 @@ const AVAILABLE_INJECTIONS = [ ], }, }, + { + id: "bug1772949", + platform: "all", + domain: "YouTube embeds", + bug: "1772949", + customFunc: "runScriptBeforeRequest", + script: "injections/js/bug1772949-youtube-webshare-shim.js", + request: ["*://www.youtube.com/*/www-embed-player.js*"], + message: "The WebShare API is being disabled on a YouTube frame.", + }, + { + id: "bug1778239", + platform: "all", + domain: "m.pji.co.kr", + bug: "1778239", + contentScripts: { + matches: ["*://m.pji.co.kr/*"], + js: [ + { + file: "injections/js/bug1778239-m.pji.co.kr-banner-hide.js", + }, + ], + }, + }, { id: "bug1774005", platform: "all", @@ -577,12 +601,15 @@ const AVAILABLE_INJECTIONS = [ contentScripts: { matches: [ "*://*.pixiv.net/*", // Bug 1774006 + "*://*.crunchyroll.com/*", // Bug 1777597 + "*://www.northcountrypublicradio.org/contact/subscribe.html*", // Bug 1778382 ], js: [ { file: "injections/js/bug1774005-installtrigger-shim.js", }, ], + allFrames: true, }, }, ]; diff --git a/browser/extensions/webcompat/data/shims.js b/browser/extensions/webcompat/data/shims.js index b33888c48ad1..26412b29e83d 100644 --- a/browser/extensions/webcompat/data/shims.js +++ b/browser/extensions/webcompat/data/shims.js @@ -133,44 +133,36 @@ const AVAILABLE_SHIMS = [ onlyIfBlockedByETP: true, }, { - id: "AdNexus", + id: "AdNexusAST", platform: "all", - name: "AdNexus", - bug: "1713696", - file: "empty-script.js", - matches: [ - "*://acdn.adnxs.com/ast/ast.js", - { - patterns: ["*://*.adnxs.com/*/pb.js", "*://*.adnxs.com/*/prebid"], - target: "adnexus-prebid.js", - types: ["script"], - }, - ], + name: "AdNexus AST", + bug: "1734130", + file: "adnexus-ast.js", + matches: ["*://*.adnxs.com/*/ast.js*"], onlyIfBlockedByETP: true, }, { - id: "AdSafeProtectedFavIcon", + id: "AdNexusPrebid", platform: "all", - name: "Ad Safe Protected favicon", - bug: "1717806", - matches: [ - { - patterns: ["*://static.adsafeprotected.com/favicon.ico"], - target: "https://redirect.firefox.etp/adsafeprotected_favicon", - types: ["image", "imageset", "xmlhttprequest"], - onlyIfBlockedByETP: true, - }, - { - patterns: ["https://redirect.firefox.etp/adsafeprotected_favicon"], - target: "tracking-pixel.png", - types: ["image", "imageset", "xmlhttprequest"], - }, - ], + name: "AdNexus Prebid", + bug: "1713696", + file: "adnexus-prebid.js", + matches: ["*://*.adnxs.com/*/pb.js*", "*://*.adnxs.com/*/prebid*"], + onlyIfBlockedByETP: true, }, { + id: "AdobeEverestJS", + platform: "all", + name: "Adobe EverestJS", + bug: "1728114", + file: "everest.js", + matches: ["*://www.everestjs.net/static/st.v3.js*"], + onlyIfBlockedByETP: true, + }, + { + // keep this above AdSafeProtectedTrackingPixels id: "AdSafeProtectedGoogleIMAAdapter", platform: "all", - branches: ["nightly:android"], name: "Ad Safe Protected Google IMA Adapter", bug: "1508639", file: "adsafeprotected-ima.js", @@ -196,6 +188,42 @@ const AVAILABLE_SHIMS = [ ], onlyIfBlockedByETP: true, }, + { + id: "AdvertisingDotCom", + platform: "all", + name: "advertising.com", + bug: "1701685", + matches: [ + { + patterns: ["*://*.advertising.com/*.js*"], + target: "https://redirect.firefox.etp/advertisingdotcom_js", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + patterns: ["*://*.advertising.com/*"], + target: "https://redirect.firefox.etp/advertisingdotcom_pixel", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + patterns: ["*://*.adsafeprotected.com/*"], + target: "https://redirect.firefox.etp/advertisingdotcom_pixel", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + patterns: ["https://redirect.firefox.etp/adsafeprotected_pixel"], + target: "tracking-pixel.png", + types: ["image", "imageset", "xmlhttprequest"], + }, + { + patterns: ["https://redirect.firefox.etp/advertisingdotcom_js"], + target: "empty-script.js", + types: ["xmlhttprequest"], + }, + ], + }, { id: "Branch", platform: "all", @@ -254,6 +282,7 @@ const AVAILABLE_SHIMS = [ onlyIfBlockedByETP: true, }, { + // keep this above AdSafeProtectedTrackingPixels id: "Doubleclick", platform: "all", name: "Doubleclick", @@ -277,6 +306,7 @@ const AVAILABLE_SHIMS = [ }, { patterns: [ + "*://vast.adsafeprotected.com/vast*", "*://securepubads.g.doubleclick.net/gampad/*xml_vmap2*", "*://pubads.g.doubleclick.net/gampad/*xml_vmap2*", ], @@ -355,6 +385,17 @@ const AVAILABLE_SHIMS = [ }, ], }, + { + id: "Fastclick", + platform: "all", + name: "Fastclick", + bug: "1738220", + file: "fastclick.js", + matches: [ + "*://secure.cdn.fastclick.net/js/cnvr-launcher/*/launcher-stub.min.js*", + ], + onlyIfBlockedByETP: true, + }, { id: "GoogleAnalyticsAndTagManager", platform: "all", @@ -463,6 +504,7 @@ const AVAILABLE_SHIMS = [ onlyIfBlockedByETP: true, }, { + // keep this above AdSafeProtectedTrackingPixels id: "IASPET", platform: "all", name: "Integral Ad Science PET", @@ -776,6 +818,61 @@ const AVAILABLE_SHIMS = [ ], onlyIfDFPIActive: true, }, + { + // keep this below any other shims checking adsafeprotected URLs + id: "AdSafeProtectedTrackingPixels", + platform: "all", + name: "Ad Safe Protected tracking pixels", + bug: "1717806", + matches: [ + { + patterns: [ + "*://*.adsafeprotected.com/*.gif*", + "*://*.adsafeprotected.com/*.png*", + ], + target: "https://redirect.firefox.etp/adsafeprotected_pixel", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + patterns: [ + "*://*.adsafeprotected.com/*.js*", + "*://*.adsafeprotected.com/*/adj*", + "*://*.adsafeprotected.com/*/imp/*", + "*://*.adsafeprotected.com/*/Serving/*", + "*://*.adsafeprotected.com/*/unit/*", + "*://*.adsafeprotected.com/jload", + "*://*.adsafeprotected.com/jload?*", + "*://*.adsafeprotected.com/jsvid", + "*://*.adsafeprotected.com/jsvid?*", + "*://*.adsafeprotected.com/mon*", + "*://*.adsafeprotected.com/tpl", + "*://*.adsafeprotected.com/tpl?*", + "*://*.adsafeprotected.com/services/pub*", + ], + target: "https://redirect.firefox.etp/adsafeprotected_js", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + // note, fallback case seems to be an image + patterns: ["*://*.adsafeprotected.com/*"], + target: "https://redirect.firefox.etp/adsafeprotected_pixel", + types: ["image", "imageset", "xmlhttprequest"], + onlyIfBlockedByETP: true, + }, + { + patterns: ["https://redirect.firefox.etp/adsafeprotected_pixel"], + target: "tracking-pixel.png", + types: ["image", "imageset", "xmlhttprequest"], + }, + { + patterns: ["https://redirect.firefox.etp/adsafeprotected_js"], + target: "empty-script.js", + types: ["xmlhttprequest"], + }, + ], + }, ]; module.exports = AVAILABLE_SHIMS; diff --git a/browser/extensions/webcompat/data/ua_overrides.js b/browser/extensions/webcompat/data/ua_overrides.js index 8d1ae487d955..2e4a5462f2d4 100644 --- a/browser/extensions/webcompat/data/ua_overrides.js +++ b/browser/extensions/webcompat/data/ua_overrides.js @@ -260,10 +260,7 @@ const AVAILABLE_UA_OVERRIDES = [ config: { matches: ["*://*.ceskatelevize.cz/*"], uaTransformer: originalUA => { - return ( - UAHelpers.getPrefix(originalUA) + - " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.111 Mobile Safari/537.36" - ); + return UAHelpers.getDeviceAppropriateChromeUA(); }, }, }, @@ -719,7 +716,6 @@ const AVAILABLE_UA_OVERRIDES = [ "*://*.ibmserviceengage.com/*", // #105438 "*://*.wordpress.org/*", // Bug 1743431 "*://as.eservice.asus.com/*", // #104113 - "*://bethesda.net/*", // #94607, "*://cdn-vzn.yottaa.net/*", // Bug 1764795 "*://dsae.co.za/*", // Bug 1765925 "*://fpt.dfp.microsoft.com/*", // #104237 @@ -839,7 +835,9 @@ const AVAILABLE_UA_OVERRIDES = [ config: { matches: ["*://nordjyske.dk/*"], uaTransformer: originalUA => { - return UAHelpers.getDeviceAppropriateChromeUA("97.0.4692.9", "Pixel 4"); + return UAHelpers.getDeviceAppropriateChromeUA({ + androidDevice: "Pixel 4", + }); }, }, }, @@ -894,7 +892,7 @@ const AVAILABLE_UA_OVERRIDES = [ config: { matches: ["*://www.otsuka.co.jp/fib/*"], uaTransformer: originalUA => { - return UAHelpers.getDeviceAppropriateChromeUA("97.0.4692.9"); + return UAHelpers.getDeviceAppropriateChromeUA(); }, }, }, @@ -917,6 +915,64 @@ const AVAILABLE_UA_OVERRIDES = [ }, }, }, + { + /* + * Bug 1771200 - UA override for lazada.co.id + * Webcompat issue #106229 - https://webcompat.com/issues/106229 + * + * The map is not playing and an error message is displayed + * in Firefox for Android, but work with Chrome UA + */ + id: "bug1779059", + platform: "android", + domain: "lazada.co.id", + bug: "1779059", + config: { + matches: ["*://member-m.lazada.co.id/address/*"], + uaTransformer: originalUA => { + return UAHelpers.getDeviceAppropriateChromeUA(); + }, + }, + }, + { + /* + * Bug 1778168 - UA override for watch.antennaplus.gr + * Webcompat issue #106529 - https://webcompat.com/issues/106529 + * + * The site's content is not loaded unless a Chrome UA is used, + * and breaks on Linux (so we claim Windows instead in that case). + */ + id: "bug1778168", + platform: "desktop", + domain: "watch.antennaplus.gr", + bug: "1778168", + config: { + matches: ["*://watch.antennaplus.gr/*"], + uaTransformer: originalUA => { + return UAHelpers.getDeviceAppropriateChromeUA({ + desktopOS: "nonLinux", + }); + }, + }, + }, + { + /* + * Bug 1776897 - UA override for watch.antennaplus.gr + * Webcompat issue #106545 - https://webcompat.com/issues/106545 + * + * The site's podcast audio player does not load unless a Chrome UA is used. + */ + id: "bug1776897", + platform: "all", + domain: "www.edencast.fr", + bug: "1776897", + config: { + matches: ["*://www.edencast.fr/zoomcast*"], + uaTransformer: originalUA => { + return UAHelpers.getDeviceAppropriateChromeUA(); + }, + }, + }, ]; module.exports = AVAILABLE_UA_OVERRIDES; diff --git a/browser/extensions/webcompat/injections/js/bug1772949-youtube-webshare-shim.js b/browser/extensions/webcompat/injections/js/bug1772949-youtube-webshare-shim.js new file mode 100644 index 000000000000..0e21689ef75a --- /dev/null +++ b/browser/extensions/webcompat/injections/js/bug1772949-youtube-webshare-shim.js @@ -0,0 +1,14 @@ +"use strict"; + +/** + * Bug 1772949 - Disable WebShare on YouTube embed frames + * + * This interventions undefines navigator.share for YouTube embed frames, + * so they show the traditional YouTube sharing interface instead of nothing. + */ + +if (window !== window.top) { + Object.defineProperty(navigator.wrappedJSObject, "share", { + value: undefined, + }); +} diff --git a/browser/extensions/webcompat/injections/js/bug1778239-m.pji.co.kr-banner-hide.js b/browser/extensions/webcompat/injections/js/bug1778239-m.pji.co.kr-banner-hide.js new file mode 100644 index 000000000000..f93e04b27436 --- /dev/null +++ b/browser/extensions/webcompat/injections/js/bug1778239-m.pji.co.kr-banner-hide.js @@ -0,0 +1,18 @@ +"use strict"; + +/** + * Bug 1778239 - Dismiss the "optimized for Chrome" banner on m.pji.co.kr + * + * This interventions force-sets a window variable `flag` to true, to bypass + * the need to use a Chrome user-agent string to hide the banner. + */ + +/* globals exportFunction */ + +Object.defineProperty(window.wrappedJSObject, "flag", { + get: exportFunction(function() { + return true; + }, window), + + set: exportFunction(function() {}, window), +}); diff --git a/browser/extensions/webcompat/lib/custom_functions.js b/browser/extensions/webcompat/lib/custom_functions.js index 9bfc6fbdb5ff..7b972f6d6bf2 100644 --- a/browser/extensions/webcompat/lib/custom_functions.js +++ b/browser/extensions/webcompat/lib/custom_functions.js @@ -91,6 +91,38 @@ const CUSTOM_FUNCTIONS = { browser.webRequest.onBeforeRequest.removeListener(listener); delete injection.data.listener; }, + runScriptBeforeRequest: injection => { + const { bug, message, request, script, types } = injection; + const warning = `${message} See https://bugzilla.mozilla.org/show_bug.cgi?id=${bug} for details.`; + + const listener = (injection.listener = e => { + const { tabId, frameId } = e; + return browser.tabs + .executeScript(tabId, { + file: script, + frameId, + runAt: "document_start", + }) + .then(() => { + browser.tabs.executeScript(tabId, { + code: `console.warn(${JSON.stringify(warning)})`, + runAt: "document_start", + }); + }) + .catch(_ => {}); + }); + + browser.webRequest.onBeforeRequest.addListener( + listener, + { urls: request, types: types || ["script"] }, + ["blocking"] + ); + }, + runScriptBeforeRequestDisable: injection => { + const { listener } = injection; + browser.webRequest.onBeforeRequest.removeListener(listener); + delete injection.data.listener; + }, }; module.exports = CUSTOM_FUNCTIONS; diff --git a/browser/extensions/webcompat/lib/ua_helpers.js b/browser/extensions/webcompat/lib/ua_helpers.js index a1a50352df95..6f4f25b2ac63 100644 --- a/browser/extensions/webcompat/lib/ua_helpers.js +++ b/browser/extensions/webcompat/lib/ua_helpers.js @@ -8,11 +8,9 @@ var UAHelpers = { _deviceAppropriateChromeUAs: {}, - getDeviceAppropriateChromeUA( - chromeVersion = "76.0.3809.111", - specificAndroidDevice = "" - ) { - const key = `${chromeVersion}:${specificAndroidDevice}`; + getDeviceAppropriateChromeUA(config = {}) { + const { version = "103.0.5060.71", androidDevice, desktopOS } = config; + const key = `${version}:${androidDevice}:${desktopOS}`; if (!UAHelpers._deviceAppropriateChromeUAs[key]) { const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : ""; @@ -24,13 +22,13 @@ var UAHelpers = { if (userAgent.includes("Android")) { const RunningAndroidVersion = userAgent.match(/Android\/[0-9.]+/) || "Android 6.0"; - if (specificAndroidDevice) { + if (androidDevice) { UAHelpers._deviceAppropriateChromeUAs[ key - ] = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; ${specificAndroidDevice}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Mobile Safari/537.36`; + ] = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; ${androidDevice}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Mobile Safari/537.36`; } else { - const ChromePhoneUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 5 Build/MRA58N) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Mobile Safari/537.36`; - const ChromeTabletUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 7 Build/JSS15Q) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`; + const ChromePhoneUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 5 Build/MRA58N) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Mobile Safari/537.36`; + const ChromeTabletUA = `Mozilla/5.0 (Linux; ${RunningAndroidVersion}; Nexus 7 Build/JSS15Q) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`; const IsPhone = userAgent.includes("Mobile"); UAHelpers._deviceAppropriateChromeUAs[key] = IsPhone ? ChromePhoneUA @@ -38,16 +36,19 @@ var UAHelpers = { } } else { let osSegment = "Windows NT 10.0; Win64; x64"; - if (userAgent.includes("Macintosh")) { + if (desktopOS === "macOS" || userAgent.includes("Macintosh")) { osSegment = "Macintosh; Intel Mac OS X 10_15_7"; } - if (userAgent.includes("Linux")) { + if ( + desktopOS !== "nonLinux" && + (desktopOS === "linux" || userAgent.includes("Linux")) + ) { osSegment = "X11; Ubuntu; Linux x86_64"; } UAHelpers._deviceAppropriateChromeUAs[ key - ] = `Mozilla/5.0 (${osSegment}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`; + ] = `Mozilla/5.0 (${osSegment}) FxQuantum/${RunningFirefoxVersion} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`; } } return UAHelpers._deviceAppropriateChromeUAs[key]; @@ -55,8 +56,8 @@ var UAHelpers = { getPrefix(originalUA) { return originalUA.substr(0, originalUA.indexOf(")") + 1); }, - overrideWithDeviceAppropriateChromeUA(chromeVersion = undefined) { - const chromeUA = UAHelpers.getDeviceAppropriateChromeUA(chromeVersion); + overrideWithDeviceAppropriateChromeUA(config) { + const chromeUA = UAHelpers.getDeviceAppropriateChromeUA(config); Object.defineProperty(window.navigator.wrappedJSObject, "userAgent", { get: exportFunction(() => chromeUA, window), set: exportFunction(function() {}, window), diff --git a/browser/extensions/webcompat/manifest.json b/browser/extensions/webcompat/manifest.json index 9bbb84d07ca0..58cca442a31f 100644 --- a/browser/extensions/webcompat/manifest.json +++ b/browser/extensions/webcompat/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "Web Compatibility Interventions", "description": "Urgent post-release fixes for web compatibility.", - "version": "103.13.0", + "version": "104.0.0", "applications": { "gecko": { "id": "webcompat@mozilla.org", @@ -94,6 +94,7 @@ "web_accessible_resources": [ "shims/addthis-angular.js", "shims/adform.js", + "shims/adnexus-ast.js", "shims/adnexus-prebid.js", "shims/adsafeprotected-ima.js", "shims/apstag.js", @@ -109,8 +110,10 @@ "shims/eluminate.js", "shims/empty-script.js", "shims/empty-shim.txt", + "shims/everest.js", "shims/facebook-sdk.js", "shims/facebook.svg", + "shims/fastclick.js", "shims/firebase.js", "shims/google-ads.js", "shims/google-analytics-and-tag-manager.js", diff --git a/browser/extensions/webcompat/moz.build b/browser/extensions/webcompat/moz.build index 49e1583c41fe..d2bd2301fea5 100644 --- a/browser/extensions/webcompat/moz.build +++ b/browser/extensions/webcompat/moz.build @@ -81,12 +81,15 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["injections"]["js"] += [ "injections/js/bug1731825-office365-email-handling-prompt-autohide.js", "injections/js/bug1739489-draftjs-beforeinput.js", "injections/js/bug1769762-tiktok.com-plugins-shim.js", + "injections/js/bug1772949-youtube-webshare-shim.js", "injections/js/bug1774005-installtrigger-shim.js", + "injections/js/bug1778239-m.pji.co.kr-banner-hide.js", ] FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["shims"] += [ "shims/addthis-angular.js", "shims/adform.js", + "shims/adnexus-ast.js", "shims/adnexus-prebid.js", "shims/adsafeprotected-ima.js", "shims/apstag.js", @@ -102,8 +105,10 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["shims"] += [ "shims/eluminate.js", "shims/empty-script.js", "shims/empty-shim.txt", + "shims/everest.js", "shims/facebook-sdk.js", "shims/facebook.svg", + "shims/fastclick.js", "shims/firebase.js", "shims/google-ads.js", "shims/google-analytics-and-tag-manager.js", diff --git a/browser/extensions/webcompat/shims/adnexus-ast.js b/browser/extensions/webcompat/shims/adnexus-ast.js new file mode 100644 index 000000000000..e72808a332a2 --- /dev/null +++ b/browser/extensions/webcompat/shims/adnexus-ast.js @@ -0,0 +1,210 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Bug 1734130 - Shim AdNexus AST + * + * Some sites expect AST to successfully load, or they break. + * This shim mitigates that breakage. + */ + +if (!window.apntag?.loaded) { + const anq = window.apntag?.anq || []; + + const gTags = new Map(); + const gAds = new Map(); + const gEventHandlers = {}; + + const Ad = class { + adType = "banner"; + auctionId = "-"; + banner = { + width: 1, + height: 1, + content: "", + trackers: { + impression_urls: [], + video_events: {}, + }, + }; + brandCategoryId = 0; + buyerMemberId = 0; + cpm = 0.1; + cpm_publisher_currency = 0.1; + creativeId = 0; + dealId = undefined; + height = 1; + mediaSubtypeId = 1; + mediaTypeId = 1; + publisher_currency_code = "US"; + source = "-"; + tagId = -1; + targetId = ""; + width = 1; + + constructor(tagId, targetId) { + this.tagId = tagId; + this.targetId = targetId; + } + }; + + const fireAdEvent = (type, adObj) => { + const { targetId } = adObj; + const handlers = gEventHandlers[type]?.[targetId]; + if (!handlers) { + return Promise.resolve(); + } + const evt = { adObj, type }; + return new Promise(done => { + setTimeout(() => { + for (const cb of handlers) { + try { + cb(evt); + } catch (e) { + console.error(e); + } + } + done(); + }, 1); + }); + }; + + const refreshTag = targetId => { + const tag = gTags.get(targetId); + if (!tag) { + return; + } + if (!gAds.has(targetId)) { + gAds.set(targetId, new Ad(tag.tagId, targetId)); + } + const adObj = gAds.get(targetId); + fireAdEvent("adRequested", adObj).then(() => { + // TODO: do some sites expect adAvailable+adLoaded instead of adNoBid? + fireAdEvent("adNoBid", adObj); + }); + }; + + const off = (type, targetId, cb) => { + gEventHandlers[type]?.[targetId]?.delete(cb); + }; + + const on = (type, targetId, cb) => { + gEventHandlers[type] = gEventHandlers[type] || {}; + gEventHandlers[type][targetId] = + gEventHandlers[type][targetId] || new Set(); + gEventHandlers[type][targetId].add(cb); + }; + + const Tag = class { + static #nextId = 0; + debug = undefined; + displayed = false; + initialHeight = 1; + initialWidth = 1; + keywords = {}; + member = 0; + showTagCalled = false; + sizes = []; + targetId = ""; + utCalled = true; + utDivId = ""; + utiframeId = ""; + uuid = ""; + + constructor(raw) { + const { keywords, sizes, targetId } = raw; + this.tagId = Tag.#nextId++; + this.keywords = keywords || {}; + this.sizes = sizes || []; + this.targetId = targetId || ""; + } + modifyTag() {} + off(type, cb) { + off(type, this.targetId, cb); + } + on(type, cb) { + on(type, this.targetId, cb); + } + setKeywords(kw) { + this.keywords = kw; + } + }; + + window.apntag = { + anq, + attachClickTrackers() {}, + checkAdAvailable() {}, + clearPageTargeting() {}, + clearRequest() {}, + collapseAd() {}, + debug: false, + defineTag(dfn) { + const { targetId } = dfn; + if (!targetId) { + return; + } + gTags.set(targetId, new Tag(dfn)); + }, + disableDebug() {}, + dongle: undefined, + emitEvent(adObj, type) { + fireAdEvent(type, adObj); + }, + enableCookieSet() {}, + enableDebug() {}, + fireImpressionTrackers() {}, + getAdMarkup: () => "", + getAdWrap() {}, + getAstVersion: () => "0.49.0", + getPageTargeting() {}, + getTag(targetId) { + return gTags.get(targetId); + }, + handleCb() {}, + handleMediationBid() {}, + highlightAd() {}, + loaded: true, + loadTags() { + for (const tagName of gTags.keys()) { + refreshTag(tagName); + } + }, + modifyTag() {}, + notify() {}, + offEvent(type, target, cb) { + off(type, target, cb); + }, + onEvent(type, target, cb) { + on(type, target, cb); + }, + recordErrorEvent() {}, + refresh() {}, + registerRenderer() {}, + requests: {}, + resizeAd() {}, + setEndpoint() {}, + setKeywords() {}, + setPageOpts() {}, + setPageTargeting() {}, + setSafeFrameConfig() {}, + setSizes() {}, + showTag() {}, + }; + + const push = function(fn) { + if (typeof fn === "function") { + try { + fn(); + } catch (e) { + console.trace(e); + } + } + }; + + anq.push = push; + + anq.forEach(push); +} diff --git a/browser/extensions/webcompat/shims/branch.js b/browser/extensions/webcompat/shims/branch.js index 4689f5b2c333..31e8f4eeec78 100644 --- a/browser/extensions/webcompat/shims/branch.js +++ b/browser/extensions/webcompat/shims/branch.js @@ -73,7 +73,7 @@ if (!window?.branch?.b) { trackCommerceEvent() {} validateCode() {} })(); - const push = (fn, args) => { + const push = ([fn, ...args]) => { try { window.branch[fn].apply(window.branch, args); } catch (e) { diff --git a/browser/extensions/webcompat/shims/everest.js b/browser/extensions/webcompat/shims/everest.js new file mode 100644 index 000000000000..259ab9033eb7 --- /dev/null +++ b/browser/extensions/webcompat/shims/everest.js @@ -0,0 +1,171 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Bug 1728114 - Shim Adobe EverestJS + * + * Sites assuming EverestJS will load can break if it is blocked. + * This shim mitigates that breakage. + */ + +if (!window.__ql) { + window.__ql = {}; +} + +if (!window.EF) { + const AdCloudLocalStorage = { + get: (_, cb) => cb(), + isInitDone: true, + isInitSuccess: true, + }; + + const emptyObj = {}; + + const nullSrc = { + getHosts: () => [undefined], + getProtocols: () => [undefined], + hash: {}, + hashParamsOrder: [], + host: undefined, + path: [], + port: undefined, + query: {}, + queryDelimiter: "&", + queryParamsOrder: [], + queryPrefix: "?", + queryWithoutEncode: {}, + respectEmptyQueryParamValue: undefined, + scheme: undefined, + text: "//", + userInfo: undefined, + }; + + const pixelDetailsEvent = { + addToDom() {}, + canAddToDom: () => false, + fire() {}, + getDomElement() {}, + initializeUri() {}, + pixelDetailsReceiver() {}, + scheme: "https:", + uri: nullSrc, + userid: 0, + }; + + window.EF = { + AdCloudLocalStorage, + accessTopUrl: 0, + acquireCookieMatchingSlot() {}, + addListener() {}, + addPixelDetailsReadyListener() {}, + addToDom() {}, + allow3rdPartyPixels: 1, + appData: "", + appendDictionary() {}, + checkGlobalSid() {}, + checkUrlParams() {}, + cmHost: "cm.everesttech.net", + context: { + isFbApp: () => 0, + isPageview: () => false, + isSegmentation: () => false, + isTransaction: () => false, + }, + conversionData: "", + cookieMatchingSlots: 1, + debug: 0, + deserializeUrlParams: () => emptyObj, + doCookieMatching() {}, + ef_itp_ls: false, + eventType: "", + executeAfterLoad() {}, + executeOnloadCallbacks() {}, + expectedTrackingParams: ["ev_cl", "ev_sid"], + fbIsApp: 0, + fbsCM: 0, + fbsPixelId: 0, + filterList: () => [], + getArrayIndex: -1, + getConversionData: () => "", + getConversionDataFromLocalStorage: cb => cb(), + getDisplayClickUri: () => "", + getEpochFromEfUniq: () => 0, + getFirstLevelObjectCopy: () => emptyObj, + getInvisibleIframeElement() {}, + getInvisibleImageElement() {}, + getMacroSubstitutedText: () => "", + getPixelDetails: cb => cb({}), + getScriptElement() {}, + getScriptSrc: () => "", + getServerParams: () => emptyObj, + getSortedAttributes: () => [], + getTrackingParams: () => emptyObj, + getTransactionParams: () => emptyObj, + handleConversionData() {}, + impressionProperties: "", + impressionTypes: ["impression", "impression_served"], + inFloodlight: 0, + init(config) { + try { + const { userId } = config; + window.EF.userId = userId; + pixelDetailsEvent.userId = userId; + } catch (_) {} + }, + initializeEFVariables() {}, + isArray: a => Array.isArray(a), + isEmptyDictionary: () => true, + isITPEnabled: () => false, + isPermanentCookieSet: () => false, + isSearchClick: () => 0, + isXSSReady() {}, + jsHost: "www.everestjs.net", + jsTagAdded: 0, + location: nullSrc, + locationHref: nullSrc, + locationSkipBang: nullSrc, + log() {}, + main() {}, + main2() {}, + newCookieMatchingEvent: () => emptyObj, + newFbsCookieMatching: () => emptyObj, + newImpression: () => emptyObj, + newPageview: () => emptyObj, + newPixelDetails: () => emptyObj, + newPixelEvent: () => emptyObj, + newPixelServerDisplayClickRedirectUri: () => emptyObj, + newPixelServerGenericRedirectUri: () => emptyObj, + newPixelServerUri: () => emptyObj, + newProductSegment: () => emptyObj, + newSegmentJavascript: () => emptyObj, + newTransaction: () => emptyObj, + newUri: () => emptyObj, + onloadCallbacks: [], + pageViewProperties: "", + pageviewProperties: "", + pixelDetails: {}, + pixelDetailsAdded: 1, + pixelDetailsEvent, + pixelDetailsParams: [], + pixelDetailsReadyCallbackFns: [], + pixelDetailsRecieverCalled: 1, + pixelHost: "pixel.everesttech.net", + protocol: document?.location?.protocol || "", + referrer: nullSrc, + removeListener() {}, + searchSegment: "", + segment: "", + serverParamsListener() {}, + sid: 0, + sku: "", + throttleCookie: "", + trackingJavascriptSrc: nullSrc, + transactionObjectList: [], + transactionProperties: "", + userServerParams: {}, + userid: 0, + }; +} diff --git a/browser/extensions/webcompat/shims/fastclick.js b/browser/extensions/webcompat/shims/fastclick.js new file mode 100644 index 000000000000..ad6814c9953b --- /dev/null +++ b/browser/extensions/webcompat/shims/fastclick.js @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Bug 1738220 - Shim Conversant FastClick + * + * Sites assuming FastClick will load can break if it is blocked. + * This shim mitigates that breakage. + */ + +// FastClick bundles nodeJS packages/core-js/internals/dom-iterables.js +// which is known to be needed by at least one site. +if (!HTMLCollection.prototype.forEach) { + const DOMIterables = [ + "CSSRuleList", + "CSSStyleDeclaration", + "CSSValueList", + "ClientRectList", + "DOMRectList", + "DOMStringList", + "DOMTokenList", + "DataTransferItemList", + "FileList", + "HTMLAllCollection", + "HTMLCollection", + "HTMLFormElement", + "HTMLSelectElement", + "MediaList", + "MimeTypeArray", + "NamedNodeMap", + "NodeList", + "PaintRequestList", + "Plugin", + "PluginArray", + "SVGLengthList", + "SVGNumberList", + "SVGPathSegList", + "SVGPointList", + "SVGStringList", + "SVGTransformList", + "SourceBufferList", + "StyleSheetList", + "TextTrackCueList", + "TextTrackList", + "TouchList", + ]; + + const forEach = Array.prototype.forEach; + + const handlePrototype = proto => { + if (!proto || proto.forEach === forEach) { + return; + } + try { + Object.defineProperty(proto, "forEach", { + enumerable: false, + get: () => forEach, + }); + } catch (_) { + proto.forEach = forEach; + } + }; + + for (const name of DOMIterables) { + handlePrototype(window[name]?.prototype); + } +} + +if (!window.conversant?.launch) { + const c = (window.conversant = window.conversant || {}); + c.launch = () => {}; +} diff --git a/browser/extensions/webcompat/shims/google-publisher-tags.js b/browser/extensions/webcompat/shims/google-publisher-tags.js index 746ce45b3e67..c38b9ca8e478 100644 --- a/browser/extensions/webcompat/shims/google-publisher-tags.js +++ b/browser/extensions/webcompat/shims/google-publisher-tags.js @@ -430,11 +430,15 @@ if (window.googletag?.apiReady === undefined) { this.#mapping = new SizeMapping(); } addSize(size, creatives) { - if (!Array.isArray(size) || isNaN(size[0]) || isNaN(size[1])) { + if ( + size !== "fluid" && + (!Array.isArray(size) || isNaN(size[0]) || isNaN(size[1])) + ) { this.#mapping = null; } else { this.#mapping?.push([size, creatives]); } + return this; } build() { return this.#mapping;