Allow features to require optional permissions

Design doc:
https://docs.google.com/document/d/1OhL0Yh7SmWffXyjW_XVQOK95Fqh7gLltk1eEtnKN8Ds/edit

Fixed: twpowertools:86
Change-Id: Iccb22aac2b285307854b7a4c002e9702c24d57f2
diff --git a/src/sw.js b/src/sw.js
index 73efa06..fce78d2 100644
--- a/src/sw.js
+++ b/src/sw.js
@@ -1,7 +1,8 @@
 // IMPORTANT: keep this file in sync with background.js
 import XMLHttpRequest from 'sw-xhr';
 
-import {cleanUpOptions} from './common/optionsUtils.js';
+import {cleanUpOptPermissions} from './common/optionsPermissions.js';
+import {cleanUpOptions, disableItemsWithMissingPermissions} from './common/optionsUtils.js';
 import KillSwitchMechanism from './killSwitch/index.js';
 
 // XMLHttpRequest is not present in service workers and is required by the
@@ -40,3 +41,34 @@
     killSwitchMechanism.updateKillSwitchStatus();
   }
 });
+
+// Clean up optional permissions and check that none are missing for enabled
+// features as soon as the extension starts and when the options change.
+cleanUpOptPermissions();
+
+chrome.storage.sync.onChanged.addListener(() => {
+  cleanUpOptPermissions();
+});
+
+chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
+  if (sender.id !== chrome.runtime.id)
+    return console.warn(
+        'An unknown sender (' + sender.id +
+            ') sent a message to the extension: ',
+        msg);
+
+  console.assert(msg.message);
+  switch (msg.message) {
+    case 'runDisableItemsWithMissingPermissions':
+      console.assert(
+          msg.options?.items && msg.options?.permissionChecksFeatures);
+      disableItemsWithMissingPermissions(
+          msg.options?.items, msg.options?.permissionChecksFeatures)
+          .then(items => sendResponse({status: 'resolved', items}))
+          .catch(error => sendResponse({status: 'rejected', error}));
+      break;
+
+    default:
+      console.warn('Unknown message "' + msg.message + '".');
+  }
+});