/src/mozilla-central/dom/base/nsContentPermissionHelper.cpp
Line | Count | Source (jump to first uncovered line) |
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 <map> |
8 | | #include "nsCOMPtr.h" |
9 | | #include "nsIPrincipal.h" |
10 | | #include "mozilla/dom/ContentChild.h" |
11 | | #include "mozilla/dom/ContentParent.h" |
12 | | #include "mozilla/dom/Element.h" |
13 | | #include "mozilla/dom/Event.h" |
14 | | #include "mozilla/dom/PContentPermission.h" |
15 | | #include "mozilla/dom/PermissionMessageUtils.h" |
16 | | #include "mozilla/dom/PContentPermissionRequestParent.h" |
17 | | #include "mozilla/dom/ScriptSettings.h" |
18 | | #include "mozilla/dom/TabChild.h" |
19 | | #include "mozilla/dom/TabParent.h" |
20 | | #include "mozilla/EventStateManager.h" |
21 | | #include "mozilla/Unused.h" |
22 | | #include "nsComponentManagerUtils.h" |
23 | | #include "nsArrayUtils.h" |
24 | | #include "nsIMutableArray.h" |
25 | | #include "nsContentPermissionHelper.h" |
26 | | #include "nsJSUtils.h" |
27 | | #include "nsISupportsPrimitives.h" |
28 | | #include "nsServiceManagerUtils.h" |
29 | | #include "nsIDocument.h" |
30 | | #include "nsWeakPtr.h" |
31 | | |
32 | | using mozilla::Unused; // <snicker> |
33 | | using namespace mozilla::dom; |
34 | | using namespace mozilla; |
35 | | |
36 | 0 | #define kVisibilityChange "visibilitychange" |
37 | | |
38 | | class VisibilityChangeListener final : public nsIDOMEventListener |
39 | | { |
40 | | public: |
41 | | NS_DECL_ISUPPORTS |
42 | | NS_DECL_NSIDOMEVENTLISTENER |
43 | | |
44 | | explicit VisibilityChangeListener(nsPIDOMWindowInner* aWindow); |
45 | | |
46 | | void RemoveListener(); |
47 | | void SetCallback(nsIContentPermissionRequestCallback* aCallback); |
48 | | already_AddRefed<nsIContentPermissionRequestCallback> GetCallback(); |
49 | | |
50 | | private: |
51 | 0 | virtual ~VisibilityChangeListener() {} |
52 | | |
53 | | nsWeakPtr mWindow; |
54 | | nsCOMPtr<nsIContentPermissionRequestCallback> mCallback; |
55 | | }; |
56 | | |
57 | | NS_IMPL_ISUPPORTS(VisibilityChangeListener, nsIDOMEventListener) |
58 | | |
59 | | VisibilityChangeListener::VisibilityChangeListener(nsPIDOMWindowInner* aWindow) |
60 | 0 | { |
61 | 0 | MOZ_ASSERT(aWindow); |
62 | 0 |
|
63 | 0 | mWindow = do_GetWeakReference(aWindow); |
64 | 0 | nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc(); |
65 | 0 | if (doc) { |
66 | 0 | doc->AddSystemEventListener(NS_LITERAL_STRING(kVisibilityChange), |
67 | 0 | /* listener */ this, |
68 | 0 | /* use capture */ true, |
69 | 0 | /* wants untrusted */ false); |
70 | 0 | } |
71 | 0 |
|
72 | 0 | } |
73 | | |
74 | | NS_IMETHODIMP |
75 | | VisibilityChangeListener::HandleEvent(Event* aEvent) |
76 | 0 | { |
77 | 0 | nsAutoString type; |
78 | 0 | aEvent->GetType(type); |
79 | 0 | if (!type.EqualsLiteral(kVisibilityChange)) { |
80 | 0 | return NS_ERROR_FAILURE; |
81 | 0 | } |
82 | 0 | |
83 | 0 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(aEvent->GetTarget()); |
84 | 0 | MOZ_ASSERT(doc); |
85 | 0 |
|
86 | 0 | if (mCallback) { |
87 | 0 | mCallback->NotifyVisibility(!doc->Hidden()); |
88 | 0 | } |
89 | 0 |
|
90 | 0 | return NS_OK; |
91 | 0 | } |
92 | | |
93 | | void |
94 | | VisibilityChangeListener::RemoveListener() |
95 | 0 | { |
96 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow); |
97 | 0 | if (!window) { |
98 | 0 | return; |
99 | 0 | } |
100 | 0 | |
101 | 0 | nsCOMPtr<EventTarget> target = do_QueryInterface(window->GetExtantDoc()); |
102 | 0 | if (target) { |
103 | 0 | target->RemoveSystemEventListener(NS_LITERAL_STRING(kVisibilityChange), |
104 | 0 | /* listener */ this, |
105 | 0 | /* use capture */ true); |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | | void |
110 | | VisibilityChangeListener::SetCallback(nsIContentPermissionRequestCallback *aCallback) |
111 | 0 | { |
112 | 0 | mCallback = aCallback; |
113 | 0 | } |
114 | | |
115 | | already_AddRefed<nsIContentPermissionRequestCallback> |
116 | | VisibilityChangeListener::GetCallback() |
117 | 0 | { |
118 | 0 | nsCOMPtr<nsIContentPermissionRequestCallback> callback = mCallback; |
119 | 0 | return callback.forget(); |
120 | 0 | } |
121 | | |
122 | | namespace mozilla { |
123 | | namespace dom { |
124 | | |
125 | | class ContentPermissionRequestParent : public PContentPermissionRequestParent |
126 | | { |
127 | | public: |
128 | | ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, |
129 | | Element* aElement, |
130 | | const IPC::Principal& aPrincipal, |
131 | | const bool aIsHandlingUserInput); |
132 | | virtual ~ContentPermissionRequestParent(); |
133 | | |
134 | | bool IsBeingDestroyed(); |
135 | | |
136 | | nsCOMPtr<nsIPrincipal> mPrincipal; |
137 | | nsCOMPtr<Element> mElement; |
138 | | bool mIsHandlingUserInput; |
139 | | RefPtr<nsContentPermissionRequestProxy> mProxy; |
140 | | nsTArray<PermissionRequest> mRequests; |
141 | | |
142 | | private: |
143 | | virtual mozilla::ipc::IPCResult Recvprompt() override; |
144 | | virtual mozilla::ipc::IPCResult RecvNotifyVisibility(const bool& aIsVisible) override; |
145 | | virtual mozilla::ipc::IPCResult RecvDestroy() override; |
146 | | virtual void ActorDestroy(ActorDestroyReason why) override; |
147 | | }; |
148 | | |
149 | | ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, |
150 | | Element* aElement, |
151 | | const IPC::Principal& aPrincipal, |
152 | | const bool aIsHandlingUserInput) |
153 | 0 | { |
154 | 0 | MOZ_COUNT_CTOR(ContentPermissionRequestParent); |
155 | 0 |
|
156 | 0 | mPrincipal = aPrincipal; |
157 | 0 | mElement = aElement; |
158 | 0 | mRequests = aRequests; |
159 | 0 | mIsHandlingUserInput = aIsHandlingUserInput; |
160 | 0 | } |
161 | | |
162 | | ContentPermissionRequestParent::~ContentPermissionRequestParent() |
163 | 0 | { |
164 | 0 | MOZ_COUNT_DTOR(ContentPermissionRequestParent); |
165 | 0 | } |
166 | | |
167 | | mozilla::ipc::IPCResult |
168 | | ContentPermissionRequestParent::Recvprompt() |
169 | 0 | { |
170 | 0 | mProxy = new nsContentPermissionRequestProxy(this); |
171 | 0 | if (NS_FAILED(mProxy->Init(mRequests))) { |
172 | 0 | mProxy->Cancel(); |
173 | 0 | } |
174 | 0 | return IPC_OK(); |
175 | 0 | } |
176 | | |
177 | | mozilla::ipc::IPCResult |
178 | | ContentPermissionRequestParent::RecvNotifyVisibility(const bool& aIsVisible) |
179 | 0 | { |
180 | 0 | if (!mProxy) { |
181 | 0 | return IPC_FAIL_NO_REASON(this); |
182 | 0 | } |
183 | 0 | mProxy->NotifyVisibility(aIsVisible); |
184 | 0 | return IPC_OK(); |
185 | 0 | } |
186 | | |
187 | | mozilla::ipc::IPCResult |
188 | | ContentPermissionRequestParent::RecvDestroy() |
189 | 0 | { |
190 | 0 | Unused << PContentPermissionRequestParent::Send__delete__(this); |
191 | 0 | return IPC_OK(); |
192 | 0 | } |
193 | | |
194 | | void |
195 | | ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) |
196 | 0 | { |
197 | 0 | if (mProxy) { |
198 | 0 | mProxy->OnParentDestroyed(); |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | | bool |
203 | | ContentPermissionRequestParent::IsBeingDestroyed() |
204 | 0 | { |
205 | 0 | // When ContentParent::MarkAsDead() is called, we are being destroyed. |
206 | 0 | // It's unsafe to send out any message now. |
207 | 0 | ContentParent* contentParent = static_cast<ContentParent*>(Manager()); |
208 | 0 | return !contentParent->IsAlive(); |
209 | 0 | } |
210 | | |
211 | | NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType) |
212 | | |
213 | | ContentPermissionType::ContentPermissionType(const nsACString& aType, |
214 | | const nsACString& aAccess, |
215 | | const nsTArray<nsString>& aOptions) |
216 | 0 | { |
217 | 0 | mType = aType; |
218 | 0 | mAccess = aAccess; |
219 | 0 | mOptions = aOptions; |
220 | 0 | } |
221 | | |
222 | | ContentPermissionType::~ContentPermissionType() |
223 | 0 | { |
224 | 0 | } |
225 | | |
226 | | NS_IMETHODIMP |
227 | | ContentPermissionType::GetType(nsACString& aType) |
228 | 0 | { |
229 | 0 | aType = mType; |
230 | 0 | return NS_OK; |
231 | 0 | } |
232 | | |
233 | | NS_IMETHODIMP |
234 | | ContentPermissionType::GetAccess(nsACString& aAccess) |
235 | 0 | { |
236 | 0 | aAccess = mAccess; |
237 | 0 | return NS_OK; |
238 | 0 | } |
239 | | |
240 | | NS_IMETHODIMP |
241 | | ContentPermissionType::GetOptions(nsIArray** aOptions) |
242 | 0 | { |
243 | 0 | NS_ENSURE_ARG_POINTER(aOptions); |
244 | 0 |
|
245 | 0 | *aOptions = nullptr; |
246 | 0 |
|
247 | 0 | nsresult rv; |
248 | 0 | nsCOMPtr<nsIMutableArray> options = |
249 | 0 | do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); |
250 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
251 | 0 |
|
252 | 0 | // copy options into JS array |
253 | 0 | for (uint32_t i = 0; i < mOptions.Length(); ++i) { |
254 | 0 | nsCOMPtr<nsISupportsString> isupportsString = |
255 | 0 | do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); |
256 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
257 | 0 |
|
258 | 0 | rv = isupportsString->SetData(mOptions[i]); |
259 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
260 | 0 |
|
261 | 0 | rv = options->AppendElement(isupportsString); |
262 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
263 | 0 | } |
264 | 0 |
|
265 | 0 | options.forget(aOptions); |
266 | 0 | return NS_OK; |
267 | 0 | } |
268 | | |
269 | | // nsContentPermissionUtils |
270 | | |
271 | | /* static */ uint32_t |
272 | | nsContentPermissionUtils::ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray, |
273 | | nsIMutableArray* aDesArray) |
274 | 0 | { |
275 | 0 | uint32_t len = aSrcArray.Length(); |
276 | 0 | for (uint32_t i = 0; i < len; i++) { |
277 | 0 | RefPtr<ContentPermissionType> cpt = |
278 | 0 | new ContentPermissionType(aSrcArray[i].type(), |
279 | 0 | aSrcArray[i].access(), |
280 | 0 | aSrcArray[i].options()); |
281 | 0 | aDesArray->AppendElement(cpt); |
282 | 0 | } |
283 | 0 | return len; |
284 | 0 | } |
285 | | |
286 | | /* static */ uint32_t |
287 | | nsContentPermissionUtils::ConvertArrayToPermissionRequest(nsIArray* aSrcArray, |
288 | | nsTArray<PermissionRequest>& aDesArray) |
289 | 0 | { |
290 | 0 | uint32_t len = 0; |
291 | 0 | aSrcArray->GetLength(&len); |
292 | 0 | for (uint32_t i = 0; i < len; i++) { |
293 | 0 | nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i); |
294 | 0 | nsAutoCString type; |
295 | 0 | nsAutoCString access; |
296 | 0 | cpt->GetType(type); |
297 | 0 | cpt->GetAccess(access); |
298 | 0 |
|
299 | 0 | nsCOMPtr<nsIArray> optionArray; |
300 | 0 | cpt->GetOptions(getter_AddRefs(optionArray)); |
301 | 0 | uint32_t optionsLength = 0; |
302 | 0 | if (optionArray) { |
303 | 0 | optionArray->GetLength(&optionsLength); |
304 | 0 | } |
305 | 0 | nsTArray<nsString> options; |
306 | 0 | for (uint32_t j = 0; j < optionsLength; ++j) { |
307 | 0 | nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j); |
308 | 0 | if (isupportsString) { |
309 | 0 | nsString option; |
310 | 0 | isupportsString->GetData(option); |
311 | 0 | options.AppendElement(option); |
312 | 0 | } |
313 | 0 | } |
314 | 0 |
|
315 | 0 | aDesArray.AppendElement(PermissionRequest(type, access, options)); |
316 | 0 | } |
317 | 0 | return len; |
318 | 0 | } |
319 | | |
320 | | static std::map<PContentPermissionRequestParent*, TabId>& |
321 | | ContentPermissionRequestParentMap() |
322 | 0 | { |
323 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
324 | 0 | static std::map<PContentPermissionRequestParent*, TabId> sPermissionRequestParentMap; |
325 | 0 | return sPermissionRequestParentMap; |
326 | 0 | } |
327 | | |
328 | | static std::map<PContentPermissionRequestChild*, TabId>& |
329 | | ContentPermissionRequestChildMap() |
330 | 0 | { |
331 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
332 | 0 | static std::map<PContentPermissionRequestChild*, TabId> sPermissionRequestChildMap; |
333 | 0 | return sPermissionRequestChildMap; |
334 | 0 | } |
335 | | |
336 | | /* static */ nsresult |
337 | | nsContentPermissionUtils::CreatePermissionArray(const nsACString& aType, |
338 | | const nsACString& aAccess, |
339 | | const nsTArray<nsString>& aOptions, |
340 | | nsIArray** aTypesArray) |
341 | 0 | { |
342 | 0 | nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); |
343 | 0 | RefPtr<ContentPermissionType> permType = new ContentPermissionType(aType, |
344 | 0 | aAccess, |
345 | 0 | aOptions); |
346 | 0 | types->AppendElement(permType); |
347 | 0 | types.forget(aTypesArray); |
348 | 0 |
|
349 | 0 | return NS_OK; |
350 | 0 | } |
351 | | |
352 | | /* static */ PContentPermissionRequestParent* |
353 | | nsContentPermissionUtils::CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, |
354 | | Element* aElement, |
355 | | const IPC::Principal& aPrincipal, |
356 | | const bool aIsHandlingUserInput, |
357 | | const TabId& aTabId) |
358 | 0 | { |
359 | 0 | PContentPermissionRequestParent* parent = |
360 | 0 | new ContentPermissionRequestParent(aRequests, aElement, aPrincipal, aIsHandlingUserInput); |
361 | 0 | ContentPermissionRequestParentMap()[parent] = aTabId; |
362 | 0 |
|
363 | 0 | return parent; |
364 | 0 | } |
365 | | |
366 | | /* static */ nsresult |
367 | | nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest* aRequest, |
368 | | nsPIDOMWindowInner* aWindow) |
369 | 0 | { |
370 | 0 | NS_ENSURE_STATE(aWindow && aWindow->IsCurrentInnerWindow()); |
371 | 0 |
|
372 | 0 | // for content process |
373 | 0 | if (XRE_IsContentProcess()) { |
374 | 0 |
|
375 | 0 | RefPtr<RemotePermissionRequest> req = |
376 | 0 | new RemotePermissionRequest(aRequest, aWindow); |
377 | 0 |
|
378 | 0 | MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread. |
379 | 0 |
|
380 | 0 | TabChild* child = TabChild::GetFrom(aWindow->GetDocShell()); |
381 | 0 | NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
382 | 0 |
|
383 | 0 | nsCOMPtr<nsIArray> typeArray; |
384 | 0 | nsresult rv = aRequest->GetTypes(getter_AddRefs(typeArray)); |
385 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
386 | 0 |
|
387 | 0 | nsTArray<PermissionRequest> permArray; |
388 | 0 | ConvertArrayToPermissionRequest(typeArray, permArray); |
389 | 0 |
|
390 | 0 | nsCOMPtr<nsIPrincipal> principal; |
391 | 0 | rv = aRequest->GetPrincipal(getter_AddRefs(principal)); |
392 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
393 | 0 |
|
394 | 0 | bool isHandlingUserInput; |
395 | 0 | rv = aRequest->GetIsHandlingUserInput(&isHandlingUserInput); |
396 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
397 | 0 |
|
398 | 0 | ContentChild::GetSingleton()->SetEventTargetForActor( |
399 | 0 | req, aWindow->EventTargetFor(TaskCategory::Other)); |
400 | 0 |
|
401 | 0 | req->IPDLAddRef(); |
402 | 0 | ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor( |
403 | 0 | req, |
404 | 0 | permArray, |
405 | 0 | IPC::Principal(principal), |
406 | 0 | isHandlingUserInput, |
407 | 0 | child->GetTabId()); |
408 | 0 | ContentPermissionRequestChildMap()[req.get()] = child->GetTabId(); |
409 | 0 |
|
410 | 0 | req->Sendprompt(); |
411 | 0 | return NS_OK; |
412 | 0 | } |
413 | 0 | |
414 | 0 | // for chrome process |
415 | 0 | nsCOMPtr<nsIContentPermissionPrompt> prompt = |
416 | 0 | do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); |
417 | 0 | if (prompt) { |
418 | 0 | if (NS_FAILED(prompt->Prompt(aRequest))) { |
419 | 0 | return NS_ERROR_FAILURE; |
420 | 0 | } |
421 | 0 | } |
422 | 0 | return NS_OK; |
423 | 0 | } |
424 | | |
425 | | /* static */ nsTArray<PContentPermissionRequestParent*> |
426 | | nsContentPermissionUtils::GetContentPermissionRequestParentById(const TabId& aTabId) |
427 | 0 | { |
428 | 0 | nsTArray<PContentPermissionRequestParent*> parentArray; |
429 | 0 | for (auto& it : ContentPermissionRequestParentMap()) { |
430 | 0 | if (it.second == aTabId) { |
431 | 0 | parentArray.AppendElement(it.first); |
432 | 0 | } |
433 | 0 | } |
434 | 0 |
|
435 | 0 | return parentArray; |
436 | 0 | } |
437 | | |
438 | | /* static */ void |
439 | | nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent( |
440 | | PContentPermissionRequestParent* aParent) |
441 | 0 | { |
442 | 0 | auto it = ContentPermissionRequestParentMap().find(aParent); |
443 | 0 | MOZ_ASSERT(it != ContentPermissionRequestParentMap().end()); |
444 | 0 |
|
445 | 0 | ContentPermissionRequestParentMap().erase(it); |
446 | 0 | } |
447 | | |
448 | | /* static */ nsTArray<PContentPermissionRequestChild*> |
449 | | nsContentPermissionUtils::GetContentPermissionRequestChildById(const TabId& aTabId) |
450 | 0 | { |
451 | 0 | nsTArray<PContentPermissionRequestChild*> childArray; |
452 | 0 | for (auto& it : ContentPermissionRequestChildMap()) { |
453 | 0 | if (it.second == aTabId) { |
454 | 0 | childArray.AppendElement(it.first); |
455 | 0 | } |
456 | 0 | } |
457 | 0 |
|
458 | 0 | return childArray; |
459 | 0 | } |
460 | | |
461 | | /* static */ void |
462 | | nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild( |
463 | | PContentPermissionRequestChild* aChild) |
464 | 0 | { |
465 | 0 | auto it = ContentPermissionRequestChildMap().find(aChild); |
466 | 0 | MOZ_ASSERT(it != ContentPermissionRequestChildMap().end()); |
467 | 0 |
|
468 | 0 | ContentPermissionRequestChildMap().erase(it); |
469 | 0 | } |
470 | | |
471 | | NS_IMPL_ISUPPORTS(nsContentPermissionRequester, nsIContentPermissionRequester) |
472 | | |
473 | | nsContentPermissionRequester::nsContentPermissionRequester(nsPIDOMWindowInner* aWindow) |
474 | | : mWindow(do_GetWeakReference(aWindow)) |
475 | | , mListener(new VisibilityChangeListener(aWindow)) |
476 | 0 | { |
477 | 0 | } |
478 | | |
479 | | nsContentPermissionRequester::~nsContentPermissionRequester() |
480 | 0 | { |
481 | 0 | mListener->RemoveListener(); |
482 | 0 | mListener = nullptr; |
483 | 0 | } |
484 | | |
485 | | NS_IMETHODIMP |
486 | | nsContentPermissionRequester::GetVisibility(nsIContentPermissionRequestCallback* aCallback) |
487 | 0 | { |
488 | 0 | NS_ENSURE_ARG_POINTER(aCallback); |
489 | 0 |
|
490 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow); |
491 | 0 | if (!window) { |
492 | 0 | return NS_ERROR_FAILURE; |
493 | 0 | } |
494 | 0 | |
495 | 0 | nsCOMPtr<nsIDocShell> docshell = window->GetDocShell(); |
496 | 0 | if (!docshell) { |
497 | 0 | return NS_ERROR_FAILURE; |
498 | 0 | } |
499 | 0 | |
500 | 0 | bool isActive = false; |
501 | 0 | docshell->GetIsActive(&isActive); |
502 | 0 | aCallback->NotifyVisibility(isActive); |
503 | 0 | return NS_OK; |
504 | 0 | } |
505 | | |
506 | | NS_IMETHODIMP |
507 | | nsContentPermissionRequester::SetOnVisibilityChange(nsIContentPermissionRequestCallback* aCallback) |
508 | 0 | { |
509 | 0 | mListener->SetCallback(aCallback); |
510 | 0 |
|
511 | 0 | if (!aCallback) { |
512 | 0 | mListener->RemoveListener(); |
513 | 0 | } |
514 | 0 |
|
515 | 0 | return NS_OK; |
516 | 0 | } |
517 | | |
518 | | NS_IMETHODIMP |
519 | | nsContentPermissionRequester::GetOnVisibilityChange(nsIContentPermissionRequestCallback** aCallback) |
520 | 0 | { |
521 | 0 | NS_ENSURE_ARG_POINTER(aCallback); |
522 | 0 |
|
523 | 0 | nsCOMPtr<nsIContentPermissionRequestCallback> callback = mListener->GetCallback(); |
524 | 0 | callback.forget(aCallback); |
525 | 0 | return NS_OK; |
526 | 0 | } |
527 | | |
528 | | } // namespace dom |
529 | | } // namespace mozilla |
530 | | |
531 | | NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy, |
532 | | nsIContentPermissionRequester) |
533 | | |
534 | | NS_IMETHODIMP |
535 | | nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy |
536 | | ::GetVisibility(nsIContentPermissionRequestCallback* aCallback) |
537 | 0 | { |
538 | 0 | NS_ENSURE_ARG_POINTER(aCallback); |
539 | 0 |
|
540 | 0 | mGetCallback = aCallback; |
541 | 0 | mWaitGettingResult = true; |
542 | 0 | Unused << mParent->SendGetVisibility(); |
543 | 0 | return NS_OK; |
544 | 0 | } |
545 | | |
546 | | NS_IMETHODIMP |
547 | | nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy |
548 | | ::SetOnVisibilityChange(nsIContentPermissionRequestCallback* aCallback) |
549 | 0 | { |
550 | 0 | mOnChangeCallback = aCallback; |
551 | 0 | return NS_OK; |
552 | 0 | } |
553 | | |
554 | | NS_IMETHODIMP |
555 | | nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy |
556 | | ::GetOnVisibilityChange(nsIContentPermissionRequestCallback** aCallback) |
557 | 0 | { |
558 | 0 | NS_ENSURE_ARG_POINTER(aCallback); |
559 | 0 |
|
560 | 0 | nsCOMPtr<nsIContentPermissionRequestCallback> callback = mOnChangeCallback; |
561 | 0 | callback.forget(aCallback); |
562 | 0 | return NS_OK; |
563 | 0 | } |
564 | | |
565 | | void |
566 | | nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy |
567 | | ::NotifyVisibilityResult(const bool& aIsVisible) |
568 | 0 | { |
569 | 0 | if (mWaitGettingResult) { |
570 | 0 | MOZ_ASSERT(mGetCallback); |
571 | 0 | mWaitGettingResult = false; |
572 | 0 | mGetCallback->NotifyVisibility(aIsVisible); |
573 | 0 | return; |
574 | 0 | } |
575 | 0 |
|
576 | 0 | if (mOnChangeCallback) { |
577 | 0 | mOnChangeCallback->NotifyVisibility(aIsVisible); |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | nsContentPermissionRequestProxy::nsContentPermissionRequestProxy(ContentPermissionRequestParent* parent) |
582 | | : mParent(parent) |
583 | 0 | { |
584 | 0 | NS_ASSERTION(mParent, "null parent"); |
585 | 0 | } |
586 | | |
587 | | nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() |
588 | 0 | { |
589 | 0 | } |
590 | | |
591 | | nsresult |
592 | | nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests) |
593 | 0 | { |
594 | 0 | mPermissionRequests = requests; |
595 | 0 | mRequester = new nsContentPermissionRequesterProxy(mParent); |
596 | 0 |
|
597 | 0 | nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); |
598 | 0 | if (!prompt) { |
599 | 0 | return NS_ERROR_FAILURE; |
600 | 0 | } |
601 | 0 | |
602 | 0 | prompt->Prompt(this); |
603 | 0 | return NS_OK; |
604 | 0 | } |
605 | | |
606 | | void |
607 | | nsContentPermissionRequestProxy::OnParentDestroyed() |
608 | 0 | { |
609 | 0 | mRequester = nullptr; |
610 | 0 | mParent = nullptr; |
611 | 0 | } |
612 | | |
613 | | NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest) |
614 | | |
615 | | NS_IMETHODIMP |
616 | | nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) |
617 | 0 | { |
618 | 0 | nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); |
619 | 0 | if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(mPermissionRequests, types)) { |
620 | 0 | types.forget(aTypes); |
621 | 0 | return NS_OK; |
622 | 0 | } |
623 | 0 | return NS_ERROR_FAILURE; |
624 | 0 | } |
625 | | |
626 | | NS_IMETHODIMP |
627 | | nsContentPermissionRequestProxy::GetWindow(mozIDOMWindow * *aRequestingWindow) |
628 | 0 | { |
629 | 0 | NS_ENSURE_ARG_POINTER(aRequestingWindow); |
630 | 0 | *aRequestingWindow = nullptr; // ipc doesn't have a window |
631 | 0 | return NS_OK; |
632 | 0 | } |
633 | | |
634 | | NS_IMETHODIMP |
635 | | nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) |
636 | 0 | { |
637 | 0 | NS_ENSURE_ARG_POINTER(aRequestingPrincipal); |
638 | 0 | if (mParent == nullptr) { |
639 | 0 | return NS_ERROR_FAILURE; |
640 | 0 | } |
641 | 0 | |
642 | 0 | NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal); |
643 | 0 | return NS_OK; |
644 | 0 | } |
645 | | |
646 | | NS_IMETHODIMP |
647 | | nsContentPermissionRequestProxy::GetElement(Element** aRequestingElement) |
648 | 0 | { |
649 | 0 | NS_ENSURE_ARG_POINTER(aRequestingElement); |
650 | 0 | if (mParent == nullptr) { |
651 | 0 | return NS_ERROR_FAILURE; |
652 | 0 | } |
653 | 0 | |
654 | 0 | nsCOMPtr<Element> elem = mParent->mElement; |
655 | 0 | elem.forget(aRequestingElement); |
656 | 0 | return NS_OK; |
657 | 0 | } |
658 | | |
659 | | NS_IMETHODIMP |
660 | | nsContentPermissionRequestProxy::GetIsHandlingUserInput(bool* aIsHandlingUserInput) |
661 | 0 | { |
662 | 0 | NS_ENSURE_ARG_POINTER(aIsHandlingUserInput); |
663 | 0 | if (mParent == nullptr) { |
664 | 0 | return NS_ERROR_FAILURE; |
665 | 0 | } |
666 | 0 | *aIsHandlingUserInput = mParent->mIsHandlingUserInput; |
667 | 0 | return NS_OK; |
668 | 0 | } |
669 | | |
670 | | NS_IMETHODIMP |
671 | | nsContentPermissionRequestProxy::Cancel() |
672 | 0 | { |
673 | 0 | if (mParent == nullptr) { |
674 | 0 | return NS_ERROR_FAILURE; |
675 | 0 | } |
676 | 0 | |
677 | 0 | // Don't send out the delete message when the managing protocol (PBrowser) is |
678 | 0 | // being destroyed and PContentPermissionRequest will soon be. |
679 | 0 | if (mParent->IsBeingDestroyed()) { |
680 | 0 | return NS_ERROR_FAILURE; |
681 | 0 | } |
682 | 0 | |
683 | 0 | nsTArray<PermissionChoice> emptyChoices; |
684 | 0 |
|
685 | 0 | Unused << mParent->SendNotifyResult(false, emptyChoices); |
686 | 0 | mParent = nullptr; |
687 | 0 | return NS_OK; |
688 | 0 | } |
689 | | |
690 | | NS_IMETHODIMP |
691 | | nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices) |
692 | 0 | { |
693 | 0 | if (mParent == nullptr) { |
694 | 0 | return NS_ERROR_FAILURE; |
695 | 0 | } |
696 | 0 | |
697 | 0 | // Don't send out the delete message when the managing protocol (PBrowser) is |
698 | 0 | // being destroyed and PContentPermissionRequest will soon be. |
699 | 0 | if (mParent->IsBeingDestroyed()) { |
700 | 0 | return NS_ERROR_FAILURE; |
701 | 0 | } |
702 | 0 | |
703 | 0 | nsTArray<PermissionChoice> choices; |
704 | 0 | if (aChoices.isNullOrUndefined()) { |
705 | 0 | // No choice is specified. |
706 | 0 | } else if (aChoices.isObject()) { |
707 | 0 | // Iterate through all permission types. |
708 | 0 | for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) { |
709 | 0 | nsCString type = mPermissionRequests[i].type(); |
710 | 0 |
|
711 | 0 | JS::Rooted<JSObject*> obj(RootingCx(), &aChoices.toObject()); |
712 | 0 | obj = CheckedUnwrap(obj); |
713 | 0 | if (!obj) { |
714 | 0 | return NS_ERROR_FAILURE; |
715 | 0 | } |
716 | 0 | |
717 | 0 | AutoJSAPI jsapi; |
718 | 0 | jsapi.Init(); |
719 | 0 |
|
720 | 0 | JSContext* cx = jsapi.cx(); |
721 | 0 | JSAutoRealm ar(cx, obj); |
722 | 0 |
|
723 | 0 | JS::Rooted<JS::Value> val(cx); |
724 | 0 |
|
725 | 0 | if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) || |
726 | 0 | !val.isString()) { |
727 | 0 | // no setting for the permission type, clear exception and skip it |
728 | 0 | jsapi.ClearException(); |
729 | 0 | } else { |
730 | 0 | nsAutoJSString choice; |
731 | 0 | if (!choice.init(cx, val)) { |
732 | 0 | jsapi.ClearException(); |
733 | 0 | return NS_ERROR_FAILURE; |
734 | 0 | } |
735 | 0 | choices.AppendElement(PermissionChoice(type, choice)); |
736 | 0 | } |
737 | 0 | } |
738 | 0 | } else { |
739 | 0 | MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object"); |
740 | 0 | return NS_ERROR_FAILURE; |
741 | 0 | } |
742 | 0 |
|
743 | 0 | Unused << mParent->SendNotifyResult(true, choices); |
744 | 0 | mParent = nullptr; |
745 | 0 | return NS_OK; |
746 | 0 | } |
747 | | |
748 | | void |
749 | | nsContentPermissionRequestProxy::NotifyVisibility(const bool& aIsVisible) |
750 | 0 | { |
751 | 0 | MOZ_ASSERT(mRequester); |
752 | 0 |
|
753 | 0 | mRequester->NotifyVisibilityResult(aIsVisible); |
754 | 0 | } |
755 | | |
756 | | NS_IMETHODIMP |
757 | | nsContentPermissionRequestProxy::GetRequester(nsIContentPermissionRequester** aRequester) |
758 | 0 | { |
759 | 0 | NS_ENSURE_ARG_POINTER(aRequester); |
760 | 0 |
|
761 | 0 | RefPtr<nsContentPermissionRequesterProxy> requester = mRequester; |
762 | 0 | requester.forget(aRequester); |
763 | 0 | return NS_OK; |
764 | 0 | } |
765 | | |
766 | | // RemotePermissionRequest |
767 | | |
768 | | NS_IMPL_ISUPPORTS(RemotePermissionRequest, nsIContentPermissionRequestCallback); |
769 | | |
770 | | RemotePermissionRequest::RemotePermissionRequest( |
771 | | nsIContentPermissionRequest* aRequest, |
772 | | nsPIDOMWindowInner* aWindow) |
773 | | : mRequest(aRequest) |
774 | | , mWindow(aWindow) |
775 | | , mIPCOpen(false) |
776 | | , mDestroyed(false) |
777 | 0 | { |
778 | 0 | mListener = new VisibilityChangeListener(mWindow); |
779 | 0 | mListener->SetCallback(this); |
780 | 0 | } |
781 | | |
782 | | RemotePermissionRequest::~RemotePermissionRequest() |
783 | 0 | { |
784 | 0 | MOZ_ASSERT(!mIPCOpen, "Protocol must not be open when RemotePermissionRequest is destroyed."); |
785 | 0 | } |
786 | | |
787 | | void |
788 | | RemotePermissionRequest::DoCancel() |
789 | 0 | { |
790 | 0 | NS_ASSERTION(mRequest, "We need a request"); |
791 | 0 | mRequest->Cancel(); |
792 | 0 | } |
793 | | |
794 | | void |
795 | | RemotePermissionRequest::DoAllow(JS::HandleValue aChoices) |
796 | 0 | { |
797 | 0 | NS_ASSERTION(mRequest, "We need a request"); |
798 | 0 | mRequest->Allow(aChoices); |
799 | 0 | } |
800 | | |
801 | | // PContentPermissionRequestChild |
802 | | mozilla::ipc::IPCResult |
803 | | RemotePermissionRequest::RecvNotifyResult(const bool& aAllow, |
804 | | InfallibleTArray<PermissionChoice>&& aChoices) |
805 | 0 | { |
806 | 0 | Destroy(); |
807 | 0 |
|
808 | 0 | if (aAllow && mWindow->IsCurrentInnerWindow()) { |
809 | 0 | // Use 'undefined' if no choice is provided. |
810 | 0 | if (aChoices.IsEmpty()) { |
811 | 0 | DoAllow(JS::UndefinedHandleValue); |
812 | 0 | return IPC_OK(); |
813 | 0 | } |
814 | 0 |
|
815 | 0 | // Convert choices to a JS val if any. |
816 | 0 | // {"type1": "choice1", "type2": "choiceA"} |
817 | 0 | AutoJSAPI jsapi; |
818 | 0 | if (NS_WARN_IF(!jsapi.Init(mWindow))) { |
819 | 0 | return IPC_OK(); // This is not an IPC error. |
820 | 0 | } |
821 | 0 |
|
822 | 0 | JSContext* cx = jsapi.cx(); |
823 | 0 | JS::Rooted<JSObject*> obj(cx); |
824 | 0 | obj = JS_NewPlainObject(cx); |
825 | 0 | for (uint32_t i = 0; i < aChoices.Length(); ++i) { |
826 | 0 | const nsString& choice = aChoices[i].choice(); |
827 | 0 | const nsCString& type = aChoices[i].type(); |
828 | 0 | JS::Rooted<JSString*> jChoice(cx, JS_NewUCStringCopyN(cx, choice.get(), choice.Length())); |
829 | 0 | JS::Rooted<JS::Value> vChoice(cx, StringValue(jChoice)); |
830 | 0 | if (!JS_SetProperty(cx, obj, type.get(), vChoice)) { |
831 | 0 | return IPC_FAIL_NO_REASON(this); |
832 | 0 | } |
833 | 0 | } |
834 | 0 | JS::RootedValue val(cx, JS::ObjectValue(*obj)); |
835 | 0 | DoAllow(val); |
836 | 0 | } else { |
837 | 0 | DoCancel(); |
838 | 0 | } |
839 | 0 | return IPC_OK(); |
840 | 0 | } |
841 | | |
842 | | mozilla::ipc::IPCResult |
843 | | RemotePermissionRequest::RecvGetVisibility() |
844 | 0 | { |
845 | 0 | nsCOMPtr<nsIDocShell> docshell = mWindow->GetDocShell(); |
846 | 0 | if (!docshell) { |
847 | 0 | return IPC_FAIL_NO_REASON(this); |
848 | 0 | } |
849 | 0 |
|
850 | 0 | bool isActive = false; |
851 | 0 | docshell->GetIsActive(&isActive); |
852 | 0 | Unused << SendNotifyVisibility(isActive); |
853 | 0 | return IPC_OK(); |
854 | 0 | } |
855 | | |
856 | | void |
857 | | RemotePermissionRequest::Destroy() |
858 | 0 | { |
859 | 0 | if (!IPCOpen()) { |
860 | 0 | return; |
861 | 0 | } |
862 | 0 | Unused << this->SendDestroy(); |
863 | 0 | mListener->RemoveListener(); |
864 | 0 | mListener = nullptr; |
865 | 0 | mDestroyed = true; |
866 | 0 | } |
867 | | |
868 | | NS_IMETHODIMP |
869 | | RemotePermissionRequest::NotifyVisibility(bool isVisible) |
870 | 0 | { |
871 | 0 | if (!IPCOpen()) { |
872 | 0 | return NS_OK; |
873 | 0 | } |
874 | 0 | |
875 | 0 | Unused << SendNotifyVisibility(isVisible); |
876 | 0 | return NS_OK; |
877 | 0 | } |