Bug 1900225: Part 2 - Inform user of system UX issues initiated by geolocation request r=gstoll,emilio,bolsson,pbz

This patch installs the framework for various platforms to inform the user of
one of two things: 1) a coming system dialog asking for system geolocation
permission that will be presented after the Firefox doorhanger asking for
permission for the page, and 2) that we will open a system preferences window,
where the user can enable geolocation for Firefox because it is currently not
enabled.  The code that handles this has been remoted to the parent process
since implementations will not be able to operate in the content process
sandbox.

Here, it stubs the behavior so this does nothing on every platform.
In this patch series, the behavior will be implemented for Windows.

Note: The code will run the geolocation for the page if the user granted it in
Firefox, regardless of whether the user granted or canceled the system
permission.  This respects the user's instruction and provides a work-around in
the event of a bug, although it would usually either fail to get a location or
it will get a very poor one (e.g. via IP lookup).

Differential Revision: https://phabricator.services.mozilla.com/D216473
This commit is contained in:
David P 2024-08-27 22:47:32 +00:00
Родитель 4c1f57b267
Коммит fcb97ac813
12 изменённых файлов: 476 добавлений и 14 удалений

Просмотреть файл

@ -198,11 +198,18 @@ geolocation.allow=Allow
geolocation.allow.accesskey=A
geolocation.block=Block
geolocation.block.accesskey=B
# %S is replaced by the product name (e.g. Firefox)
geolocation.needsSystemSetting=This will open system location settings. Please grant location permission to %S.
geolocation.shareWithSite4=Allow %S to access your location?
geolocation.shareWithFile4=Allow this local file to access your location?
# LOCALIZATION NOTE(geolocation.shareWithSiteUnsafeDelegation2):
# %1$S is the first party origin, %2$S is the third party origin.
geolocation.shareWithSiteUnsafeDelegation2=Allow %1$S to give %2$S permission to access your location?
# %S is replaced by the product name (e.g. Firefox)
geolocation.systemSettingsMessage=Grant %S location permission in system settings.
geolocation.systemSettingsTitle=Awaiting Location Permission
# %S is replaced by the product name (e.g. Firefox)
geolocation.systemWillRequestPermission=The system will ask you to grant this permission to %S.
geolocation.remember=Remember this decision
# Virtual Reality Device UI

Просмотреть файл

