getDeviceAppropriateChromeUA(config); }, desktop_not_mobile: () => { return UAHelpers.desktopUA(); }, mimic_Android_Hotspot2_device: ua => { return UAHelpers.androidHotspot2Device(ua); }, replace_colon_in_rv_with_space: ua => { return ua.replace("rv:", "rv "); }, reduce_firefox_version_by_one: ua => { const [head, fx, tail] = ua.split(/(firefox\/)/i); if (!fx || !tail) { return ua; } const major = parseInt(tail); if (!major) { return ua; } return `${head}${fx}${major - 1}${tail.slice(major.toString().length)}`; }, add_Safari: (ua, config) => { config.withFirefox = true; return UAHelpers.safari(config); }, Safari: (ua, config) => { return UAHelpers.safari(config); }, Safari_with_FxQuantum: (ua, config) => { config.withFxQuantum = true; return UAHelpers.safari(config); }, }, valid_platforms: [ "all", "android", "desktop", "fenix", "linux", "mac", "windows", ], valid_channels: ["beta", "esr", "nightly", "stable"], shouldSkip(intervention, firefoxVersion, firefoxChannel) { const { bug, max_version, min_version, not_channels, only_channels, skip_if, ua_string, } = intervention; if (firefoxChannel) { if (only_channels && !only_channels.includes(firefoxChannel)) { return true; } if (not_channels?.includes(firefoxChannel)) { return true; } } if (min_version && firefoxVersion < min_version) { return true; } if (max_version) { // Make sure to handle the case where only the major version matters, // for instance if we want 138 and the version number is 138.1. if (String(max_version).includes(".")) { if (firefoxVersion > max_version) { return true; } } else if (Math.floor(firefoxVersion) > max_version) { return true; } } if (ua_string) { for (let ua of Array.isArray(ua_string) ? ua_string : [ua_string]) { if (!InterventionHelpers.ua_change_functions[ua.change ?? ua]) { return true; } } } if (skip_if) { try { if ( !this.skip_if_functions[skip_if] || this.skip_if_functions[skip_if]?.() ) { return true; } } catch (e) { console.trace( `Error while checking skip-if condition ${skip_if} for bug ${bug}:`, e ); return true; } } return false; }, nonCustomInterventionKeys: Object.freeze( new Set([ "content_scripts", "enabled", "max_version", "min_version", "not_platforms", "platforms", "not_channels", "only_channels", "pref_check", "skip_if", "ua_string", ]) ), isMissingCustomFunctions(intervention, customFunctionNames) { for (let key of Object.keys(intervention)) { if ( !InterventionHelpers.nonCustomInterventionKeys.has(key) && !customFunctionNames.has(key) ) { return true; } } return false; }, async getOS() { const os = browser.aboutConfigPrefs.getPref("platform_override") ?? (await browser.runtime.getPlatformInfo()).os; if (os === "win") { return "windows"; } return os; }, async getPlatformMatches() { if (!InterventionHelpers._platformMatches) { const os = await this.getOS(); InterventionHelpers._platformMatches = [ "all", os, os == "android" ? "android" : "desktop", ]; if (os == "android") { const packageName = await browser.appConstants.getAndroidPackageName(); if (packageName.includes("fenix") || packageName.includes("firefox")) { InterventionHelpers._platformMatches.push("fenix"); } } } return InterventionHelpers._platformMatches; }, async checkPlatformMatches(intervention) { let desired = intervention.platforms; let undesired = intervention.not_platforms; if (!desired && !undesired) { return true; } const actual = await InterventionHelpers.getPlatformMatches(); if (undesired) { if (!Array.isArray(undesired)) { undesired = [undesired]; } if ( undesired.includes("all") || actual.filter(x => undesired.includes(x)).length ) { return false; } } if (!desired) { return true; } if (!Array.isArray(desired)) { desired = [desired]; } return ( desired.includes("all") || !!actual.filter(x => desired.includes(x)).length ); }, applyUAChanges(ua, changes) { if (!Array.isArray(changes)) { changes = [changes]; } for (let config of changes) { if (typeof config === "string") { config = { change: config }; } let finalChanges = config.change; if (!Array.isArray(finalChanges)) { finalChanges = [finalChanges]; } for (const change of finalChanges) { try { ua = InterventionHelpers.ua_change_functions[change](ua, config); } catch (e) { console.trace( `Error while calling UA change function ${change} for bug ${config.bug}:`, e ); return ua; } } } return ua; }, /** * Useful helper to generate a list of domains with a fixed base domain and * multiple country-TLDs or other cases with various TLDs. * * Example: * matchPatternsForTLDs("*://mozilla.", "/*", ["com", "org"]) * => ["*://mozilla.com/*", "*://mozilla.org/*"] */ matchPatternsForTLDs(base, suffix, tlds) { return tlds.map(tld => base + tld + suffix); }, /** * A modified version of matchPatternsForTLDs that always returns the match * list for all known Google country TLDs. */ matchPatternsForGoogle(base, suffix = "/*") { return InterventionHelpers.matchPatternsForTLDs(base, suffix, GOOGLE_TLDS); }, }; PK