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/. */ 4 5"use strict"; 6 7var EXPORTED_SYMBOLS = ["RemotePageAccessManager"]; 8 9/* 10 * Used for all kinds of permissions checks which requires explicit 11 * whitelisting of specific permissions granted through Remote Pages. 12 * An RPM function will be exported into the page only if it appears 13 * in the access managers's accessMap for that page's uri. 14 * 15 * This module may be used from both the child and parent process. 16 * 17 * Please note that prefs that one wants to update need to be 18 * whitelisted within AsyncPrefs.jsm. 19 */ 20let RemotePageAccessManager = { 21 /* The accessMap lists the permissions that are allowed per page. 22 * The structure should be of the following form: 23 * <URL> : { 24 * <function name>: [<keys>], 25 * ... 26 * } 27 * For the page with given URL, permission is allowed for each 28 * listed function with a matching key. The first argument to the 29 * function must match one of the keys. If keys is an array with a 30 * single asterisk element ["*"], then all values are permitted. 31 */ 32 accessMap: { 33 "about:certerror": { 34 RPMSendAsyncMessage: [ 35 "Browser:EnableOnlineMode", 36 "Browser:ResetSSLPreferences", 37 "GetChangedCertPrefs", 38 "Browser:OpenCaptivePortalPage", 39 "Browser:SSLErrorGoBack", 40 "Browser:PrimeMitm", 41 "Browser:ResetEnterpriseRootsPref", 42 "DisplayOfflineSupportPage", 43 ], 44 RPMRecordTelemetryEvent: ["*"], 45 RPMAddMessageListener: ["*"], 46 RPMRemoveMessageListener: ["*"], 47 RPMGetFormatURLPref: ["app.support.baseURL"], 48 RPMGetBoolPref: [ 49 "security.certerrors.mitm.priming.enabled", 50 "security.certerrors.permanentOverride", 51 "security.enterprise_roots.auto-enabled", 52 "security.certerror.hideAddException", 53 ], 54 RPMSetBoolPref: ["security.tls.version.enable-deprecated"], 55 RPMGetIntPref: [ 56 "services.settings.clock_skew_seconds", 57 "services.settings.last_update_seconds", 58 ], 59 RPMGetAppBuildID: ["*"], 60 RPMGetInnerMostURI: ["*"], 61 RPMIsWindowPrivate: ["*"], 62 RPMAddToHistogram: ["*"], 63 }, 64 "about:httpsonlyerror": { 65 RPMGetFormatURLPref: ["app.support.baseURL"], 66 RPMSendAsyncMessage: ["goBack", "openInsecure"], 67 RPMAddMessageListener: ["WWWReachable"], 68 RPMTryPingSecureWWWLink: ["*"], 69 RPMOpenSecureWWWLink: ["*"], 70 }, 71 "about:certificate": { 72 RPMSendQuery: ["getCertificates"], 73 }, 74 "about:neterror": { 75 RPMSendAsyncMessage: [ 76 "Browser:EnableOnlineMode", 77 "Browser:ResetSSLPreferences", 78 "GetChangedCertPrefs", 79 "Browser:OpenCaptivePortalPage", 80 "Browser:SSLErrorGoBack", 81 "Browser:PrimeMitm", 82 "Browser:ResetEnterpriseRootsPref", 83 "ReportBlockingError", 84 "DisplayOfflineSupportPage", 85 ], 86 RPMAddMessageListener: ["*"], 87 RPMRemoveMessageListener: ["*"], 88 RPMGetFormatURLPref: ["app.support.baseURL"], 89 RPMGetBoolPref: [ 90 "security.certerror.hideAddException", 91 "security.tls.version.enable-deprecated", 92 "security.certerrors.tls.version.show-override", 93 "security.xfocsp.errorReporting.automatic", 94 "security.xfocsp.errorReporting.enabled", 95 "browser.proton.enabled", 96 ], 97 RPMSetBoolPref: [ 98 "security.tls.version.enable-deprecated", 99 "security.xfocsp.errorReporting.automatic", 100 ], 101 RPMPrefIsLocked: ["security.tls.version.min"], 102 RPMAddToHistogram: ["*"], 103 RPMGetInnerMostURI: ["*"], 104 RPMGetHttpResponseHeader: ["*"], 105 }, 106 "about:plugins": { 107 RPMSendQuery: ["RequestPlugins"], 108 }, 109 "about:pocket-saved": { 110 RPMSendAsyncMessage: ["*"], 111 RPMAddMessageListener: ["*"], 112 RPMRemoveMessageListener: ["*"], 113 }, 114 "about:pocket-signup": { 115 RPMSendAsyncMessage: ["*"], 116 RPMAddMessageListener: ["*"], 117 RPMRemoveMessageListener: ["*"], 118 }, 119 "about:pocket-home": { 120 RPMSendAsyncMessage: ["*"], 121 RPMAddMessageListener: ["*"], 122 RPMRemoveMessageListener: ["*"], 123 }, 124 "about:privatebrowsing": { 125 RPMSendAsyncMessage: [ 126 "OpenPrivateWindow", 127 "SearchBannerDismissed", 128 "OpenSearchPreferences", 129 "SearchHandoff", 130 ], 131 RPMSendQuery: [ 132 "ShouldShowSearch", 133 "ShouldShowSearchBanner", 134 "ShouldShowVPNPromo", 135 ], 136 RPMAddMessageListener: ["*"], 137 RPMRemoveMessageListener: ["*"], 138 RPMGetFormatURLPref: [ 139 "app.support.baseURL", 140 "browser.privatebrowsing.vpnpromourl", 141 ], 142 RPMIsWindowPrivate: ["*"], 143 }, 144 "about:protections": { 145 RPMSendAsyncMessage: [ 146 "OpenContentBlockingPreferences", 147 "OpenAboutLogins", 148 "OpenSyncPreferences", 149 "ClearMonitorCache", 150 "RecordEntryPoint", 151 ], 152 RPMSendQuery: [ 153 "FetchUserLoginsData", 154 "FetchMonitorData", 155 "FetchContentBlockingEvents", 156 "FetchMobileDeviceConnected", 157 "GetShowProxyCard", 158 "FetchEntryPoint", 159 "FetchVPNSubStatus", 160 "FetchShowVPNCard", 161 ], 162 RPMAddMessageListener: ["*"], 163 RPMRemoveMessageListener: ["*"], 164 RPMSetBoolPref: [ 165 "browser.contentblocking.report.show_mobile_app", 166 "browser.contentblocking.report.hide_vpn_banner", 167 ], 168 RPMGetBoolPref: [ 169 "browser.contentblocking.report.lockwise.enabled", 170 "browser.contentblocking.report.monitor.enabled", 171 "privacy.socialtracking.block_cookies.enabled", 172 "browser.contentblocking.report.proxy.enabled", 173 "privacy.trackingprotection.cryptomining.enabled", 174 "privacy.trackingprotection.fingerprinting.enabled", 175 "privacy.trackingprotection.enabled", 176 "privacy.trackingprotection.socialtracking.enabled", 177 "browser.contentblocking.report.show_mobile_app", 178 "browser.contentblocking.report.hide_vpn_banner", 179 "browser.contentblocking.report.vpn.enabled", 180 ], 181 RPMGetStringPref: [ 182 "browser.contentblocking.category", 183 "browser.contentblocking.report.monitor.url", 184 "browser.contentblocking.report.monitor.sign_in_url", 185 "browser.contentblocking.report.manage_devices.url", 186 "browser.contentblocking.report.proxy_extension.url", 187 "browser.contentblocking.report.lockwise.mobile-android.url", 188 "browser.contentblocking.report.lockwise.mobile-ios.url", 189 "browser.contentblocking.report.mobile-ios.url", 190 "browser.contentblocking.report.mobile-android.url", 191 "browser.contentblocking.report.vpn.url", 192 "browser.contentblocking.report.vpn-promo.url", 193 "browser.contentblocking.report.vpn-android.url", 194 "browser.contentblocking.report.vpn-ios.url", 195 "browser.contentblocking.report.vpn_platforms", 196 ], 197 RPMGetIntPref: ["network.cookie.cookieBehavior"], 198 RPMGetFormatURLPref: [ 199 "browser.contentblocking.report.monitor.how_it_works.url", 200 "browser.contentblocking.report.lockwise.how_it_works.url", 201 "browser.contentblocking.report.monitor.preferences_url", 202 "browser.contentblocking.report.monitor.home_page_url", 203 "browser.contentblocking.report.social.url", 204 "browser.contentblocking.report.cookie.url", 205 "browser.contentblocking.report.tracker.url", 206 "browser.contentblocking.report.fingerprinter.url", 207 "browser.contentblocking.report.cryptominer.url", 208 ], 209 RPMRecordTelemetryEvent: ["*"], 210 }, 211 "about:tabcrashed": { 212 RPMSendAsyncMessage: ["Load", "closeTab", "restoreTab", "restoreAll"], 213 RPMAddMessageListener: ["*"], 214 RPMRemoveMessageListener: ["*"], 215 }, 216 }, 217 218 /** 219 * Check if access is allowed to the given feature for a given document. 220 * This should be called from within the child process. A feature must 221 * contain the value in the whitelist array in the list within the 222 * accessMap for access to be granted. 223 * 224 * @param aDocument child process document to call from 225 * @param aFeature to feature to check access to 226 * @param aValue value that must be included with that feature's whitelist 227 * @returns true if access is allowed or false otherwise 228 */ 229 checkAllowAccess(aDocument, aFeature, aValue) { 230 let principal = aDocument.nodePrincipal; 231 // if there is no content principal; deny access 232 if (!principal) { 233 return false; 234 } 235 236 return this.checkAllowAccessWithPrincipal( 237 principal, 238 aFeature, 239 aValue, 240 aDocument 241 ); 242 }, 243 244 /** 245 * Check if access is allowed to the given feature for a given principal. 246 * This may be called from within the child or parent process. A feature 247 * must contain the value in the whitelist array in the list within the 248 * accessMap for access to be granted. 249 * 250 * In the parent process, the passed-in document is expected to be null. 251 * 252 * @param aPrincipal principal being called from 253 * @param aFeature to feature to check access to 254 * @param aValue value that must be included with that feature's whitelist 255 * @param aDocument optional child process document to call from 256 * @returns true if access is allowed or false otherwise 257 */ 258 checkAllowAccessWithPrincipal(aPrincipal, aFeature, aValue, aDocument) { 259 let accessMapForFeature = this.checkAllowAccessToFeature( 260 aPrincipal, 261 aFeature, 262 aDocument 263 ); 264 if (!accessMapForFeature) { 265 Cu.reportError( 266 "RemotePageAccessManager does not allow access to Feature: " + 267 aFeature + 268 " for: " + 269 aDocument.location 270 ); 271 272 return false; 273 } 274 275 // If the actual value is in the whitelist for that feature; 276 // allow access 277 if (accessMapForFeature.includes(aValue) || accessMapForFeature[0] == "*") { 278 return true; 279 } 280 281 return false; 282 }, 283 284 /** 285 * Check if a particular feature can be accessed without checking for a 286 * value within the whitelist. 287 * 288 * @param aPrincipal principal being called from 289 * @param aFeature to feature to check access to 290 * @param aDocument optional child process document to call from 291 * @returns non-null whitelist if access is allowed or null otherwise 292 */ 293 checkAllowAccessToFeature(aPrincipal, aFeature, aDocument) { 294 let spec; 295 if (!aPrincipal.isContentPrincipal) { 296 // For the sake of remote pages, when the principal has no uri, 297 // we want to access the "real" document URI directly, e.g. if the 298 // about: page is sandboxed. 299 if (!aDocument) { 300 return null; 301 } 302 if (!aDocument.documentURIObject.schemeIs("about")) { 303 return null; 304 } 305 spec = 306 aDocument.documentURIObject.prePath + 307 aDocument.documentURIObject.filePath; 308 } else { 309 if (!aPrincipal.schemeIs("about")) { 310 return null; 311 } 312 spec = aPrincipal.prePath + aPrincipal.filePath; 313 } 314 315 // Check if there is an entry for that requestying URI in the accessMap; 316 // if not, deny access. 317 let accessMapForURI = this.accessMap[spec]; 318 if (!accessMapForURI) { 319 return null; 320 } 321 322 // Check if the feature is allowed to be accessed for that URI; 323 // if not, deny access. 324 return accessMapForURI[aFeature]; 325 }, 326}; 327