@ -86,6 +86,13 @@ XPCOMUtils.defineLazyServiceGetter(
"@mozilla.org/content-pref/service;1",
"nsIContentPrefService2"
);
ChromeUtils.defineLazyGetter(lazy, "gBrandBundle", function () {
return Services.strings.createBundle(
"chrome://branding/locale/brand.properties"
);
});
ChromeUtils.defineLazyGetter(lazy, "gBrowserBundle", function () {
return Services.strings.createBundle(
"chrome://browser/locale/browser.properties"
@ -251,6 +258,17 @@ class PermissionPrompt {
throw new Error("Not implemented.");
}
/**
* The hint text to show to the user in the PopupNotification, see
* `PopupNotifications_show` in PopupNotifications.sys.mjs.
* By default, no hint is shown.
*
* @return {string}
*/
get hintText() {
return undefined;
}
/**
* Provides the preferred name to use in the permission popups,
* based on the principal URI (the URI.hostPort for any URI scheme
@ -607,6 +625,7 @@ class PermissionPrompt {
return false;
};
options.hintText = this.hintText;
// Post-prompts show up as dismissed.
options.dismissed = postPrompt;
@ -731,6 +750,14 @@ class GeolocationPermissionPrompt extends PermissionPromptForRequest {
constructor(request) {
super();
this.request = request;
let types = request.types.QueryInterface(Ci.nsIArray);
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
if (perm.options.length) {
this.systemPermissionMsg = perm.options.queryElementAt(
0,
Ci.nsISupportsString
);
}
}
get type() {
@ -799,6 +826,26 @@ class GeolocationPermissionPrompt extends PermissionPromptForRequest {
);
}
get hintText() {
let productName = lazy.gBrandBundle.GetStringFromName("brandShortName");
if (this.systemPermissionMsg == "sysdlg") {
return lazy.gBrowserBundle.formatStringFromName(
"geolocation.systemWillRequestPermission",
[productName]
);
}
if (this.systemPermissionMsg == "syssetting") {
return lazy.gBrowserBundle.formatStringFromName(
"geolocation.needsSystemSetting",
[productName]
);
}
return undefined;
}
get promptActions() {
return [
{

Просмотреть файл

@ -6,16 +6,21 @@
#include "Geolocation.h"
#include "GeolocationIPCUtils.h"
#include "GeolocationSystem.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/CycleCollectedJSContext.h" // for nsAutoMicroTask
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/GeolocationPositionError.h"
#include "mozilla/dom/GeolocationPositionErrorBinding.h"
#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_geo.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
@ -28,6 +33,7 @@
#include "mozilla/dom/Document.h"
#include "nsINamed.h"
#include "nsIObserverService.h"
#include "nsIPromptService.h"
#include "nsIScriptError.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
@ -65,6 +71,7 @@ class nsIPrincipal;
using mozilla::Unused; // <snicker>
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::geolocation;
mozilla::LazyLogModule gGeolocationLog("Geolocation");
@ -88,6 +95,7 @@ class nsGeolocationRequest final : public ContentPermissionRequestBase,
// nsIContentPermissionRequest
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Cancel(void) override;
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Allow(JS::Handle<JS::Value> choices) override;
NS_IMETHOD GetTypes(nsIArray** aTypes) override;
void Shutdown();
@ -109,6 +117,11 @@ class nsGeolocationRequest final : public ContentPermissionRequestBase,
bool IsWatch() { return mIsWatchPositionRequest; }
int32_t WatchId() { return mWatchId; }
void SetPromptBehavior(
geolocation::SystemGeolocationPermissionBehavior aBehavior) {
mBehavior = aBehavior;
}
private:
virtual ~nsGeolocationRequest();
@ -146,6 +159,8 @@ class nsGeolocationRequest final : public ContentPermissionRequestBase,
bool mShutdown;
bool mSeenAnySignal = false;
nsCOMPtr<nsIEventTarget> mMainThreadSerialEventTarget;
SystemGeolocationPermissionBehavior mBehavior;
};
static UniquePtr<PositionOptions> CreatePositionOptionsCopy(
@ -209,7 +224,8 @@ nsGeolocationRequest::nsGeolocationRequest(
mLocator(aLocator),
mWatchId(aWatchId),
mShutdown(false),
mMainThreadSerialEventTarget(aMainThreadSerialEventTarget) {}
mMainThreadSerialEventTarget(aMainThreadSerialEventTarget),
mBehavior(SystemGeolocationPermissionBehavior::NoPrompt) {}
nsGeolocationRequest::~nsGeolocationRequest() { StopTimeoutTimer(); }
@ -252,6 +268,113 @@ nsGeolocationRequest::Cancel() {
return NS_OK;
}
/**
* When the promise for the cancel dialog is resolved or rejected, we should
* stop waiting for permission. If it was granted then the
* SystemGeolocationPermissionRequest should already be resolved, so we do
* nothing. Otherwise, we were either cancelled or got an error, so we cancel
* the SystemGeolocationPermissionRequest.
*/
class CancelSystemGeolocationPermissionRequest : public PromiseNativeHandler {
public:
NS_DECL_ISUPPORTS
explicit CancelSystemGeolocationPermissionRequest(
SystemGeolocationPermissionRequest* aRequest)
: mRequest(aRequest) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override {
mRequest->Stop();
}
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override {
mRequest->Stop();
}
private:
~CancelSystemGeolocationPermissionRequest() = default;
RefPtr<SystemGeolocationPermissionRequest> mRequest;
};
NS_IMPL_ISUPPORTS0(CancelSystemGeolocationPermissionRequest)
/* static */
void Geolocation::ReallowWithSystemPermissionOrCancel(
BrowsingContext* aBrowsingContext,
geolocation::ParentRequestResolver&& aResolver) {
// Make sure we don't return without responding to the geolocation request.
auto denyPermissionOnError =
MakeScopeExit([&aResolver]() MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
aResolver(GeolocationPermissionStatus::Error);
});
NS_ENSURE_TRUE_VOID(aBrowsingContext);
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundleService> sbs =
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
NS_ENSURE_TRUE_VOID(sbs);
sbs->CreateBundle("chrome://browser/locale/browser.properties",
getter_AddRefs(bundle));
NS_ENSURE_TRUE_VOID(bundle);
nsAutoString title;
nsresult rv =
bundle->GetStringFromName("geolocation.systemSettingsTitle", title);
NS_ENSURE_SUCCESS_VOID(rv);
nsAutoString brandName;
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES,
"brandShortName", brandName);
NS_ENSURE_SUCCESS_VOID(rv);
AutoTArray<nsString, 1> formatParams;
formatParams.AppendElement(brandName);
nsAutoString message;
rv = bundle->FormatStringFromName("geolocation.systemSettingsMessage",
formatParams, message);
NS_ENSURE_SUCCESS_VOID(rv);
// We MUST do this because aResolver is moved below.
denyPermissionOnError.release();
RefPtr<SystemGeolocationPermissionRequest> permissionRequest =
geolocation::PresentSystemSettings(aBrowsingContext,
std::move(aResolver));
NS_ENSURE_TRUE_VOID(permissionRequest);
auto cancelRequestOnError = MakeScopeExit([&]() {
// Stop waiting for the system permission and just leave it up to the user.
permissionRequest->Stop();
});
nsCOMPtr<nsIPromptService> promptSvc =
do_GetService("@mozilla.org/prompter;1", &rv);
NS_ENSURE_SUCCESS_VOID(rv);
RefPtr<mozilla::dom::Promise> cancelDialogPromise;
rv = promptSvc->AsyncConfirmEx(
aBrowsingContext, nsIPromptService::MODAL_TYPE_TAB, title.get(),
message.get(),
nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0,
nullptr, nullptr, nullptr, nullptr, false, JS::UndefinedHandleValue,
getter_AddRefs(cancelDialogPromise));
NS_ENSURE_SUCCESS_VOID(rv);
MOZ_ASSERT(cancelDialogPromise);
// If the cancel dialog promise is resolved or rejected then the dialog is no
// longer visible so we should stop waiting for permission, whether it was
// granted or not.
cancelDialogPromise->AppendNativeHandler(
new CancelSystemGeolocationPermissionRequest(permissionRequest));
cancelRequestOnError.release();
}
NS_IMETHODIMP
nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) {
MOZ_ASSERT(aChoices.isUndefined());
@ -260,6 +383,37 @@ nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) {
return NS_OK;
}
if (mBehavior == SystemGeolocationPermissionBehavior::GeckoWillPromptUser) {
// Asynchronously present the system dialog and wait for the permission to
// change or the request to be canceled. If the permission is (maybe)
// granted then it will call Allow again. It actually will also re-call
// Allow if the permission is denied, in order to get the "denied
// permission" behavior.
mBehavior = SystemGeolocationPermissionBehavior::NoPrompt;
RefPtr<BrowsingContext> browsingContext = mWindow->GetBrowsingContext();
if (ContentChild* cc = ContentChild::GetSingleton()) {
cc->SendRequestGeolocationPermissionFromUser(
browsingContext,
[self = RefPtr{this}](GeolocationPermissionStatus aResult)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
self->Allow(JS::UndefinedHandleValue);
},
[self = RefPtr{this}](mozilla::ipc::ResponseRejectReason aReason)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
self->Allow(JS::UndefinedHandleValue);
});
return NS_OK;
}
Geolocation::ReallowWithSystemPermissionOrCancel(
browsingContext,
[self = RefPtr{this}](GeolocationPermissionStatus aResult)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA {
self->Allow(JS::UndefinedHandleValue);
});
return NS_OK;
}
RefPtr<nsGeolocationService> gs =
nsGeolocationService::GetGeolocationService();
@ -289,7 +443,7 @@ nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) {
// will now be owned by the RequestSendLocationEvent
Update(lastPosition.position);
// After Update is called, getCurrentPosition finishes it's job.
// After Update is called, getCurrentPosition finishes its job.
if (!mIsWatchPositionRequest) {
return NS_OK;
}
@ -479,6 +633,24 @@ void nsGeolocationRequest::Shutdown() {
}
}
NS_IMETHODIMP
nsGeolocationRequest::GetTypes(nsIArray** aTypes) {
AutoTArray<nsString, 2> options;
switch (mBehavior) {
case SystemGeolocationPermissionBehavior::SystemWillPromptUser:
options.AppendElement(u"sysdlg"_ns);
break;
case SystemGeolocationPermissionBehavior::GeckoWillPromptUser:
options.AppendElement(u"syssetting"_ns);
break;
default:
break;
}
return nsContentPermissionUtils::CreatePermissionArray(mType, options,
aTypes);
}
////////////////////////////////////////////////////
// nsGeolocationRequest::TimerCallbackHolder
////////////////////////////////////////////////////
@ -1093,10 +1265,7 @@ nsresult Geolocation::GetCurrentPosition(GeoPositionCallback callback,
}
if (mOwner) {
if (!RegisterRequestWithPrompt(request)) {
return NS_ERROR_NOT_AVAILABLE;
}
RequestIfPermitted(request);
return NS_OK;
}
@ -1170,11 +1339,7 @@ int32_t Geolocation::WatchPosition(GeoPositionCallback aCallback,
}
if (mOwner) {
if (!RegisterRequestWithPrompt(request)) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return 0;
}
RequestIfPermitted(request);
return watchId;
}
@ -1245,7 +1410,8 @@ void Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest) {
}
}
bool Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request) {
/* static */ bool Geolocation::RegisterRequestWithPrompt(
nsGeolocationRequest* request) {
nsIEventTarget* target = GetMainThreadSerialEventTarget();
ContentPermissionRequestBase::PromptResult pr = request->CheckPromptPrefs();
if (pr == ContentPermissionRequestBase::PromptResult::Granted) {
@ -1264,6 +1430,48 @@ bool Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request) {
return true;
}
/* static */ geolocation::SystemGeolocationPermissionBehavior
Geolocation::GetLocationOSPermission() {
return geolocation::GetGeolocationPermissionBehavior();
}
void Geolocation::RequestIfPermitted(nsGeolocationRequest* request) {
auto getPermission = [request = RefPtr{request}](auto aPermission) {
switch (aPermission) {
case geolocation::SystemGeolocationPermissionBehavior::
SystemWillPromptUser:
case geolocation::SystemGeolocationPermissionBehavior::
GeckoWillPromptUser:
request->SetPromptBehavior(aPermission);
break;
case geolocation::SystemGeolocationPermissionBehavior::NoPrompt:
// Either location access is already permitted by OS or the system
// permission UX is not available for this platform. Do nothing.
break;
default:
MOZ_ASSERT_UNREACHABLE(
"unexpected GeolocationPermissionBehavior value");
break;
}
RegisterRequestWithPrompt(request);
};
if (auto* contentChild = ContentChild::GetSingleton()) {
contentChild->SendGetSystemGeolocationPermissionBehavior(
std::move(getPermission),
[request =
RefPtr{request}](mozilla::ipc::ResponseRejectReason aReason) {
NS_WARNING("Error sending GetSystemGeolocationPermissionBehavior");
// We still need to run the location request, even if we don't
// have permission.
RegisterRequestWithPrompt(request);
});
} else {
MOZ_ASSERT(XRE_IsParentProcess());
getPermission(GetLocationOSPermission());
}
}
JSObject* Geolocation::WrapObject(JSContext* aCtx,
JS::Handle<JSObject*> aGivenProto) {
return Geolocation_Binding::Wrap(aCtx, this, aGivenProto);

Просмотреть файл

@ -10,7 +10,6 @@
// Microsoft's API Name hackery sucks
#undef CreateEvent
#include "mozilla/StaticPtr.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsITimer.h"
@ -28,6 +27,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/CallbackObject.h"
#include "GeolocationSystem.h"
#include "nsIGeolocationProvider.h"
#include "mozilla/Attributes.h"
@ -41,6 +41,9 @@ using GeoPositionCallback =
CallbackObjectHolder<PositionCallback, nsIDOMGeoPositionCallback>;
using GeoPositionErrorCallback =
CallbackObjectHolder<PositionErrorCallback, nsIDOMGeoPositionErrorCallback>;
namespace geolocation {
enum class LocationOSPermission;
}
} // namespace mozilla::dom
struct CachedPositionAndAccuracy {
@ -179,6 +182,13 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
// null.
static already_AddRefed<Geolocation> NonWindowSingleton();
static geolocation::SystemGeolocationPermissionBehavior
GetLocationOSPermission();
static MOZ_CAN_RUN_SCRIPT void ReallowWithSystemPermissionOrCancel(
BrowsingContext* aBrowsingContext,
geolocation::ParentRequestResolver&& aResolver);
private:
~Geolocation();
@ -194,7 +204,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
UniquePtr<PositionOptions>&& aOptions,
CallerType aCallerType, ErrorResult& aRv);
bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
static bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
// Check if clearWatch is already called
bool IsAlreadyCleared(nsGeolocationRequest* aRequest);
@ -207,6 +217,9 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
// request is coming from a chrome window.
bool IsFullyActiveOrChrome();
// Initates the asynchronous process of filling the request.
static void RequestIfPermitted(nsGeolocationRequest* request);
// Two callback arrays. The first |mPendingCallbacks| holds objects for only
// one callback and then they are released/removed from the array. The second
// |mWatchingCallbacks| holds objects until the object is explicitly removed

Просмотреть файл

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_GeolocationIPCUtils_h
#define mozilla_dom_GeolocationIPCUtils_h
#include "ipc/EnumSerializer.h"
namespace mozilla::dom::geolocation {
enum class SystemGeolocationPermissionBehavior {
// OS geolocation permission may be granted or not, but Gecko should not ask
// the user for it. Gecko may not even know if it already has geolocation
// permission. This value is used when Gecko is done asking the user for
// permission, when Gecko doesn't have to ask the user because permission is
// already granted, and when Gecko is running on a platform where it cannot
// perform the system UX operations required to get permission (such as
// opening system preferences).
NoPrompt,
// Gecko does not have OS geolocation permission. The OS will ask the user
// for location permission before responding to requests.
SystemWillPromptUser,
// Gecko does not have OS geolocation permission. Gecko will open OS
// preferences and ask the user to either grant location permission or to
// cancel the request. It will wait for an answer before responding to the
// geolocation request.
GeckoWillPromptUser,
Last = GeckoWillPromptUser,
};
enum class GeolocationPermissionStatus {
Canceled,
Granted,
Error,
Last = Error
};
} // namespace mozilla::dom::geolocation
namespace IPC {
template <>
struct ParamTraits<
mozilla::dom::geolocation::SystemGeolocationPermissionBehavior>
: public ContiguousEnumSerializerInclusive<
mozilla::dom::geolocation::SystemGeolocationPermissionBehavior,
mozilla::dom::geolocation::SystemGeolocationPermissionBehavior::
NoPrompt,
mozilla::dom::geolocation::SystemGeolocationPermissionBehavior::
Last> {};
template <>
struct ParamTraits<mozilla::dom::geolocation::GeolocationPermissionStatus>
: public ContiguousEnumSerializerInclusive<
mozilla::dom::geolocation::GeolocationPermissionStatus,
mozilla::dom::geolocation::GeolocationPermissionStatus::Canceled,
mozilla::dom::geolocation::GeolocationPermissionStatus::Last> {};
} // namespace IPC
#endif /* mozilla_dom_GeolocationIPCUtils_h */

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "GeolocationSystem.h"
namespace mozilla::dom::geolocation {
SystemGeolocationPermissionBehavior GetGeolocationPermissionBehavior() {
return SystemGeolocationPermissionBehavior::NoPrompt;
}
already_AddRefed<SystemGeolocationPermissionRequest> PresentSystemSettings(
BrowsingContext* aBrowsingContext, ParentRequestResolver&& aResolver) {
MOZ_ASSERT_UNREACHABLE(
"Should not warn user of need for system location permission "
"since we cannot open system settings on this platform.");
return nullptr;
}
} // namespace mozilla::dom::geolocation

Просмотреть файл

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_GeolocationSystem_h
#define mozilla_dom_GeolocationSystem_h
#include "mozilla/dom/PContentParent.h"
#include "GeolocationIPCUtils.h"
namespace mozilla::dom {
class BrowsingContext;
namespace geolocation {
/**
* Get the behavior that Gecko should perform when the user asks for
* geolocation. The result isn't guaranteed to be accurate on all platforms
* (for example, some may prompt the user for permission without Gecko's
* knowledge). It is, however, guaranteed to be sensible. For example, this
* will never return "SystemWillPromptUser" if that is not true, nor will it
* return "GeckoWillPromptUser" if Gecko doesn't know how to open OS settings.
*/
SystemGeolocationPermissionBehavior GetGeolocationPermissionBehavior();
class SystemGeolocationPermissionRequest {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
// Stop watching for permission
virtual void Stop() = 0;
protected:
virtual ~SystemGeolocationPermissionRequest() = default;
};
using ParentRequestResolver =
PContentParent::RequestGeolocationPermissionFromUserResolver;
/**
* Opens the relevant (system or Gecko) window to request permission from the
* user. Resolves aResolver when permission is granted, an error occurs, or Stop
* has been called on the SystemGeolocationPermissionRequest.
*/
already_AddRefed<SystemGeolocationPermissionRequest> PresentSystemSettings(
BrowsingContext* aBrowsingContext, ParentRequestResolver&& aResolver);
} // namespace geolocation
} // namespace mozilla::dom
#endif /* mozilla_dom_GeolocationSystem_h */

Просмотреть файл

@ -14,8 +14,10 @@ EXPORTS += [
EXPORTS.mozilla.dom += [
"Geolocation.h",
"GeolocationCoordinates.h",
"GeolocationIPCUtils.h",
"GeolocationPosition.h",
"GeolocationPositionError.h",
"GeolocationSystem.h",
]
SOURCES += [
@ -26,6 +28,7 @@ SOURCES += [
]
UNIFIED_SOURCES += [
"GeolocationSystem.cpp",
"MLSFallback.cpp",
]

Просмотреть файл

@ -105,6 +105,7 @@
#include "mozilla/dom/FileSystemSecurity.h"
#include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/GeolocationPositionError.h"
#include "mozilla/dom/GeolocationSystem.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/JSActorService.h"
@ -7900,6 +7901,26 @@ IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
#endif
}
IPCResult ContentParent::RecvGetSystemGeolocationPermissionBehavior(
GetSystemGeolocationPermissionBehaviorResolver&& aResolver) {
aResolver(Geolocation::GetLocationOSPermission());
return IPC_OK();
}
IPCResult ContentParent::RecvRequestGeolocationPermissionFromUser(
const MaybeDiscardedBrowsingContext& aBrowsingContext,
RequestGeolocationPermissionFromUserResolver&& aResolver) {
if (MOZ_UNLIKELY(aBrowsingContext.IsNullOrDiscarded())) {
aResolver(GeolocationPermissionStatus::Error);
return IPC_OK();
}
RefPtr<BrowsingContext> browsingContext = aBrowsingContext.get();
Geolocation::ReallowWithSystemPermissionOrCancel(browsingContext,
std::move(aResolver));
return IPC_OK();
}
#ifdef FUZZING_SNAPSHOT
IPCResult ContentParent::RecvSignalFuzzingReady() {
// No action needed here, we already observe this message directly

Просмотреть файл

@ -1388,6 +1388,14 @@ class ContentParent final : public PContentParent,
mozilla::ipc::IPCResult RecvGetSystemIcon(nsIURI* aURI,
GetSystemIconResolver&& aResolver);
mozilla::ipc::IPCResult RecvGetSystemGeolocationPermissionBehavior(
GetSystemGeolocationPermissionBehaviorResolver&& aResolver);
MOZ_CAN_RUN_SCRIPT_BOUNDARY mozilla::ipc::IPCResult
RecvRequestGeolocationPermissionFromUser(
const MaybeDiscardedBrowsingContext& aBrowsingContext,
RequestGeolocationPermissionFromUserResolver&& aResolver);
#ifdef FUZZING_SNAPSHOT
mozilla::ipc::IPCResult RecvSignalFuzzingReady();
#endif

Просмотреть файл

@ -76,6 +76,7 @@ include "mozilla/dom/BindingIPCUtils.h";
include "mozilla/dom/CSPMessageUtils.h";
include "mozilla/dom/DocShellMessageUtils.h";
include "mozilla/dom/FeaturePolicyUtils.h";
include "mozilla/dom/GeolocationIPCUtils.h";
include "mozilla/dom/MediaSessionIPCUtils.h";
include "mozilla/dom/PageLoadEventUtils.h";
include "mozilla/dom/ReferrerInfoUtils.h";
@ -117,6 +118,8 @@ using mozilla::Telemetry::ScalarAction from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::KeyedScalarAction from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::DynamicScalarDefinition from "mozilla/TelemetryComms.h";
using mozilla::Telemetry::ChildEventData from "mozilla/TelemetryComms.h";
using mozilla::dom::geolocation::SystemGeolocationPermissionBehavior from "mozilla/dom/GeolocationIPCUtils.h";
using mozilla::dom::geolocation::GeolocationPermissionStatus from "mozilla/dom/GeolocationIPCUtils.h";
#if defined(XP_WIN)
[MoveOnly] using mozilla::UntrustedModulesData from "mozilla/UntrustedModulesData.h";
@ -1971,6 +1974,15 @@ parent:
// implementation in ContentParent::RecvGetSystemIcon for details.
async GetSystemIcon(nullable nsIURI aURI) returns (nsresult aResult, ByteBuf? aData);
// Returns the status of the geolocation permission on this system.
// May not be accurate if the information is not known.
async GetSystemGeolocationPermissionBehavior() returns (SystemGeolocationPermissionBehavior permission);
// Opens system geolocation settings and posts a modal dialog dialog
// to the tab that requested geolocation. Returns permission status
// after user has granted or canceled permission.
async RequestGeolocationPermissionFromUser(MaybeDiscardedBrowsingContext aBrowsingContext) returns (GeolocationPermissionStatus aStatus);
#ifdef FUZZING_SNAPSHOT
// Used by the child process to signal that it is ready to start fuzzing.
// This can in particular be used to wait for a particular event in a

Просмотреть файл

@ -10,4 +10,6 @@ if CONFIG["MOZ_ENABLE_DBUS"]:
LOCAL_INCLUDES += ["/dom/geolocation"]
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = "xul"