4-131070baca4c}"); QueryInterface = ChromeUtils.generateQI([ "nsIFingerprintingWebCompatService", ]); #initialized = false; #remoteOverrides; #granularOverrides; #rs; #validator; #isParentProcess; constructor() { this.#isParentProcess = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT; this.#remoteOverrides = new Set(); this.#granularOverrides = new Set(); this.#rs = lazy.RemoteSettings(COLLECTION_NAME); } async init() { lazy.logConsole.debug("init"); // We can only access remote settings from the parent process. So, never // init it in the content process. if (!this.#isParentProcess) { throw new Error( "Shouldn't init FingerprintingWebCompatService in content processes." ); } // Return if we have initiated. if (this.#initialized) { return; } this.#initialized = true; // Register listener to import overrides when the overrides pref changes. Services.prefs.addObserver(PREF_GRANULAR_OVERRIDES, this); Services.prefs.addObserver(PREF_GRANULAR_OVERRIDES_BASELINE, this); // Register the sync event for the remote settings updates. this.#rs.on("sync", async _ => { await this.#importRemoteSettingsOverrides(); this.#populateOverrides(); }); // Get the remote overrides from the remote settings. await this.#importRemoteSettingsOverrides(); // Get the granular overrides from the pref. this.#importPrefOverrides(); // Populate the overrides to the nsRFPService. this.#populateOverrides(); lazy.logConsole.debug("Init completes"); } // Lazily create the schema validator when needed #getSchemaValidator() { return (this.#validator ??= new lazy.JsonSchema.Validator(SCHEMA)); } // Import fingerprinting overrides from the local granular pref. #importPrefOverrides() { lazy.logConsole.debug("importLocalGranularOverrides"); // Clear overrides before we update. this.#granularOverrides.clear(); for (const [pref, isBaseline] of [ [lazy.baselineGranularOverridesPref, true], [lazy.granularOverridesPref, false], ]) { let overrides; try { overrides = JSON.parse(pref || "[]"); } catch (error) { lazy.logConsole.error( `Failed to parse granular override JSON string: Not a valid JSON.`, error ); return; } // Ensure we have an array we can iterate over and not an object. if (!Array.isArray(overrides)) { lazy.logConsole.error( "Failed to parse granular overrides JSON String: Not an array." ); return; } // Skip creating the validator if there's nothing to validate. if (overrides.length === 0) { continue; } const validator = this.#getSchemaValidator(); for (let override of overrides) { // Validate the override. let { valid, errors } = validator.validate(override); if (!valid) { lazy.logConsole.debug("Override validation error", override, errors); continue; } this.#granularOverrides.add( this.#createFingerprintingOverrideFrom(override, isBaseline) ); } } } // Import fingerprinting overrides from the remote settings. async #importRemoteSettingsOverrides() { lazy.logConsole.debug("importRemoteSettingsOverrides"); let entries; try { entries = await this.#rs.get(); } catch (e) {} this.#onRemoteUpdate(entries || []); } #onRemoteUpdate(entries) { lazy.logConsole.debug("onUpdateEntries", { entries }); if (!lazy.remoteOverridesEnabled) { lazy.logConsole.debug("Abort remote overrides"); return; } // Clear all overrides before we update the overrides. this.#remoteOverrides.clear(); for (let entry of entries) { this.#remoteOverrides.add(this.#createFingerprintingOverrideFrom(entry)); } } #createFingerprintingOverrideFrom(entry, isBaselineOverride = null) { // If the isBaselineOverride is not provided, we will use the value from the // entry. If the entry doesn't have the isBaseline field, we will default to // false. // We default to false because we didn't have the baseline mode in the past, // and the existing entries don't have the isBaseline field. const isBaseline = isBaselineOverride ?? entry.isBaseline ?? false; return new FingerprintingOverride( entry.firstPartyDomain, entry.thirdPartyDomain, entry.overrides, isBaseline ); } #populateOverrides() { lazy.logConsole.debug("populateOverrides"); // Create the array that contains all overrides. We explicitly concat the // overrides from testing pref after the ones from remote settings to ensure // that the testing pref will take precedence. let overrides = Array.from(this.#remoteOverrides).concat( Array.from(this.#granularOverrides) ); // Set the remote override to the RFP service. Services.rfp.setFingerprintingOverrides(overrides); } observe(subject, topic, prefName) { if ( prefName != PREF_GRANULAR_OVERRIDES && prefName != PREF_GRANULAR_OVERRIDES_BASELINE ) { return; } this.#importPrefOverrides(); this.#populateOverrides(); } shutdown() { lazy.logConsole.debug("shutdown"); Services.prefs.removeObserver(PREF_GRANULAR_OVERRIDES, this); Services.prefs.removeObserver(PREF_GRANULAR_OVERRIDES_BASELINE, this); } } PK