WebIdentityHandler.cpp (8907B)
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/WebIdentityHandler.h" 8 9 #include "mozilla/dom/IdentityCredential.h" 10 #include "mozilla/dom/WindowGlobalChild.h" 11 #include "nsCycleCollectionParticipant.h" 12 13 namespace mozilla::dom { 14 15 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebIdentityHandler) 16 NS_INTERFACE_MAP_ENTRY(nsISupports) 17 NS_INTERFACE_MAP_END 18 19 NS_IMPL_CYCLE_COLLECTION(WebIdentityHandler, mWindow, mGetPromise) 20 21 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebIdentityHandler) 22 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebIdentityHandler) 23 24 WebIdentityHandler::~WebIdentityHandler() { 25 MOZ_ASSERT(NS_IsMainThread()); 26 if (mActor) { 27 if (mGetPromise) { 28 mGetPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); 29 mGetPromise = nullptr; 30 Unfollow(); 31 } 32 mActor->SetHandler(nullptr); 33 mWindow = nullptr; 34 } 35 } 36 37 bool WebIdentityHandler::MaybeCreateActor() { 38 if (mActor) { 39 return true; 40 } 41 42 RefPtr<WebIdentityChild> actor = new WebIdentityChild(); 43 WindowGlobalChild* windowGlobalChild = mWindow->GetWindowGlobalChild(); 44 45 if (!windowGlobalChild || 46 !windowGlobalChild->SendPWebIdentityConstructor(actor)) { 47 return false; 48 } 49 50 mActor = actor; 51 mActor->SetHandler(this); 52 return true; 53 } 54 55 void WebIdentityHandler::GetCredential(const CredentialRequestOptions& aOptions, 56 bool aSameOriginWithAncestors, 57 const RefPtr<Promise>& aPromise) { 58 MOZ_ASSERT(XRE_IsContentProcess()); 59 MOZ_ASSERT(mWindow); 60 MOZ_ASSERT(aPromise); 61 MOZ_ASSERT(aOptions.mIdentity.WasPassed()); 62 // Prevent origin confusion by requiring no cross domain iframes 63 // in this one's ancestry 64 if (!aSameOriginWithAncestors) { 65 aPromise->MaybeRejectWithNotAllowedError("Same origin ancestors only."); 66 return; 67 } 68 69 if (!mActor) { 70 aPromise->MaybeRejectWithUnknownError("Unknown failure"); 71 return; 72 } 73 74 if (mGetPromise) { 75 aPromise->MaybeRejectWithNotAllowedError( 76 "Concurrent requests not allowed."); 77 return; 78 } 79 mGetPromise = aPromise; 80 81 RefPtr<WebIdentityHandler> self(this); 82 mActor 83 ->SendGetIdentityCredential( 84 aOptions.mIdentity.Value(), aOptions.mMediation, 85 mWindow->GetWindowContext() && 86 mWindow->GetWindowContext() 87 ->HasValidTransientUserGestureActivation()) 88 ->Then( 89 GetCurrentSerialEventTarget(), __func__, 90 [self](const WebIdentityChild::GetIdentityCredentialPromise:: 91 ResolveValueType& aResult) { 92 if (self->mGetPromise) { 93 if (aResult.type() == 94 WebIdentityGetCredentialResponse::TIPCIdentityCredential) { 95 const IPCIdentityCredential& result = 96 aResult.get_IPCIdentityCredential(); 97 self->mGetPromise->MaybeResolve( 98 new IdentityCredential(self->mWindow, result)); 99 self->mGetPromise = nullptr; 100 self->Unfollow(); 101 } else { 102 self->mGetPromise->MaybeRejectWithNetworkError( 103 "Failure to gather the credential"); 104 self->mGetPromise = nullptr; 105 self->Unfollow(); 106 } 107 } 108 }, 109 [self](const WebIdentityChild::GetIdentityCredentialPromise:: 110 RejectValueType& aResult) { 111 if (self->mGetPromise) { 112 self->mGetPromise->MaybeRejectWithOperationError(""); 113 self->mGetPromise = nullptr; 114 self->Unfollow(); 115 } 116 }); 117 } 118 119 void WebIdentityHandler::PreventSilentAccess(const RefPtr<Promise>& aPromise) { 120 if (!mActor) { 121 aPromise->MaybeRejectWithUnknownError("Unknown failure"); 122 return; 123 } 124 mActor->SendPreventSilentAccess()->Then( 125 GetCurrentSerialEventTarget(), __func__, 126 [aPromise](const WebIdentityChild::PreventSilentAccessPromise:: 127 ResolveOrRejectValue& unused) { 128 aPromise->MaybeResolveWithUndefined(); 129 }); 130 } 131 132 void WebIdentityHandler::Disconnect( 133 const IdentityCredentialDisconnectOptions& aOptions, 134 const RefPtr<Promise>& aPromise) { 135 if (!mActor) { 136 aPromise->MaybeRejectWithUnknownError("Unknown failure"); 137 return; 138 } 139 mActor->SendDisconnectIdentityCredential(aOptions)->Then( 140 GetCurrentSerialEventTarget(), __func__, 141 [aPromise](nsresult aResult) { 142 if (aResult == NS_ERROR_DOM_MALFORMED_URI) { 143 aPromise->MaybeRejectWithInvalidStateError( 144 "Error parsing the provided URI"); 145 } else if (NS_FAILED(aResult)) { 146 aPromise->MaybeRejectWithNetworkError( 147 "Error sending disconnect request"); 148 } else { 149 aPromise->MaybeResolveWithUndefined(); 150 } 151 }, 152 [aPromise](mozilla::ipc::ResponseRejectReason aError) { 153 aPromise->MaybeRejectWithUnknownError("Unknown failure"); 154 }); 155 } 156 157 void WebIdentityHandler::SetLoginStatus(const LoginStatus& aStatus, 158 const RefPtr<Promise>& aPromise) { 159 const RefPtr<Promise>& promise = aPromise; 160 if (!mActor) { 161 promise->MaybeRejectWithUnknownError( 162 "navigator.login.setStatus had an unexpected internal error"); 163 return; 164 } 165 mActor->SendSetLoginStatus(aStatus)->Then( 166 GetCurrentSerialEventTarget(), __func__, 167 [promise](const WebIdentityChild::SetLoginStatusPromise::ResolveValueType& 168 aResult) { 169 if (NS_SUCCEEDED(aResult)) { 170 promise->MaybeResolveWithUndefined(); 171 } else { 172 promise->MaybeRejectWithUnknownError( 173 "navigator.login.setStatus had an unexpected internal error"); 174 } 175 }, 176 [promise](const WebIdentityChild::SetLoginStatusPromise::RejectValueType& 177 aResult) { 178 promise->MaybeRejectWithUnknownError( 179 "navigator.login.setStatus had an unexpected internal error"); 180 }); 181 } 182 183 RefPtr<MozPromise<nsresult, nsresult, true>> 184 WebIdentityHandler::ResolveContinuationWindow( 185 const nsACString& aToken, const IdentityResolveOptions& aOptions) { 186 if (!mActor) { 187 return MozPromise<nsresult, nsresult, true>::CreateAndReject( 188 NS_ERROR_UNEXPECTED, __func__); 189 } 190 // Tell the parent process that we want to resolve with a given token and 191 // options. The main process will infer what popup we are, and find the 192 // pending promise. 193 RefPtr<MozPromise<nsresult, nsresult, true>::Private> promise = 194 new MozPromise<nsresult, nsresult, true>::Private(__func__); 195 mActor->SendResolveContinuationWindow(aToken, aOptions) 196 ->Then( 197 GetCurrentSerialEventTarget(), __func__, 198 [promise](const WebIdentityChild::ResolveContinuationWindowPromise:: 199 ResolveValueType& aResult) { 200 // Only resolve on success 201 if (NS_SUCCEEDED(aResult)) { 202 promise->Resolve(aResult, __func__); 203 } else { 204 promise->Reject(aResult, __func__); 205 } 206 }, 207 [promise](const WebIdentityChild::ResolveContinuationWindowPromise:: 208 RejectValueType& aResult) { 209 // Fall back to a not allowed error when IPC fails. 210 promise->Reject(nsresult::NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__); 211 }); 212 return promise.forget(); 213 } 214 215 RefPtr<MozPromise<bool, nsresult, true>> 216 WebIdentityHandler::IsContinuationWindow() { 217 if (!mActor) { 218 return MozPromise<bool, nsresult, true>::CreateAndReject( 219 NS_ERROR_UNEXPECTED, __func__); 220 } 221 RefPtr<MozPromise<bool, nsresult, true>::Private> promise = 222 new MozPromise<bool, nsresult, true>::Private(__func__); 223 mActor->SendIsActiveContinuationWindow()->Then( 224 GetCurrentSerialEventTarget(), __func__, 225 [promise](bool result) { promise->Resolve(result, __func__); }, 226 [promise](mozilla::ipc::ResponseRejectReason reject) { 227 promise->Resolve(false, __func__); 228 }); 229 return promise.forget(); 230 } 231 232 void WebIdentityHandler::ActorDestroyed() { 233 MOZ_ASSERT(NS_IsMainThread()); 234 mActor = nullptr; 235 } 236 237 void WebIdentityHandler::RunAbortAlgorithm() { 238 if (!mGetPromise) { 239 return; 240 } 241 242 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow); 243 244 AutoJSAPI jsapi; 245 if (!jsapi.Init(global)) { 246 mGetPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); 247 mGetPromise = nullptr; 248 Unfollow(); 249 return; 250 } 251 JSContext* cx = jsapi.cx(); 252 JS::Rooted<JS::Value> reason(cx); 253 Signal()->GetReason(cx, &reason); 254 mGetPromise->MaybeReject(reason); 255 mGetPromise = nullptr; 256 Unfollow(); 257 } 258 259 } // namespace mozilla::dom