Bug 1933479 - Add tab close button on hover to vertical tabs when sidebar is collapse...
[gecko.git] / toolkit / modules / RemotePageAccessManager.sys.mjs
blobabf72c92dff02219978b874380f4e1bbdbf8280c
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       RPMRecordGleanEvent: ["*"],
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         "security.certerrors.felt-privacy-v1",
53       ],
54       RPMGetIntPref: [
55         "security.dialog_enable_delay",
56         "services.settings.clock_skew_seconds",
57         "services.settings.last_update_seconds",
58       ],
59       RPMGetAppBuildID: ["*"],
60       RPMGetInnerMostURI: ["*"],
61       RPMIsWindowPrivate: ["*"],
62       RPMAddToHistogram: ["*"],
63     },
64     "about:home": {
65       RPMSendAsyncMessage: ["ActivityStream:ContentToMain"],
66       RPMAddMessageListener: ["ActivityStream:MainToContent"],
67     },
68     "about:httpsonlyerror": {
69       RPMGetFormatURLPref: ["app.support.baseURL"],
70       RPMGetIntPref: ["security.dialog_enable_delay"],
71       RPMSendAsyncMessage: ["goBack", "openInsecure"],
72       RPMAddMessageListener: ["WWWReachable"],
73       RPMTryPingSecureWWWLink: ["*"],
74       RPMOpenSecureWWWLink: ["*"],
75     },
76     "about:certificate": {
77       RPMSendQuery: ["getCertificates"],
78     },
79     "about:neterror": {
80       RPMSendAsyncMessage: [
81         "Browser:EnableOnlineMode",
82         "Browser:ResetSSLPreferences",
83         "GetChangedCertPrefs",
84         "Browser:OpenCaptivePortalPage",
85         "Browser:SSLErrorGoBack",
86         "Browser:PrimeMitm",
87         "Browser:ResetEnterpriseRootsPref",
88         "ReportBlockingError",
89         "DisplayOfflineSupportPage",
90         "OpenTRRPreferences",
91       ],
92       RPMCheckAlternateHostAvailable: ["*"],
93       RPMRecordGleanEvent: ["securityDohNeterror", "securityUiTlserror"],
94       RPMAddMessageListener: ["*"],
95       RPMRemoveMessageListener: ["*"],
96       RPMGetFormatURLPref: [
97         "app.support.baseURL",
98         "network.trr_ui.skip_reason_learn_more_url",
99       ],
100       RPMGetBoolPref: [
101         "security.certerror.hideAddException",
102         "security.xfocsp.errorReporting.automatic",
103         "security.xfocsp.errorReporting.enabled",
104         "security.xfocsp.hideOpenInNewWindow",
105         "network.trr.display_fallback_warning",
106         "security.certerrors.felt-privacy-v1",
107       ],
108       RPMSetPref: [
109         "security.xfocsp.errorReporting.automatic",
110         "network.trr.display_fallback_warning",
111       ],
112       RPMAddToHistogram: ["*"],
113       RPMGetInnerMostURI: ["*"],
114       RPMGetHttpResponseHeader: ["*"],
115       RPMIsTRROnlyFailure: ["*"],
116       RPMIsFirefox: ["*"],
117       RPMIsNativeFallbackFailure: ["*"],
118       RPMGetTRRSkipReason: ["*"],
119       RPMGetTRRDomain: ["*"],
120       RPMIsSiteSpecificTRRError: ["*"],
121       RPMSetTRRDisabledLoadFlags: ["*"],
122       RPMShowOSXLocalNetworkPermissionWarning: ["*"],
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:deleteprofile": {
176       RPMSendQuery: ["Profiles:GetDeleteProfileContent"],
177       RPMSendAsyncMessage: ["Profiles:CancelDelete", "Profiles:DeleteProfile"],
178     },
179     "about:editprofile": {
180       RPMSendQuery: [
181         "Profiles:GetEditProfileContent",
182         "Profiles:UpdateProfileTheme",
183       ],
184       RPMSendAsyncMessage: [
185         "Profiles:UpdateProfileName",
186         "Profiles:UpdateProfileAvatar",
187         "Profiles:OpenDeletePage",
188         "Profiles:CloseProfileTab",
189       ],
190     },
191     "about:newprofile": {
192       RPMSendQuery: [
193         "Profiles:GetNewProfileContent",
194         "Profiles:UpdateProfileTheme",
195       ],
196       RPMSendAsyncMessage: [
197         "Profiles:UpdateProfileName",
198         "Profiles:UpdateProfileAvatar",
199         "Profiles:DeleteProfile",
200         "Profiles:CloseProfileTab",
201       ],
202       RPMGetBoolPref: ["browser.profiles.profile-name.updated"],
203       RPMGetFormatURLPref: ["app.support.baseURL"],
204     },
205     "about:protections": {
206       RPMSendAsyncMessage: [
207         "OpenContentBlockingPreferences",
208         "OpenAboutLogins",
209         "OpenSyncPreferences",
210         "ClearMonitorCache",
211         "RecordEntryPoint",
212       ],
213       RPMSendQuery: [
214         "FetchUserLoginsData",
215         "FetchMonitorData",
216         "FetchContentBlockingEvents",
217         "FetchMobileDeviceConnected",
218         "GetShowProxyCard",
219         "FetchEntryPoint",
220         "FetchVPNSubStatus",
221         "FetchShowVPNCard",
222       ],
223       RPMAddMessageListener: ["*"],
224       RPMRemoveMessageListener: ["*"],
225       RPMSetPref: [
226         "browser.contentblocking.report.show_mobile_app",
227         "browser.contentblocking.report.hide_vpn_banner",
228       ],
229       RPMGetBoolPref: [
230         "browser.contentblocking.report.lockwise.enabled",
231         "browser.contentblocking.report.monitor.enabled",
232         "privacy.fingerprintingProtection",
233         "privacy.socialtracking.block_cookies.enabled",
234         "browser.contentblocking.report.proxy.enabled",
235         "privacy.trackingprotection.cryptomining.enabled",
236         "privacy.trackingprotection.fingerprinting.enabled",
237         "privacy.trackingprotection.enabled",
238         "privacy.trackingprotection.socialtracking.enabled",
239         "browser.contentblocking.report.show_mobile_app",
240         "browser.contentblocking.report.hide_vpn_banner",
241         "browser.vpn_promo.enabled",
242       ],
243       RPMGetStringPref: [
244         "browser.contentblocking.category",
245         "browser.contentblocking.report.monitor.url",
246         "browser.contentblocking.report.monitor.sign_in_url",
247         "browser.contentblocking.report.manage_devices.url",
248         "browser.contentblocking.report.proxy_extension.url",
249         "browser.contentblocking.report.lockwise.mobile-android.url",
250         "browser.contentblocking.report.lockwise.mobile-ios.url",
251         "browser.contentblocking.report.mobile-ios.url",
252         "browser.contentblocking.report.mobile-android.url",
253         "browser.contentblocking.report.vpn.url",
254         "browser.contentblocking.report.vpn-promo.url",
255         "browser.contentblocking.report.vpn-android.url",
256         "browser.contentblocking.report.vpn-ios.url",
257       ],
258       RPMGetIntPref: ["network.cookie.cookieBehavior"],
259       RPMGetFormatURLPref: [
260         "browser.contentblocking.report.monitor.how_it_works.url",
261         "browser.contentblocking.report.lockwise.how_it_works.url",
262         "browser.contentblocking.report.monitor.preferences_url",
263         "browser.contentblocking.report.monitor.home_page_url",
264         "browser.contentblocking.report.social.url",
265         "browser.contentblocking.report.cookie.url",
266         "browser.contentblocking.report.tracker.url",
267         "browser.contentblocking.report.fingerprinter.url",
268         "browser.contentblocking.report.cryptominer.url",
269       ],
270       RPMRecordGleanEvent: ["securityUiProtections"],
271     },
272     "about:shoppingsidebar": {
273       RPMSetPref: [
274         "browser.shopping.experience2023.optedIn",
275         "browser.shopping.experience2023.active",
276         "browser.shopping.experience2023.ads.userEnabled",
277         "browser.shopping.experience2023.sidebarClosedCount",
278         "browser.shopping.experience2023.showKeepSidebarClosedMessage",
279         "browser.shopping.experience2023.autoOpen.userEnabled",
280       ],
281       RPMGetFormatURLPref: ["app.support.baseURL"],
282       RPMGetIntPref: ["browser.shopping.experience2023.sidebarClosedCount"],
283       RPMGetBoolPref: [
284         "browser.shopping.experience2023.showKeepSidebarClosedMessage",
285         "sidebar.revamp",
286         "browser.shopping.experience2023.integratedSidebar",
287       ],
288     },
289     "about:tabcrashed": {
290       RPMSendAsyncMessage: ["Load", "closeTab", "restoreTab", "restoreAll"],
291       RPMAddMessageListener: ["*"],
292       RPMRemoveMessageListener: ["*"],
293     },
294     "about:welcome": {
295       RPMSendAsyncMessage: ["ActivityStream:ContentToMain"],
296       RPMAddMessageListener: ["ActivityStream:MainToContent"],
297     },
298   },
300   /**
301    * Check if access is allowed to the given feature for a given document.
302    * This should be called from within the child process.
303    *
304    * The feature within the accessMap must list the given aValue, for access to
305    * be granted.
306    *
307    * @param aDocument child process document to call from
308    * @param aFeature to feature to check access to
309    * @param aValue value that must be included with that feature's allow list
310    * @returns true if access is allowed or false otherwise
311    */
312   checkAllowAccess(aDocument, aFeature, aValue) {
313     let principal = aDocument.nodePrincipal;
314     // if there is no content principal; deny access
315     if (!principal) {
316       return false;
317     }
319     return this.checkAllowAccessWithPrincipal(
320       principal,
321       aFeature,
322       aValue,
323       aDocument
324     );
325   },
327   /**
328    * Check if access is allowed to the given feature for a given principal.
329    * This may be called from within the child or parent process.
330    *
331    * The feature within the accessMap must list the given aValue, for access to
332    * be granted.
333    *
334    * In the parent process, the passed-in document is expected to be null.
335    *
336    * @param aPrincipal principal being called from
337    * @param aFeature to feature to check access to
338    * @param aValue value that must be included with that feature's allow list
339    * @param aDocument optional child process document to call from
340    * @returns true if access is allowed or false otherwise
341    */
342   checkAllowAccessWithPrincipal(aPrincipal, aFeature, aValue, aDocument) {
343     let accessMapForFeature = this.checkAllowAccessToFeature(
344       aPrincipal,
345       aFeature,
346       aDocument
347     );
348     if (!accessMapForFeature) {
349       console.error(
350         "RemotePageAccessManager does not allow access to Feature: ",
351         aFeature,
352         " for: ",
353         aDocument.location
354       );
356       return false;
357     }
359     // If the actual value is in the allow list for that feature;
360     // allow access
361     if (accessMapForFeature.includes(aValue) || accessMapForFeature[0] == "*") {
362       return true;
363     }
365     return false;
366   },
368   /**
369    * Check if a particular feature can be accessed without checking for a
370    * specific feature value.
371    *
372    * @param aPrincipal principal being called from
373    * @param aFeature to feature to check access to
374    * @param aDocument optional child process document to call from
375    * @returns non-null allow list if access is allowed or null otherwise
376    */
377   checkAllowAccessToFeature(aPrincipal, aFeature, aDocument) {
378     let spec;
379     if (!aPrincipal.isContentPrincipal) {
380       // For the sake of remote pages, when the principal has no uri,
381       // we want to access the "real" document URI directly, e.g. if the
382       // about: page is sandboxed.
383       if (!aDocument) {
384         return null;
385       }
386       if (!aDocument.documentURIObject.schemeIs("about")) {
387         return null;
388       }
389       spec =
390         aDocument.documentURIObject.prePath +
391         aDocument.documentURIObject.filePath;
392     } else {
393       if (!aPrincipal.schemeIs("about")) {
394         return null;
395       }
396       spec = aPrincipal.prePath + aPrincipal.filePath;
397     }
399     // Check if there is an entry for that requestying URI in the accessMap;
400     // if not, deny access.
401     let accessMapForURI = this.accessMap[spec];
402     if (!accessMapForURI) {
403       return null;
404     }
406     // Check if the feature is allowed to be accessed for that URI;
407     // if not, deny access.
408     return accessMapForURI[aFeature];
409   },
411   /**
412    * This function adds a new page to the access map, but can only
413    * be used in a test environment.
414    */
415   addPage(aUrl, aFunctionMap) {
416     if (!Cu.isInAutomation) {
417       throw new Error("Cannot only modify privileges during testing");
418     }
420     if (aUrl in this.accessMap) {
421       throw new Error("Cannot modify privileges of existing page");
422     }
424     this.accessMap[aUrl] = aFunctionMap;
425   },