Add kill switch mechanism
This code implements the kill switch mechanism in the extension. This is
explained in //src/killSwitch/README.md and in the design doc:
https://docs.google.com/document/d/1O5YV6_WcxwrUyz-lwHOSTfZ3oyIFWj2EQee0VuKkhaA/edit.
Bug: twpowertools:64
Change-Id: Ia993c78035bba7038aafd53d156f20954217e86f
diff --git a/src/killSwitch/index.js b/src/killSwitch/index.js
new file mode 100644
index 0000000..1456a51
--- /dev/null
+++ b/src/killSwitch/index.js
@@ -0,0 +1,79 @@
+import {compareLoose} from 'semver';
+
+import {getExtVersion, isFirefox} from '../common/extUtils.js';
+
+import * as commonPb from './api_proto/common_pb.js';
+import {KillSwitchServicePromiseClient} from './api_proto/kill_switch_grpc_web_pb.js';
+import * as ksPb from './api_proto/kill_switch_pb.js';
+
+const host =
+ (PRODUCTION ? 'https://twpt-grpc-web.avm99963.com/' :
+ 'http://localhost:8081');
+
+export default class KillSwitchMechanism {
+ constructor() {
+ this.client = new KillSwitchServicePromiseClient(host, null, null);
+ }
+
+ getCurrentBrowser() {
+ if (isFirefox()) return commonPb.Environment.Browser.BROWSER_GECKO;
+ return commonPb.Environment.Browser.BROWSER_CHROMIUM;
+ }
+
+ updateKillSwitchStatus() {
+ let request = new ksPb.GetKillSwitchOverviewRequest();
+ request.setWithNonactiveKillSwitches(false);
+
+ this.client.getKillSwitchOverview(request)
+ .then(res => {
+ let killSwitches = res.getKillSwitchesList();
+ let currentVersion = getExtVersion();
+ if (currentVersion === '0') currentVersion = '0.0.0';
+
+ let forceDisabledFeaturesSet = new Set();
+ for (let killSwitch of killSwitches) {
+ // If it isn't active, this kill switch is not applicable.
+ if (!killSwitch.getActive()) continue;
+
+ // If min_version is set and is greater than the current version,
+ // this kill switch is not applicable.
+ if (killSwitch.getMinVersion() != '' &&
+ compareLoose(killSwitch.getMinVersion(), currentVersion) == 1)
+ continue;
+
+ // If max_version is set and is less than the current version, this
+ // kill switch is not applicable.
+ if (killSwitch.getMaxVersion() != '' &&
+ compareLoose(killSwitch.getMaxVersion(), currentVersion) == -1)
+ continue;
+
+ let browsers = killSwitch.getBrowsersList();
+ let currentBrowser = this.getCurrentBrowser();
+
+ // If this browser isn't included as part of the kill switch, the
+ // kill switch is not applicable.
+ if (!browsers.includes(currentBrowser)) continue;
+
+ console.warn(
+ 'Kill switch ' + killSwitch.getId() + ' will be applied!');
+
+ let featureCodename = killSwitch.getFeature()?.getCodename?.();
+ if (featureCodename) forceDisabledFeaturesSet.add(featureCodename);
+ }
+
+ let forceDisabledFeatures = Array.from(forceDisabledFeaturesSet);
+
+ chrome.storage.sync.set(
+ {_forceDisabledFeatures: forceDisabledFeatures}, () => {
+ if (forceDisabledFeatures.length > 0) {
+ // TODO(avm99963): show a badge to warn that some features
+ // have been force disabled.
+ }
+ });
+ })
+ .catch(err => {
+ console.error(
+ '[killSwitch] Can\'t retrieve kill switch status: ', err);
+ });
+ }
+};