forked from mirrors/gecko-dev
This patch uses TRRPerformance.jsm to get the fastest TRR and store it in a pref before running DoH heuristics. The chosen TRR URI is sent in a telemetry event. Differential Revision: https://phabricator.services.mozilla.com/D72790
670 lines
21 KiB
JavaScript
670 lines
21 KiB
JavaScript
/* 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";
|
|
/* global browser, runHeuristics */
|
|
|
|
let DEBUG;
|
|
|
|
async function log() {
|
|
// eslint-disable-next-line no-constant-condition
|
|
if (DEBUG) {
|
|
// eslint-disable-next-line no-console
|
|
console.log(...arguments);
|
|
}
|
|
}
|
|
|
|
// Gate-keeping pref to run the add-on
|
|
const DOH_ENABLED_PREF = "doh-rollout.enabled";
|
|
|
|
// When in automation, we parse this string pref as JSON and use it as our
|
|
// heuristics results set. This allows tests to set up different cases and
|
|
// verify the correct response.
|
|
const MOCK_HEURISTICS_PREF = "doh-rollout.heuristics.mockValues";
|
|
|
|
// Pref that sets DoH to on/off. It has multiple modes:
|
|
// 0: Off (default)
|
|
// 1: null (No setting)
|
|
// 2: Enabled, but will fall back to 0 on DNS lookup failure
|
|
// 3: Always on.
|
|
// 4: null (No setting)
|
|
// 5: Never on.
|
|
const TRR_MODE_PREF = "network.trr.mode";
|
|
|
|
// This preference is set to TRUE when DoH has been enabled via the add-on. It will
|
|
// allow the add-on to continue to function without the aid of the Normandy-triggered pref
|
|
// of "doh-rollout.enabled". Note that instead of setting it to false, it is cleared.
|
|
const DOH_SELF_ENABLED_PREF = "doh-rollout.self-enabled";
|
|
|
|
// This pref is part of a cache mechanism to see if the heuristics dictated a change in the DoH settings
|
|
const DOH_PREVIOUS_TRR_MODE_PREF = "doh-rollout.previous.trr.mode";
|
|
|
|
// Set after doorhanger has been interacted with by the user
|
|
const DOH_DOORHANGER_SHOWN_PREF = "doh-rollout.doorhanger-shown";
|
|
|
|
// Records if the user opted in/out of DoH study by clicking on doorhanger
|
|
const DOH_DOORHANGER_USER_DECISION_PREF = "doh-rollout.doorhanger-decision";
|
|
|
|
// Records if user has decided to opt out of study, either by disabling via the doorhanger,
|
|
// unchecking "DNS-over-HTTPS" with about:preferences, or manually setting network.trr.mode
|
|
const DOH_DISABLED_PREF = "doh-rollout.disable-heuristics";
|
|
|
|
// Set to true when a user has ANY enterprise policy set, making sure to not run
|
|
// heuristics, overwritting the policy.
|
|
const DOH_SKIP_HEURISTICS_PREF = "doh-rollout.skipHeuristicsCheck";
|
|
|
|
// Records when the add-on has been run once. This is in place to only check
|
|
// network.trr.mode for prefHasUserValue on first run.
|
|
const DOH_DONE_FIRST_RUN_PREF = "doh-rollout.doneFirstRun";
|
|
|
|
// This pref is set once a migration function has ran, updating local storage items to the
|
|
// new doh-rollot.X namespace. This applies to both `doneFirstRun` and `skipHeuristicsCheck`.
|
|
const DOH_BALROG_MIGRATION_PREF = "doh-rollout.balrog-migration-done";
|
|
|
|
// If set to true, debug logging will be enabled.
|
|
const DOH_DEBUG_PREF = "doh-rollout.debug";
|
|
|
|
const stateManager = {
|
|
async setState(state) {
|
|
log("setState: ", state);
|
|
|
|
switch (state) {
|
|
case "uninstalled":
|
|
break;
|
|
case "disabled":
|
|
await rollout.setSetting(TRR_MODE_PREF, 0);
|
|
break;
|
|
case "manuallyDisabled":
|
|
await browser.experiments.preferences.clearUserPref(
|
|
DOH_SELF_ENABLED_PREF
|
|
);
|
|
break;
|
|
case "UIOk":
|
|
await rollout.setSetting(DOH_SELF_ENABLED_PREF, true);
|
|
break;
|
|
case "enabled":
|
|
await rollout.setSetting(TRR_MODE_PREF, 2);
|
|
await rollout.setSetting(DOH_SELF_ENABLED_PREF, true);
|
|
break;
|
|
case "UIDisabled":
|
|
await rollout.setSetting(TRR_MODE_PREF, 5);
|
|
await browser.experiments.preferences.clearUserPref(
|
|
DOH_SELF_ENABLED_PREF
|
|
);
|
|
break;
|
|
}
|
|
|
|
await browser.experiments.heuristics.sendStatePing(state);
|
|
await stateManager.rememberTRRMode();
|
|
},
|
|
|
|
async rememberTRRMode() {
|
|
let curMode = await browser.experiments.preferences.getIntPref(
|
|
TRR_MODE_PREF,
|
|
0
|
|
);
|
|
log("Saving current trr mode:", curMode);
|
|
await rollout.setSetting(DOH_PREVIOUS_TRR_MODE_PREF, curMode, true);
|
|
},
|
|
|
|
async rememberDoorhangerShown() {
|
|
// This will be shown on startup and network changes until a user clicks
|
|
// to confirm/disable DoH or presses the esc key (confirming)
|
|
log("Remembering that doorhanger has been shown");
|
|
await rollout.setSetting(DOH_DOORHANGER_SHOWN_PREF, true);
|
|
},
|
|
|
|
async rememberDoorhangerDecision(decision) {
|
|
log("Remember doorhanger decision:", decision);
|
|
await rollout.setSetting(DOH_DOORHANGER_USER_DECISION_PREF, decision, true);
|
|
},
|
|
|
|
async rememberDisableHeuristics() {
|
|
log("Remembering to never run heuristics again");
|
|
await rollout.setSetting(DOH_DISABLED_PREF, true);
|
|
},
|
|
|
|
async shouldRunHeuristics() {
|
|
// Check if heuristics has been disabled from rememberDisableHeuristics()
|
|
let disableHeuristics = await rollout.getSetting(DOH_DISABLED_PREF, false);
|
|
let skipHeuristicsCheck = await rollout.getSetting(
|
|
DOH_SKIP_HEURISTICS_PREF,
|
|
false
|
|
);
|
|
|
|
if (disableHeuristics || skipHeuristicsCheck) {
|
|
// Do not modify DoH for this user.
|
|
log("shouldRunHeuristics: Will not run heuristics");
|
|
return false;
|
|
}
|
|
|
|
let prevMode = await rollout.getSetting(DOH_PREVIOUS_TRR_MODE_PREF, 0);
|
|
|
|
let curMode = await browser.experiments.preferences.getIntPref(
|
|
TRR_MODE_PREF,
|
|
0
|
|
);
|
|
|
|
log("Comparing previous trr mode to current mode:", prevMode, curMode);
|
|
|
|
// Don't run heuristics if:
|
|
// 1) Previous doesn't mode equals current mode, i.e. user overrode our changes
|
|
// 2) TRR mode equals 5, i.e. user clicked "No" on doorhanger
|
|
// 3) TRR mode equals 3, i.e. user enabled "strictly on" for DoH
|
|
// 4) They've been disabled in the past for the reasons listed above
|
|
//
|
|
// In other words, if the user has made their own decision for DoH,
|
|
// then we want to respect that and never run the heuristics again
|
|
|
|
if (prevMode === curMode) {
|
|
return true;
|
|
}
|
|
|
|
// On Mismatch - run never run again (make init check a function)
|
|
log("Mismatched, curMode: ", curMode);
|
|
|
|
// Cache results for Telemetry send, including setting eval reason
|
|
let results = await runHeuristics();
|
|
results.evaluateReason = "userModified";
|
|
if (curMode === 0 || curMode === 5) {
|
|
// If user has manually set trr.mode to 0, and it was previously something else.
|
|
browser.experiments.heuristics.sendHeuristicsPing("disable_doh", results);
|
|
browser.experiments.preferences.clearUserPref(DOH_SELF_ENABLED_PREF);
|
|
await stateManager.rememberDisableHeuristics();
|
|
} else {
|
|
// Check if trr.mode is not in default value.
|
|
await rollout.trrModePrefHasUserValue(
|
|
"shouldRunHeuristics_mismatch",
|
|
results
|
|
);
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
async shouldShowDoorhanger() {
|
|
let doorhangerShown = await rollout.getSetting(
|
|
DOH_DOORHANGER_SHOWN_PREF,
|
|
false
|
|
);
|
|
log("Should show doorhanger:", !doorhangerShown);
|
|
|
|
return !doorhangerShown;
|
|
},
|
|
|
|
async showDoorhanger() {
|
|
rollout.addDoorhangerListeners();
|
|
|
|
let doorhangerShown = await browser.experiments.doorhanger.show({
|
|
name: browser.i18n.getMessage("doorhangerName"),
|
|
text: "<> " + browser.i18n.getMessage("doorhangerBodyNew"),
|
|
okLabel: browser.i18n.getMessage("doorhangerButtonOk"),
|
|
okAccessKey: browser.i18n.getMessage("doorhangerButtonOkAccessKey"),
|
|
cancelLabel: browser.i18n.getMessage("doorhangerButtonCancel2"),
|
|
cancelAccessKey: browser.i18n.getMessage(
|
|
"doorhangerButtonCancelAccessKey"
|
|
),
|
|
});
|
|
|
|
if (!doorhangerShown) {
|
|
// The profile was created after the go-live date of the privacy statement
|
|
// that included DoH. Treat it as accepted.
|
|
log("Profile is new, doorhanger not shown.");
|
|
await stateManager.setState("UIOk");
|
|
await stateManager.rememberDoorhangerDecision("NewProfile");
|
|
await stateManager.rememberDoorhangerShown();
|
|
rollout.removeDoorhangerListeners();
|
|
}
|
|
},
|
|
};
|
|
|
|
const rollout = {
|
|
// Pretend that there was a network change at the beginning of time.
|
|
lastNetworkChangeTime: 0,
|
|
|
|
async isTesting() {
|
|
if (this._isTesting === undefined) {
|
|
this._isTesting = await browser.experiments.heuristics.isTesting();
|
|
}
|
|
|
|
return this._isTesting;
|
|
},
|
|
|
|
addDoorhangerListeners() {
|
|
browser.experiments.doorhanger.onDoorhangerAccept.addListener(
|
|
rollout.doorhangerAcceptListener
|
|
);
|
|
|
|
browser.experiments.doorhanger.onDoorhangerDecline.addListener(
|
|
rollout.doorhangerDeclineListener
|
|
);
|
|
},
|
|
|
|
removeDoorhangerListeners() {
|
|
browser.experiments.doorhanger.onDoorhangerAccept.removeListener(
|
|
rollout.doorhangerAcceptListener
|
|
);
|
|
|
|
browser.experiments.doorhanger.onDoorhangerDecline.removeListener(
|
|
rollout.doorhangerDeclineListener
|
|
);
|
|
},
|
|
|
|
async doorhangerAcceptListener(tabId) {
|
|
log("Doorhanger accepted on tab", tabId);
|
|
await stateManager.setState("UIOk");
|
|
await stateManager.rememberDoorhangerDecision("UIOk");
|
|
await stateManager.rememberDoorhangerShown();
|
|
rollout.removeDoorhangerListeners();
|
|
},
|
|
|
|
async doorhangerDeclineListener(tabId) {
|
|
log("Doorhanger declined on tab", tabId);
|
|
await stateManager.setState("UIDisabled");
|
|
await stateManager.rememberDoorhangerDecision("UIDisabled");
|
|
let results = await runHeuristics();
|
|
results.evaluateReason = "doorhangerDecline";
|
|
browser.experiments.heuristics.sendHeuristicsPing("disable_doh", results);
|
|
await stateManager.rememberDisableHeuristics();
|
|
await stateManager.rememberDoorhangerShown();
|
|
rollout.removeDoorhangerListeners();
|
|
},
|
|
|
|
async heuristics(evaluateReason) {
|
|
let shouldRunHeuristics = await stateManager.shouldRunHeuristics();
|
|
|
|
if (!shouldRunHeuristics) {
|
|
return;
|
|
}
|
|
|
|
// Run heuristics defined in heuristics.js and experiments/heuristics/api.js
|
|
let results;
|
|
|
|
if (await rollout.isTesting()) {
|
|
results = await browser.experiments.preferences.getCharPref(
|
|
MOCK_HEURISTICS_PREF,
|
|
`{ "test": "disable_doh" }`
|
|
);
|
|
results = JSON.parse(results);
|
|
} else {
|
|
results = await runHeuristics();
|
|
}
|
|
|
|
// Check if DoH should be disabled
|
|
let decision = Object.values(results).includes("disable_doh")
|
|
? "disable_doh"
|
|
: "enable_doh";
|
|
|
|
log("Heuristics decision on " + evaluateReason + ": " + decision);
|
|
|
|
// Send Telemetry on results of heuristics
|
|
results.evaluateReason = evaluateReason;
|
|
browser.experiments.heuristics.sendHeuristicsPing(decision, results);
|
|
|
|
if (decision === "disable_doh") {
|
|
await stateManager.setState("disabled");
|
|
} else {
|
|
await stateManager.setState("enabled");
|
|
if (await stateManager.shouldShowDoorhanger()) {
|
|
await stateManager.showDoorhanger();
|
|
}
|
|
}
|
|
},
|
|
|
|
async getSetting(name, defaultValue) {
|
|
let value;
|
|
|
|
switch (typeof defaultValue) {
|
|
case "boolean":
|
|
value = await browser.experiments.preferences.getBoolPref(
|
|
name,
|
|
defaultValue
|
|
);
|
|
break;
|
|
case "number":
|
|
value = await browser.experiments.preferences.getIntPref(
|
|
name,
|
|
defaultValue
|
|
);
|
|
break;
|
|
case "string":
|
|
value = await browser.experiments.preferences.getCharPref(
|
|
name,
|
|
defaultValue
|
|
);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Invalid defaultValue argument when trying to fetch pref: ${JSON.stringify(
|
|
name
|
|
)}`
|
|
);
|
|
}
|
|
|
|
log({
|
|
context: "getSetting",
|
|
type: typeof defaultValue,
|
|
name,
|
|
value,
|
|
});
|
|
|
|
return value;
|
|
},
|
|
|
|
/**
|
|
* Exposed
|
|
*
|
|
* @param {type} name description
|
|
* @param {type} value description
|
|
* @return {type} description
|
|
*/
|
|
async setSetting(name, value) {
|
|
// Based on type of pref, set pref accordingly
|
|
switch (typeof value) {
|
|
case "boolean":
|
|
await browser.experiments.preferences.setBoolPref(name, value);
|
|
break;
|
|
case "number":
|
|
await browser.experiments.preferences.setIntPref(name, value);
|
|
break;
|
|
case "string":
|
|
await browser.experiments.preferences.setCharPref(name, value);
|
|
break;
|
|
default:
|
|
throw new Error("setSetting typeof value unknown!");
|
|
}
|
|
|
|
log({
|
|
context: "setSetting",
|
|
type: typeof value,
|
|
name,
|
|
value,
|
|
});
|
|
},
|
|
|
|
async trrModePrefHasUserValue(event, results) {
|
|
results.evaluateReason = event;
|
|
|
|
// This confirms if a user has modified DoH (via the TRR_MODE_PREF) outside of the addon
|
|
// This runs only on the FIRST time that add-on is enabled and if the stored pref
|
|
// mismatches the current pref (Meaning something outside of the add-on has changed it)
|
|
|
|
if (await browser.experiments.preferences.prefHasUserValue(TRR_MODE_PREF)) {
|
|
// Send ping that user had specific trr.mode pref set before add-on study was ran.
|
|
// Note that this does not include the trr.mode - just that the addon cannot be ran.
|
|
browser.experiments.heuristics.sendHeuristicsPing(
|
|
"prefHasUserValue",
|
|
results
|
|
);
|
|
|
|
browser.experiments.preferences.clearUserPref(DOH_SELF_ENABLED_PREF);
|
|
await this.setSetting(DOH_SKIP_HEURISTICS_PREF, true);
|
|
await stateManager.rememberDisableHeuristics();
|
|
}
|
|
},
|
|
|
|
async enterprisePolicyCheck(event, results) {
|
|
results.evaluateReason = event;
|
|
|
|
// Check if trrModePrefHasUserValue determined to not enable add-on on first run
|
|
let skipHeuristicsCheck = await rollout.getSetting(
|
|
DOH_SKIP_HEURISTICS_PREF,
|
|
false
|
|
);
|
|
|
|
if (skipHeuristicsCheck) {
|
|
return;
|
|
}
|
|
|
|
// Check for Policies before running the rest of the heuristics
|
|
let policyEnableDoH = await browser.experiments.heuristics.checkEnterprisePolicies();
|
|
|
|
log("Enterprise Policy Check:", policyEnableDoH);
|
|
|
|
// Determine to skip additional heuristics (by presence of an enterprise policy)
|
|
|
|
if (policyEnableDoH === "no_policy_set") {
|
|
// Resetting skipHeuristicsCheck in case a user had a policy and then removed it!
|
|
await this.setSetting(DOH_SKIP_HEURISTICS_PREF, false);
|
|
return;
|
|
}
|
|
|
|
if (policyEnableDoH === "policy_without_doh") {
|
|
await stateManager.setState("disabled");
|
|
}
|
|
|
|
// Don't check for prefHasUserValue if policy is set to disable DoH
|
|
await this.setSetting(DOH_SKIP_HEURISTICS_PREF, true);
|
|
|
|
browser.experiments.heuristics.sendHeuristicsPing(policyEnableDoH, results);
|
|
},
|
|
|
|
async migrateLocalStoragePrefs() {
|
|
// Migrate updated local storage item names. If this has already been done once, skip the migration
|
|
const isMigrated = await browser.experiments.preferences.getBoolPref(
|
|
DOH_BALROG_MIGRATION_PREF,
|
|
false
|
|
);
|
|
|
|
if (isMigrated) {
|
|
log("User has already been migrated.");
|
|
return;
|
|
}
|
|
|
|
// Check all local storage keys from v1.0.4 users and migrate them to prefs.
|
|
// This only applies to keys that have a value.
|
|
const legacyLocalStorageKeys = [
|
|
"doneFirstRun",
|
|
"skipHeuristicsCheck",
|
|
DOH_PREVIOUS_TRR_MODE_PREF,
|
|
DOH_DOORHANGER_SHOWN_PREF,
|
|
DOH_DOORHANGER_USER_DECISION_PREF,
|
|
DOH_DISABLED_PREF,
|
|
];
|
|
|
|
for (let item of legacyLocalStorageKeys) {
|
|
let data = await browser.storage.local.get(item);
|
|
let value = data[item];
|
|
|
|
log({ context: "migration", item, value });
|
|
|
|
if (data.hasOwnProperty(item)) {
|
|
let migratedName = item;
|
|
|
|
if (!item.startsWith("doh-rollout.")) {
|
|
migratedName = "doh-rollout." + item;
|
|
}
|
|
|
|
await this.setSetting(migratedName, value);
|
|
}
|
|
}
|
|
|
|
// Set pref to skip this function in the future.
|
|
browser.experiments.preferences.setBoolPref(
|
|
DOH_BALROG_MIGRATION_PREF,
|
|
true
|
|
);
|
|
|
|
log("User successfully migrated.");
|
|
},
|
|
|
|
async init() {
|
|
log("calling init");
|
|
// Check if the add-on has run before
|
|
let doneFirstRun = await this.getSetting(DOH_DONE_FIRST_RUN_PREF, false);
|
|
|
|
// Register the events for sending pings
|
|
browser.experiments.heuristics.setupTelemetry();
|
|
|
|
// Cache runHeuristics results for first run/start up checks
|
|
let results = await runHeuristics();
|
|
|
|
if (!doneFirstRun) {
|
|
log("first run!");
|
|
await this.setSetting(DOH_DONE_FIRST_RUN_PREF, true);
|
|
// Check if user has a set a custom pref only on first run, not on each startup
|
|
await this.trrModePrefHasUserValue("first_run", results);
|
|
await this.enterprisePolicyCheck("first_run", results);
|
|
} else {
|
|
log("not first run!");
|
|
await this.enterprisePolicyCheck("startup", results);
|
|
}
|
|
|
|
if (!(await stateManager.shouldRunHeuristics())) {
|
|
return;
|
|
}
|
|
|
|
// Perform TRR selection before running heuristics.
|
|
await browser.experiments.trrselect.dryRun();
|
|
log("TRR selection dry run complete!");
|
|
|
|
let networkStatus = (await browser.networkStatus.getLinkInfo()).status;
|
|
let captiveState = "unknown";
|
|
try {
|
|
captiveState = await browser.captivePortal.getState();
|
|
} catch (e) {
|
|
// Captive Portal Service is disabled.
|
|
}
|
|
|
|
if (networkStatus == "up" && captiveState != "locked_portal") {
|
|
await rollout.heuristics("startup");
|
|
}
|
|
|
|
// Listen for network change events to run heuristics again
|
|
browser.networkStatus.onConnectionChanged.addListener(
|
|
rollout.onConnectionChanged
|
|
);
|
|
|
|
// Listen to the captive portal when it unlocks
|
|
try {
|
|
browser.captivePortal.onStateChange.addListener(
|
|
rollout.onCaptiveStateChanged
|
|
);
|
|
} catch (e) {
|
|
// Captive Portal Service is disabled.
|
|
}
|
|
},
|
|
|
|
async onConnectionChanged({ status }) {
|
|
log("onConnectionChanged", status);
|
|
|
|
if (status != "up") {
|
|
return;
|
|
}
|
|
|
|
let captiveState = "unknown";
|
|
try {
|
|
captiveState = await browser.captivePortal.getState();
|
|
} catch (e) {
|
|
// Captive Portal Service is disabled.
|
|
}
|
|
|
|
if (captiveState == "locked_portal") {
|
|
return;
|
|
}
|
|
|
|
// The network is up and we don't know that we're in a locked portal.
|
|
// Run heuristics. If we detect a portal later, we'll run heuristics again
|
|
// when it's unlocked. In that case, this run will likely have failed.
|
|
await rollout.heuristics("netchange");
|
|
},
|
|
|
|
async onCaptiveStateChanged({ state }) {
|
|
log("onCaptiveStateChanged", state);
|
|
// unlocked_portal means we were previously in a locked portal and then
|
|
// network access was granted.
|
|
if (state == "unlocked_portal") {
|
|
await rollout.heuristics("netchange");
|
|
}
|
|
},
|
|
};
|
|
|
|
const setup = {
|
|
async start() {
|
|
const isAddonDisabled = await rollout.getSetting(DOH_DISABLED_PREF, false);
|
|
const runAddonPref = await rollout.getSetting(DOH_ENABLED_PREF, false);
|
|
const runAddonBypassPref = await rollout.getSetting(
|
|
DOH_SELF_ENABLED_PREF,
|
|
false
|
|
);
|
|
const runAddonDoorhangerDecision = await rollout.getSetting(
|
|
DOH_DOORHANGER_USER_DECISION_PREF,
|
|
""
|
|
);
|
|
const runAddonPreviousTRRMode = await rollout.getSetting(
|
|
DOH_PREVIOUS_TRR_MODE_PREF,
|
|
-1
|
|
);
|
|
|
|
if (isAddonDisabled) {
|
|
// Regardless of pref, the user has chosen/heuristics dictated that this add-on should be disabled.
|
|
// DoH status will not be modified from whatever the current setting is at runtime
|
|
log(
|
|
"Addon has been disabled. DoH status will not be modified from current setting"
|
|
);
|
|
await stateManager.rememberDisableHeuristics();
|
|
return;
|
|
}
|
|
|
|
if (
|
|
runAddonPref ||
|
|
runAddonBypassPref ||
|
|
runAddonDoorhangerDecision === "UIOk" ||
|
|
runAddonDoorhangerDecision === "enabled" ||
|
|
runAddonPreviousTRRMode === 2 ||
|
|
runAddonPreviousTRRMode === 0
|
|
) {
|
|
rollout.init();
|
|
} else {
|
|
log("Disabled, aborting!");
|
|
}
|
|
},
|
|
};
|
|
|
|
(async () => {
|
|
DEBUG = await browser.experiments.preferences.getBoolPref(
|
|
DOH_DEBUG_PREF,
|
|
false
|
|
);
|
|
|
|
// Run Migration First, to continue to run rest of start up logic
|
|
await rollout.migrateLocalStoragePrefs();
|
|
|
|
log("Watching `doh-rollout.enabled` pref");
|
|
browser.experiments.preferences.onPrefChanged.addListener(async () => {
|
|
let enabled = await rollout.getSetting(DOH_ENABLED_PREF, false);
|
|
if (enabled) {
|
|
setup.start();
|
|
} else {
|
|
// Reset the TRR mode if we were running normally with no user-interference.
|
|
if (await stateManager.shouldRunHeuristics()) {
|
|
await stateManager.setState("disabled");
|
|
}
|
|
|
|
// Remove our listeners.
|
|
browser.networkStatus.onConnectionChanged.removeListener(
|
|
rollout.onConnectionChanged
|
|
);
|
|
|
|
try {
|
|
browser.captivePortal.onStateChange.removeListener(
|
|
rollout.onCaptiveStateChanged
|
|
);
|
|
} catch (e) {
|
|
// Captive Portal Service is disabled.
|
|
}
|
|
}
|
|
});
|
|
|
|
if (await rollout.getSetting(DOH_ENABLED_PREF, false)) {
|
|
await setup.start();
|
|
} else if (
|
|
(await rollout.getSetting(DOH_DONE_FIRST_RUN_PREF, false)) &&
|
|
(await stateManager.shouldRunHeuristics())
|
|
) {
|
|
// We previously had turned on DoH, and now after a restart we've been
|
|
// rolled back. Reset TRR mode.
|
|
await stateManager.setState("disabled");
|
|
}
|
|
})();
|