Bug 1875768 - Call the appropriate postfork handler on MacOS r=glandium
[gecko.git] / toolkit / modules / RemotePageAccessManager.sys.mjs
blob838f6e9157d0b9256131ae181fba628dbcee822e
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6  * RemotePageAccessManager determines which RPM functions a given
7  * about page is allowed to access. It does this based on a map from about
8  * page URLs to allowed functions for that page/URL.
9  *
10  * An RPM function will be exported into the page only if it appears
11  * in the access managers's accessMap for that page's uri.
12  *
13  * This module may be used from both the child and parent process.
14  *
15  * Please note that prefs that one wants to update need to be
16  * explicitly allowed within AsyncPrefs.sys.mjs.
17  */
18 export let RemotePageAccessManager = {
19   /* The accessMap lists the permissions that are allowed per page.
20    * The structure should be of the following form:
21    *   <URL> : {
22    *     <function name>: [<keys>],
23    *     ...
24    *   }
25    * For the page with given URL, permission is allowed for each
26    * listed function with a matching key. The first argument to the
27    * function must match one of the keys. If keys is an array with a
28    * single asterisk element ["*"], then all values are permitted.
29    */
30   accessMap: {
31     "about:certerror": {
32       RPMSendAsyncMessage: [
33         "Browser:EnableOnlineMode",
34         "Browser:ResetSSLPreferences",
35         "GetChangedCertPrefs",
36         "Browser:OpenCaptivePortalPage",
37         "Browser:SSLErrorGoBack",
38         "Browser:PrimeMitm",
39         "Browser:ResetEnterpriseRootsPref",
40         "DisplayOfflineSupportPage",
41       ],
42       RPMRecordTelemetryEvent: ["*"],
43       RPMAddMessageListener: ["*"],
44       RPMRemoveMessageListener: ["*"],
45       RPMGetFormatURLPref: ["app.support.baseURL"],
46       RPMGetBoolPref: [
47         "security.certerrors.mitm.priming.enabled",
48         "security.certerrors.permanentOverride",
49         "security.enterprise_roots.auto-enabled",
50         "security.certerror.hideAddException",
51         "network.trr.display_fallback_warning",
52       ],
53       RPMGetIntPref: [
54         "security.dialog_enable_delay",
55         "services.settings.clock_skew_seconds",
56         "services.settings.last_update_seconds",
57       ],
58       RPMGetAppBuildID: ["*"],
59       RPMGetInnerMostURI: ["*"],
60       RPMIsWindowPrivate: ["*"],
61       RPMAddToHistogram: ["*"],
62     },
63     "about:home": {
64       RPMSendAsyncMessage: ["ActivityStream:ContentToMain"],
65       RPMAddMessageListener: ["ActivityStream:MainToContent"],
66     },
67     "about:httpsonlyerror": {
68       RPMGetFormatURLPref: ["app.support.baseURL"],
69       RPMGetIntPref: ["security.dialog_enable_delay"],
70       RPMSendAsyncMessage: ["goBack", "openInsecure"],
71       RPMAddMessageListener: ["WWWReachable"],
72       RPMTryPingSecureWWWLink: ["*"],
73       RPMOpenSecureWWWLink: ["*"],
74     },
75     "about:certificate": {
76       RPMSendQuery: ["getCertificates"],
77     },
78     "about:neterror": {
79       RPMSendAsyncMessage: [
80         "Browser:EnableOnlineMode",
81         "Browser:ResetSSLPreferences",
82         "GetChangedCertPrefs",
83         "Browser:OpenCaptivePortalPage",
84         "Browser:SSLErrorGoBack",
85         "Browser:PrimeMitm",
86         "Browser:ResetEnterpriseRootsPref",
87         "ReportBlockingError",
88         "DisplayOfflineSupportPage",
89         "OpenTRRPreferences",
90       ],
91       RPMCheckAlternateHostAvailable: ["*"],
92       RPMRecordTelemetryEvent: [
93         "security.doh.neterror",
94         "security.ui.tlserror",
95       ],
96       RPMAddMessageListener: ["*"],
97       RPMRemoveMessageListener: ["*"],
98       RPMGetFormatURLPref: [
99         "app.support.baseURL",
100         "network.trr_ui.skip_reason_learn_more_url",
101       ],
102       RPMGetBoolPref: [
103         "security.certerror.hideAddException",
104         "security.xfocsp.errorReporting.automatic",
105         "security.xfocsp.errorReporting.enabled",
106         "security.xfocsp.hideOpenInNewWindow",
107         "network.trr.display_fallback_warning",
108       ],
109       RPMSetPref: [
110         "security.xfocsp.errorReporting.automatic",
111         "network.trr.display_fallback_warning",
112       ],
113       RPMAddToHistogram: ["*"],
114       RPMGetInnerMostURI: ["*"],
115       RPMGetHttpResponseHeader: ["*"],
116       RPMIsTRROnlyFailure: ["*"],
117       RPMIsFirefox: ["*"],
118       RPMIsNativeFallbackFailure: ["*"],
119       RPMGetTRRSkipReason: ["*"],
120       RPMGetTRRDomain: ["*"],
121       RPMIsSiteSpecificTRRError: ["*"],
122       RPMSetTRRDisabledLoadFlags: ["*"],
123       RPMSendQuery: ["Browser:AddTRRExcludedDomain"],
124       RPMGetIntPref: ["network.trr.mode"],
125     },
126     "about:newtab": {
127       RPMSendAsyncMessage: ["ActivityStream:ContentToMain"],
128       RPMAddMessageListener: ["ActivityStream:MainToContent"],
129     },
130     "about:pocket-saved": {
131       RPMSendAsyncMessage: ["*"],
132       RPMAddMessageListener: ["*"],
133       RPMRemoveMessageListener: ["*"],
134       RPMGetStringPref: ["extensions.pocket.site"],
135     },
136     "about:pocket-signup": {
137       RPMSendAsyncMessage: ["*"],
138       RPMAddMessageListener: ["*"],
139       RPMRemoveMessageListener: ["*"],
140       RPMGetStringPref: ["extensions.pocket.site"],
141     },
142     "about:pocket-home": {
143       RPMSendAsyncMessage: ["*"],
144       RPMAddMessageListener: ["*"],
145       RPMRemoveMessageListener: ["*"],
146       RPMGetStringPref: ["extensions.pocket.site"],
147     },
148     "about:pocket-style-guide": {
149       RPMSendAsyncMessage: ["*"],
150       RPMAddMessageListener: ["*"],
151       RPMRemoveMessageListener: ["*"],
152     },
153     "about:privatebrowsing": {
154       RPMSendAsyncMessage: [
155         "OpenPrivateWindow",
156         "SearchBannerDismissed",
157         "OpenSearchPreferences",
158         "SearchHandoff",
159       ],
160       RPMSendQuery: [
161         "IsPromoBlocked",
162         "ShouldShowSearchBanner",
163         "ShouldShowPromo",
164         "SpecialMessageActionDispatch",
165       ],
166       RPMAddMessageListener: ["*"],
167       RPMRemoveMessageListener: ["*"],
168       RPMGetFormatURLPref: [
169         "app.support.baseURL",
170         "browser.privatebrowsing.vpnpromourl",
171       ],
172       RPMIsWindowPrivate: ["*"],
173       RPMGetBoolPref: ["browser.privatebrowsing.felt-privacy-v1"],
174     },
175     "about:protections": {
176       RPMSendAsyncMessage: [
177         "OpenContentBlockingPreferences",
178         "OpenAboutLogins",
179         "OpenSyncPreferences",
180         "ClearMonitorCache",
181         "RecordEntryPoint",
182       ],
183       RPMSendQuery: [
184         "FetchUserLoginsData",
185         "FetchMonitorData",
186         "FetchContentBlockingEvents",
187         "FetchMobileDeviceConnected",
188         "GetShowProxyCard",
189         "FetchEntryPoint",
190         "FetchVPNSubStatus",
191         "FetchShowVPNCard",
192       ],
193       RPMAddMessageListener: ["*"],
194       RPMRemoveMessageListener: ["*"],
195       RPMSetPref: [
196         "browser.contentblocking.report.show_mobile_app",
197         "browser.contentblocking.report.hide_vpn_banner",
198       ],
199       RPMGetBoolPref: [
200         "browser.contentblocking.report.lockwise.enabled",
201         "browser.contentblocking.report.monitor.enabled",
202         "privacy.fingerprintingProtection",
203         "privacy.socialtracking.block_cookies.enabled",
204         "browser.contentblocking.report.proxy.enabled",
205         "privacy.trackingprotection.cryptomining.enabled",
206         "privacy.trackingprotection.fingerprinting.enabled",
207         "privacy.trackingprotection.enabled",
208         "privacy.trackingprotection.socialtracking.enabled",
209         "browser.contentblocking.report.show_mobile_app",
210         "browser.contentblocking.report.hide_vpn_banner",
211         "browser.vpn_promo.enabled",
212       ],
213       RPMGetStringPref: [
214         "browser.contentblocking.category",
215         "browser.contentblocking.report.monitor.url",
216         "browser.contentblocking.report.monitor.sign_in_url",
217         "browser.contentblocking.report.manage_devices.url",
218         "browser.contentblocking.report.proxy_extension.url",
219         "browser.contentblocking.report.lockwise.mobile-android.url",
220         "browser.contentblocking.report.lockwise.mobile-ios.url",
221         "browser.contentblocking.report.mobile-ios.url",
222         "browser.contentblocking.report.mobile-android.url",
223         "browser.contentblocking.report.vpn.url",
224         "browser.contentblocking.report.vpn-promo.url",
225         "browser.contentblocking.report.vpn-android.url",
226         "browser.contentblocking.report.vpn-ios.url",
227       ],
228       RPMGetIntPref: ["network.cookie.cookieBehavior"],
229       RPMGetFormatURLPref: [
230         "browser.contentblocking.report.monitor.how_it_works.url",
231         "browser.contentblocking.report.lockwise.how_it_works.url",
232         "browser.contentblocking.report.monitor.preferences_url",
233         "browser.contentblocking.report.monitor.home_page_url",
234         "browser.contentblocking.report.social.url",
235         "browser.contentblocking.report.cookie.url",
236         "browser.contentblocking.report.tracker.url",
237         "browser.contentblocking.report.fingerprinter.url",
238         "browser.contentblocking.report.cryptominer.url",
239       ],
240       RPMRecordTelemetryEvent: ["*"],
241     },
242     "about:shoppingsidebar": {
243       RPMSetPref: [
244         "browser.shopping.experience2023.optedIn",
245         "browser.shopping.experience2023.active",
246         "browser.shopping.experience2023.ads.userEnabled",
247         "browser.shopping.experience2023.sidebarClosedCount",
248         "browser.shopping.experience2023.showKeepSidebarClosedMessage",
249         "browser.shopping.experience2023.autoOpen.userEnabled",
250       ],
251       RPMGetFormatURLPref: ["app.support.baseURL"],
252       RPMGetIntPref: ["browser.shopping.experience2023.sidebarClosedCount"],
253       RPMGetBoolPref: [
254         "browser.shopping.experience2023.showKeepSidebarClosedMessage",
255       ],
256     },
257     "about:tabcrashed": {
258       RPMSendAsyncMessage: ["Load", "closeTab", "restoreTab", "restoreAll"],
259       RPMAddMessageListener: ["*"],
260       RPMRemoveMessageListener: ["*"],
261     },
262     "about:welcome": {
263       RPMSendAsyncMessage: ["ActivityStream:ContentToMain"],
264       RPMAddMessageListener: ["ActivityStream:MainToContent"],
265     },
266   },
268   /**
269    * Check if access is allowed to the given feature for a given document.
270    * This should be called from within the child process.
271    *
272    * The feature within the accessMap must list the given aValue, for access to
273    * be granted.
274    *
275    * @param aDocument child process document to call from
276    * @param aFeature to feature to check access to
277    * @param aValue value that must be included with that feature's allow list
278    * @returns true if access is allowed or false otherwise
279    */
280   checkAllowAccess(aDocument, aFeature, aValue) {
281     let principal = aDocument.nodePrincipal;
282     // if there is no content principal; deny access
283     if (!principal) {
284       return false;
285     }
287     return this.checkAllowAccessWithPrincipal(
288       principal,
289       aFeature,
290       aValue,
291       aDocument
292     );
293   },
295   /**
296    * Check if access is allowed to the given feature for a given principal.
297    * This may be called from within the child or parent process.
298    *
299    * The feature within the accessMap must list the given aValue, for access to
300    * be granted.
301    *
302    * In the parent process, the passed-in document is expected to be null.
303    *
304    * @param aPrincipal principal being called from
305    * @param aFeature to feature to check access to
306    * @param aValue value that must be included with that feature's allow list
307    * @param aDocument optional child process document to call from
308    * @returns true if access is allowed or false otherwise
309    */
310   checkAllowAccessWithPrincipal(aPrincipal, aFeature, aValue, aDocument) {
311     let accessMapForFeature = this.checkAllowAccessToFeature(
312       aPrincipal,
313       aFeature,
314       aDocument
315     );
316     if (!accessMapForFeature) {
317       console.error(
318         "RemotePageAccessManager does not allow access to Feature: ",
319         aFeature,
320         " for: ",
321         aDocument.location
322       );
324       return false;
325     }
327     // If the actual value is in the allow list for that feature;
328     // allow access
329     if (accessMapForFeature.includes(aValue) || accessMapForFeature[0] == "*") {
330       return true;
331     }
333     return false;
334   },
336   /**
337    * Check if a particular feature can be accessed without checking for a
338    * specific feature value.
339    *
340    * @param aPrincipal principal being called from
341    * @param aFeature to feature to check access to
342    * @param aDocument optional child process document to call from
343    * @returns non-null allow list if access is allowed or null otherwise
344    */
345   checkAllowAccessToFeature(aPrincipal, aFeature, aDocument) {
346     let spec;
347     if (!aPrincipal.isContentPrincipal) {
348       // For the sake of remote pages, when the principal has no uri,
349       // we want to access the "real" document URI directly, e.g. if the
350       // about: page is sandboxed.
351       if (!aDocument) {
352         return null;
353       }
354       if (!aDocument.documentURIObject.schemeIs("about")) {
355         return null;
356       }
357       spec =
358         aDocument.documentURIObject.prePath +
359         aDocument.documentURIObject.filePath;
360     } else {
361       if (!aPrincipal.schemeIs("about")) {
362         return null;
363       }
364       spec = aPrincipal.prePath + aPrincipal.filePath;
365     }
367     // Check if there is an entry for that requestying URI in the accessMap;
368     // if not, deny access.
369     let accessMapForURI = this.accessMap[spec];
370     if (!accessMapForURI) {
371       return null;
372     }
374     // Check if the feature is allowed to be accessed for that URI;
375     // if not, deny access.
376     return accessMapForURI[aFeature];
377   },
379   /**
380    * This function adds a new page to the access map, but can only
381    * be used in a test environment.
382    */
383   addPage(aUrl, aFunctionMap) {
384     if (!Cu.isInAutomation) {
385       throw new Error("Cannot only modify privileges during testing");
386     }
388     if (aUrl in this.accessMap) {
389       throw new Error("Cannot modify privileges of existing page");
390     }
392     this.accessMap[aUrl] = aFunctionMap;
393   },