Bug 1945576, part 2 - Add implementation for Login Status JS hooks - r=anti-tracking-reviewers,timhuang
Differential Revision: https://phabricator.services.mozilla.com/D240218
This commit is contained in:
@@ -98,7 +98,9 @@ static bool ConsumeUserActivation(nsPIDOMWindowInner* aParent) {
|
||||
return doc->ConsumeTransientUserGestureActivation();
|
||||
}
|
||||
|
||||
static bool IsSameOriginWithAncestors(nsPIDOMWindowInner* aParent) {
|
||||
// static
|
||||
bool CredentialsContainer::IsSameOriginWithAncestors(
|
||||
nsPIDOMWindowInner* aParent) {
|
||||
// This method returns true if aParent is either not in a frame / iframe, or
|
||||
// is in a frame or iframe and all ancestors for aParent are the same origin.
|
||||
// This is useful for Credential Management because we need to prohibit
|
||||
|
||||
@@ -38,6 +38,8 @@ class CredentialsContainer final : public nsISupports, public nsWrapperCache {
|
||||
|
||||
already_AddRefed<Promise> PreventSilentAccess(ErrorResult& aRv);
|
||||
|
||||
static bool IsSameOriginWithAncestors(nsPIDOMWindowInner* aParent);
|
||||
|
||||
private:
|
||||
~CredentialsContainer();
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "mozilla/dom/IdentityCredential.h"
|
||||
#include "mozilla/dom/IdentityCredentialBinding.h"
|
||||
#include "mozilla/dom/CredentialManagementBinding.h"
|
||||
#include "mozilla/dom/LoginStatusBinding.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
@@ -81,6 +82,10 @@ struct ParamTraits<mozilla::dom::IdentityCredentialRequestOptions> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::LoginStatus>
|
||||
: public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::LoginStatus> {};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_dom_identitycredentialserializationhelpers_h__
|
||||
|
||||
@@ -4,10 +4,48 @@
|
||||
* 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 "mozilla/Components.h"
|
||||
#include "mozilla/dom/CredentialsContainer.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/NavigatorLogin.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static constexpr nsLiteralCString kLoginStatusPermission =
|
||||
"self-reported-logged-in"_ns;
|
||||
|
||||
uint32_t ConvertStatusToPermission(LoginStatus aStatus) {
|
||||
if (aStatus == LoginStatus::Logged_in) {
|
||||
return nsIPermissionManager::ALLOW_ACTION;
|
||||
} else if (aStatus == LoginStatus::Logged_out) {
|
||||
return nsIPermissionManager::DENY_ACTION;
|
||||
} else {
|
||||
// This should be unreachable, but let's return a real value
|
||||
return nsIPermissionManager::UNKNOWN_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<LoginStatus> PermissionToStatus(uint32_t aPermission) {
|
||||
if (aPermission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return Some(LoginStatus::Logged_in);
|
||||
} else if (aPermission == nsIPermissionManager::DENY_ACTION) {
|
||||
return Some(LoginStatus::Logged_out);
|
||||
} else {
|
||||
if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
MOZ_ASSERT(false, "Unexpected permission action from login status");
|
||||
}
|
||||
return Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(NavigatorLogin, mOwner)
|
||||
|
||||
@@ -18,21 +56,91 @@ JSObject* NavigatorLogin::WrapObject(JSContext* aCx,
|
||||
return NavigatorLogin_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NavigatorLogin::NavigatorLogin(nsIGlobalObject* aGlobal)
|
||||
: mOwner(aGlobal){
|
||||
MOZ_ASSERT(mOwner);
|
||||
};
|
||||
NavigatorLogin::NavigatorLogin(nsIGlobalObject* aGlobal) : mOwner(aGlobal) {
|
||||
MOZ_ASSERT(mOwner);
|
||||
};
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise> NavigatorLogin::SetStatus(
|
||||
const LoginStatus& aStatus, mozilla::ErrorResult& aRv) {
|
||||
|
||||
LoginStatus aStatus, mozilla::ErrorResult& aRv) {
|
||||
RefPtr<Promise> promise = Promise::Create(mOwner, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
promise->MaybeRejectWithNotSupportedError(
|
||||
"navigator.login.setStatus not implemented"_ns);
|
||||
|
||||
nsPIDOMWindowInner* window = mOwner->GetAsInnerWindow();
|
||||
if (!window) {
|
||||
promise->MaybeRejectWithUnknownError(
|
||||
"navigator.login.setStatus called on unavailable window"_ns);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!CredentialsContainer::IsSameOriginWithAncestors(window)) {
|
||||
promise->MaybeRejectWithSecurityError(
|
||||
"navigator.login.setStatus must be called in a frame that is same-origin with its ancestors"_ns);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
WindowGlobalChild* wgc = window->GetWindowGlobalChild();
|
||||
if (!wgc) {
|
||||
promise->MaybeRejectWithUnknownError(
|
||||
"navigator.login.setStatus called while window already destroyed"_ns);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
wgc->SendSetLoginStatus(aStatus)->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[promise](
|
||||
const WindowGlobalChild::SetLoginStatusPromise::ResolveValueType&
|
||||
aResult) {
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
} else {
|
||||
promise->MaybeRejectWithUnknownError(
|
||||
"navigator.login.setStatus had an unexpected internal error");
|
||||
}
|
||||
},
|
||||
[promise](const WindowGlobalChild::SetLoginStatusPromise::RejectValueType&
|
||||
aResult) {
|
||||
promise->MaybeRejectWithUnknownError(
|
||||
"navigator.login.setStatus had an unexpected internal error");
|
||||
});
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
// static
|
||||
nsresult NavigatorLogin::SetLoginStatus(nsIPrincipal* aPrincipal,
|
||||
LoginStatus aStatus) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
components::PermissionManager::Service();
|
||||
if (!permMgr) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return permMgr->AddFromPrincipal(aPrincipal, kLoginStatusPermission,
|
||||
ConvertStatusToPermission(aStatus),
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult GetLoginStatus(nsIPrincipal* aPrincipal, Maybe<LoginStatus>& aStatus) {
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
components::PermissionManager::Service();
|
||||
if (!permMgr) {
|
||||
aStatus = Nothing();
|
||||
return NS_ERROR_SERVICE_NOT_AVAILABLE;
|
||||
}
|
||||
uint32_t action;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(
|
||||
aPrincipal, kLoginStatusPermission, &action);
|
||||
if (NS_FAILED(rv)) {
|
||||
aStatus = Nothing();
|
||||
return rv;
|
||||
}
|
||||
aStatus = PermissionToStatus(action);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#ifndef mozilla_dom_NavigatorLogin_h
|
||||
#define mozilla_dom_NavigatorLogin_h
|
||||
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/dom/LoginStatusBinding.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@@ -24,9 +27,12 @@ class NavigatorLogin : public nsWrapperCache {
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise> SetStatus(const LoginStatus& aStatus,
|
||||
already_AddRefed<mozilla::dom::Promise> SetStatus(LoginStatus aStatus,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
static Maybe<LoginStatus> GetLoginStatus(nsIPrincipal* aPrincipal);
|
||||
static nsresult SetLoginStatus(nsIPrincipal* aPrincipal, LoginStatus aStatus);
|
||||
|
||||
protected:
|
||||
virtual ~NavigatorLogin();
|
||||
|
||||
@@ -36,4 +42,4 @@ class NavigatorLogin : public nsWrapperCache {
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_NavigatorLogin_h
|
||||
#endif // mozilla_dom_NavigatorLogin_h
|
||||
|
||||
@@ -40,6 +40,7 @@ using mozilla::dom::IdentityCredentialDisconnectOptions from "mozilla/dom/Identi
|
||||
using mozilla::dom::IdentityCredentialInit from "mozilla/dom/IdentityCredentialBinding.h";
|
||||
using mozilla::dom::IdentityCredentialRequestOptions from "mozilla/dom/IdentityCredentialBinding.h";
|
||||
using mozilla::dom::IdentityLoginTargetType from "mozilla/dom/IdentityCredentialBinding.h";
|
||||
using mozilla::dom::LoginStatus from "mozilla/dom/LoginStatusBinding.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -218,6 +219,9 @@ parent:
|
||||
async DisconnectIdentityCredential(IdentityCredentialDisconnectOptions aOptions) returns (nsresult rv);
|
||||
async PreventSilentAccess() returns (nsresult rv);
|
||||
|
||||
// Indicate that the page has reported itself as logged in
|
||||
async SetLoginStatus(LoginStatus foo) returns (nsresult rv);
|
||||
|
||||
async GetStorageAccessPermission(bool aIncludeIdentityCredential) returns(uint32_t permission_action);
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/IdentityCredential.h"
|
||||
#include "mozilla/dom/MediaController.h"
|
||||
#include "mozilla/dom/NavigatorLogin.h"
|
||||
#include "mozilla/dom/WebAuthnTransactionParent.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/ChromeUtils.h"
|
||||
@@ -1503,6 +1504,18 @@ IPCResult WindowGlobalParent::RecvPreventSilentAccess(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvSetLoginStatus(
|
||||
LoginStatus aStatus, const SetLoginStatusResolver& aResolver) {
|
||||
nsIPrincipal* principal = DocumentPrincipal();
|
||||
if (!principal) {
|
||||
aResolver(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
return IPC_OK();
|
||||
}
|
||||
nsresult rv = NavigatorLogin::SetLoginStatus(principal, aStatus);
|
||||
aResolver(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult WindowGlobalParent::RecvGetStorageAccessPermission(
|
||||
bool aIncludeIdentityCredential,
|
||||
GetStorageAccessPermissionResolver&& aResolve) {
|
||||
|
||||
@@ -328,6 +328,9 @@ class WindowGlobalParent final : public WindowContext,
|
||||
mozilla::ipc::IPCResult RecvDisconnectIdentityCredential(
|
||||
const IdentityCredentialDisconnectOptions& aOptions,
|
||||
const DisconnectIdentityCredentialResolver& aResolver);
|
||||
mozilla::ipc::IPCResult RecvSetLoginStatus(
|
||||
LoginStatus aStatus, const SetLoginStatusResolver& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPreventSilentAccess(
|
||||
const PreventSilentAccessResolver& aResolver);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user