NavigatorLogin.cpp (5255B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/NavigatorLogin.h" 8 9 #include "mozilla/Components.h" 10 #include "mozilla/Maybe.h" 11 #include "mozilla/dom/CredentialsContainer.h" 12 #include "mozilla/dom/Document.h" 13 #include "mozilla/dom/Promise.h" 14 #include "mozilla/dom/WebIdentityHandler.h" 15 #include "mozilla/net/SFVService.h" 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsIGlobalObject.h" 18 #include "nsIPermissionManager.h" 19 #include "nsIPrincipal.h" 20 #include "nsString.h" 21 22 namespace mozilla { 23 namespace dom { 24 25 static constexpr nsLiteralCString kLoginStatusPermission = 26 "self-reported-logged-in"_ns; 27 28 uint32_t ConvertStatusToPermission(LoginStatus aStatus) { 29 if (aStatus == LoginStatus::Logged_in) { 30 return nsIPermissionManager::ALLOW_ACTION; 31 } else if (aStatus == LoginStatus::Logged_out) { 32 return nsIPermissionManager::DENY_ACTION; 33 } else { 34 // This should be unreachable, but let's return a real value 35 return nsIPermissionManager::UNKNOWN_ACTION; 36 } 37 } 38 39 Maybe<LoginStatus> PermissionToStatus(uint32_t aPermission) { 40 if (aPermission == nsIPermissionManager::ALLOW_ACTION) { 41 return Some(LoginStatus::Logged_in); 42 } else if (aPermission == nsIPermissionManager::DENY_ACTION) { 43 return Some(LoginStatus::Logged_out); 44 } else { 45 if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) { 46 MOZ_ASSERT(false, "Unexpected permission action from login status"); 47 } 48 return Nothing(); 49 } 50 } 51 52 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(NavigatorLogin, mOwner) 53 54 NavigatorLogin::~NavigatorLogin() = default; 55 56 JSObject* NavigatorLogin::WrapObject(JSContext* aCx, 57 JS::Handle<JSObject*> aGivenProto) { 58 return NavigatorLogin_Binding::Wrap(aCx, this, aGivenProto); 59 } 60 61 NavigatorLogin::NavigatorLogin(nsPIDOMWindowInner* aGlobal) : mOwner(aGlobal) { 62 MOZ_ASSERT(mOwner); 63 }; 64 65 already_AddRefed<mozilla::dom::Promise> NavigatorLogin::SetStatus( 66 LoginStatus aStatus, mozilla::ErrorResult& aRv) { 67 RefPtr<Promise> promise = Promise::Create(mOwner->AsGlobal(), aRv); 68 if (aRv.Failed()) { 69 return nullptr; 70 } 71 72 if (!CredentialsContainer::IsSameOriginWithAncestors(mOwner)) { 73 promise->MaybeRejectWithSecurityError( 74 "navigator.login.setStatus must be called in a frame that is same-origin with its ancestors"_ns); 75 return promise.forget(); 76 } 77 78 WebIdentityHandler* identityHandler = mOwner->GetOrCreateWebIdentityHandler(); 79 if (!identityHandler) { 80 promise->MaybeRejectWithOperationError(""); 81 return promise.forget(); 82 } 83 84 identityHandler->SetLoginStatus(aStatus, promise); 85 return promise.forget(); 86 } 87 88 // static 89 nsresult NavigatorLogin::SetLoginStatus(nsIPrincipal* aPrincipal, 90 LoginStatus aStatus) { 91 MOZ_ASSERT(XRE_IsParentProcess()); 92 93 nsCOMPtr<nsIPermissionManager> permMgr = 94 components::PermissionManager::Service(); 95 if (!permMgr) { 96 return NS_ERROR_NOT_AVAILABLE; 97 } 98 99 return permMgr->AddFromPrincipal(aPrincipal, kLoginStatusPermission, 100 ConvertStatusToPermission(aStatus), 101 nsIPermissionManager::EXPIRE_NEVER, 0); 102 } 103 104 // static 105 nsresult NavigatorLogin::SetLoginStatus(nsIPrincipal* aPrincipal, 106 const nsACString& aStatus) { 107 LoginStatus parsedStatus; 108 nsresult rv = ParseLoginStatusHeader(aStatus, parsedStatus); 109 NS_ENSURE_SUCCESS(rv, rv); 110 return SetLoginStatus(aPrincipal, parsedStatus); 111 } 112 113 // static 114 nsresult NavigatorLogin::ParseLoginStatusHeader(const nsACString& aStatus, 115 LoginStatus& aResult) { 116 nsCOMPtr<nsISFVService> sfv = net::GetSFVService(); 117 nsCOMPtr<nsISFVItem> item; 118 nsresult rv = sfv->ParseItem(aStatus, getter_AddRefs(item)); 119 if (NS_FAILED(rv)) { 120 return rv; 121 } 122 123 nsCOMPtr<nsISFVBareItem> value; 124 rv = item->GetValue(getter_AddRefs(value)); 125 if (NS_FAILED(rv)) { 126 return rv; 127 } 128 129 nsCOMPtr<nsISFVToken> token = do_QueryInterface(value); 130 if (!token) { 131 return NS_ERROR_UNEXPECTED; 132 } 133 134 nsAutoCString parsedStatus; 135 rv = token->GetValue(parsedStatus); 136 if (NS_FAILED(rv)) { 137 return rv; 138 } 139 140 if (parsedStatus == "logged-in") { 141 aResult = LoginStatus::Logged_in; 142 return NS_OK; 143 } 144 if (parsedStatus == "logged-out") { 145 aResult = LoginStatus::Logged_out; 146 return NS_OK; 147 } 148 return NS_ERROR_INVALID_ARG; 149 } 150 151 // static 152 nsresult GetLoginStatus(nsIPrincipal* aPrincipal, Maybe<LoginStatus>& aStatus) { 153 nsCOMPtr<nsIPermissionManager> permMgr = 154 components::PermissionManager::Service(); 155 if (!permMgr) { 156 aStatus = Nothing(); 157 return NS_ERROR_SERVICE_NOT_AVAILABLE; 158 } 159 uint32_t action; 160 nsresult rv = permMgr->TestPermissionFromPrincipal( 161 aPrincipal, kLoginStatusPermission, &action); 162 if (NS_FAILED(rv)) { 163 aStatus = Nothing(); 164 return rv; 165 } 166 aStatus = PermissionToStatus(action); 167 return NS_OK; 168 } 169 170 } // namespace dom 171 } // namespace mozilla