1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LNAPermissionRequest.h"
#include "nsGlobalWindowInner.h"
#include "mozilla/dom/Document.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "mozilla/glean/NetwerkMetrics.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "nsIIOService.h"
#include "nsIOService.h"
namespace mozilla::net {
//-------------------------------------------------
// LNA Permission Requests
//-------------------------------------------------
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(LNAPermissionRequest,
ContentPermissionRequestBase)
NS_IMPL_CYCLE_COLLECTION_INHERITED(LNAPermissionRequest,
ContentPermissionRequestBase)
LNAPermissionRequest::LNAPermissionRequest(PermissionPromptCallback&& aCallback,
nsILoadInfo* aLoadInfo,
const nsACString& aType)
: dom::ContentPermissionRequestBase(
aLoadInfo->GetLoadingPrincipal(), nullptr,
(aType.Equals(LOCAL_HOST_PERMISSION_KEY) ? "network.localhost"_ns
: "network.localnetwork"_ns),
aType),
mPermissionPromptCallback(std::move(aCallback)) {
MOZ_ASSERT(aLoadInfo);
aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(mPrincipal));
RefPtr<mozilla::dom::BrowsingContext> bc;
aLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
if (bc && bc->Top()) {
if (bc->Top()->Canonical()) {
RefPtr<mozilla::dom::WindowGlobalParent> topWindowGlobal =
bc->Top()->Canonical()->GetCurrentWindowGlobal();
if (topWindowGlobal) {
mTopLevelPrincipal = topWindowGlobal->DocumentPrincipal();
}
}
}
if (!mTopLevelPrincipal) {
// this could happen in tests
mTopLevelPrincipal = mPrincipal;
}
if (!mPrincipal->Equals(mTopLevelPrincipal)) {
// This is a cross origin request from Iframe
// Since permission delegation is not implemented yet in the parent process
// we need to set this flag to true explicitly and display the origin of the
// iframe in the prompt. See Bug 1978550
mIsRequestDelegatedToUnsafeThirdParty = true;
// permissions for this iframe is limited to the iframe's principal
mTopLevelPrincipal = mPrincipal;
}
mLoadInfo = aLoadInfo;
MOZ_ASSERT(mPrincipal);
}
NS_IMETHODIMP
LNAPermissionRequest::GetElement(mozilla::dom::Element** aElement) {
NS_ENSURE_ARG_POINTER(aElement);
RefPtr<mozilla::dom::BrowsingContext> bc;
mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
if (!bc) {
return NS_ERROR_FAILURE;
}
return bc->GetTopFrameElement(aElement);
}
// callback when the permission request is denied
NS_IMETHODIMP
LNAPermissionRequest::Cancel() {
// callback to the http channel on the prompt failure result
mPermissionPromptCallback(false, mType, mPromptWasShown);
return NS_OK;
}
// callback when the permission request is allowed
NS_IMETHODIMP
LNAPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
// callback to the http channel on the prompt success result
mPermissionPromptCallback(true, mType, mPromptWasShown);
return NS_OK;
}
// callback when the permission prompt is shown
NS_IMETHODIMP
LNAPermissionRequest::NotifyShown() {
// Mark that the prompt was shown to the user
mPromptWasShown = true;
// Record telemetry for permission prompts shown to users
if (mType.Equals(LOCAL_HOST_PERMISSION_KEY)) {
if (mIsRequestDelegatedToUnsafeThirdParty) {
mozilla::glean::networking::local_network_access_prompts_shown
.Get("localhost_cross_site"_ns)
.Add(1);
} else {
mozilla::glean::networking::local_network_access_prompts_shown
.Get("localhost"_ns)
.Add(1);
}
} else if (mType.Equals(LOCAL_NETWORK_PERMISSION_KEY)) {
if (mIsRequestDelegatedToUnsafeThirdParty) {
mozilla::glean::networking::local_network_access_prompts_shown
.Get("local_network_cross_site"_ns)
.Add(1);
} else {
mozilla::glean::networking::local_network_access_prompts_shown
.Get("local_network"_ns)
.Add(1);
}
}
return NS_OK;
}
nsresult LNAPermissionRequest::RequestPermission() {
MOZ_ASSERT(NS_IsMainThread());
// This check always returns true
// See Bug 1978550
if (!CheckPermissionDelegate()) {
return Cancel();
}
// Check if the domain should skip LNA checks
if (mPrincipal && gIOService) {
nsAutoCString origin;
nsresult rv = mPrincipal->GetAsciiHost(origin);
if (NS_SUCCEEDED(rv) && !origin.IsEmpty()) {
if (gIOService->ShouldSkipDomainForLNA(origin)) {
// Domain is in the skip list, grant permission automatically
return Allow(JS::UndefinedHandleValue);
}
}
}
PromptResult pr = CheckPromptPrefs();
if (pr == PromptResult::Granted) {
return Allow(JS::UndefinedHandleValue);
}
if (pr == PromptResult::Denied) {
return Cancel();
}
if (NS_SUCCEEDED(
dom::nsContentPermissionUtils::AskPermission(this, mWindow))) {
// Here we could be getting synchronous callback from the prompts depending
// on whether there is already a permission for this or not. If we have a
// permission, we will get a synchronous callback Allow/Deny and async if
// we don't have a permission yet and waiting for user permission.
return NS_OK;
}
return Cancel();
}
} // namespace mozilla::net
|