1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "GonkPermission.h"
7 #include "mozilla/dom/ContentParent.h"
8 #endif // MOZ_WIDGET_GONK
10 #include "nsIDOMElement.h"
11 #include "nsIPrincipal.h"
12 #include "mozilla/dom/Element.h"
13 #include "mozilla/dom/PContentPermission.h"
14 #include "mozilla/dom/PermissionMessageUtils.h"
15 #include "mozilla/dom/PContentPermissionRequestParent.h"
16 #include "mozilla/dom/ScriptSettings.h"
17 #include "mozilla/dom/TabChild.h"
18 #include "mozilla/dom/TabParent.h"
19 #include "mozilla/unused.h"
20 #include "nsComponentManagerUtils.h"
21 #include "nsArrayUtils.h"
22 #include "nsIMutableArray.h"
23 #include "nsContentPermissionHelper.h"
24 #include "nsJSUtils.h"
25 #include "nsISupportsPrimitives.h"
26 #include "nsServiceManagerUtils.h"
28 using mozilla::unused
; // <snicker>
29 using namespace mozilla::dom
;
30 using namespace mozilla
;
35 class ContentPermissionRequestParent
: public PContentPermissionRequestParent
38 ContentPermissionRequestParent(const nsTArray
<PermissionRequest
>& aRequests
,
40 const IPC::Principal
& principal
);
41 virtual ~ContentPermissionRequestParent();
43 bool IsBeingDestroyed();
45 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
46 nsCOMPtr
<Element
> mElement
;
47 nsRefPtr
<nsContentPermissionRequestProxy
> mProxy
;
48 nsTArray
<PermissionRequest
> mRequests
;
51 virtual bool Recvprompt();
52 virtual void ActorDestroy(ActorDestroyReason why
);
55 ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray
<PermissionRequest
>& aRequests
,
57 const IPC::Principal
& aPrincipal
)
59 MOZ_COUNT_CTOR(ContentPermissionRequestParent
);
61 mPrincipal
= aPrincipal
;
63 mRequests
= aRequests
;
66 ContentPermissionRequestParent::~ContentPermissionRequestParent()
68 MOZ_COUNT_DTOR(ContentPermissionRequestParent
);
72 ContentPermissionRequestParent::Recvprompt()
74 mProxy
= new nsContentPermissionRequestProxy();
75 NS_ASSERTION(mProxy
, "Alloc of request proxy failed");
76 if (NS_FAILED(mProxy
->Init(mRequests
, this))) {
83 ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why
)
86 mProxy
->OnParentDestroyed();
91 ContentPermissionRequestParent::IsBeingDestroyed()
93 // When TabParent::Destroy() is called, we are being destroyed. It's unsafe
94 // to send out any message now.
95 TabParent
* tabParent
= static_cast<TabParent
*>(Manager());
96 return tabParent
->IsDestroyed();
99 NS_IMPL_ISUPPORTS(ContentPermissionType
, nsIContentPermissionType
)
101 ContentPermissionType::ContentPermissionType(const nsACString
& aType
,
102 const nsACString
& aAccess
,
103 const nsTArray
<nsString
>& aOptions
)
110 ContentPermissionType::~ContentPermissionType()
115 ContentPermissionType::GetType(nsACString
& aType
)
122 ContentPermissionType::GetAccess(nsACString
& aAccess
)
129 ContentPermissionType::GetOptions(nsIArray
** aOptions
)
131 NS_ENSURE_ARG_POINTER(aOptions
);
136 nsCOMPtr
<nsIMutableArray
> options
=
137 do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
138 NS_ENSURE_SUCCESS(rv
, rv
);
140 // copy options into JS array
141 for (uint32_t i
= 0; i
< mOptions
.Length(); ++i
) {
142 nsCOMPtr
<nsISupportsString
> isupportsString
=
143 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
144 NS_ENSURE_SUCCESS(rv
, rv
);
146 rv
= isupportsString
->SetData(mOptions
[i
]);
147 NS_ENSURE_SUCCESS(rv
, rv
);
149 rv
= options
->AppendElement(isupportsString
, false);
150 NS_ENSURE_SUCCESS(rv
, rv
);
153 NS_ADDREF(*aOptions
= options
);
157 // nsContentPermissionUtils
159 /* static */ uint32_t
160 nsContentPermissionUtils::ConvertPermissionRequestToArray(nsTArray
<PermissionRequest
>& aSrcArray
,
161 nsIMutableArray
* aDesArray
)
163 uint32_t len
= aSrcArray
.Length();
164 for (uint32_t i
= 0; i
< len
; i
++) {
165 nsRefPtr
<ContentPermissionType
> cpt
=
166 new ContentPermissionType(aSrcArray
[i
].type(),
167 aSrcArray
[i
].access(),
168 aSrcArray
[i
].options());
169 aDesArray
->AppendElement(cpt
, false);
174 /* static */ uint32_t
175 nsContentPermissionUtils::ConvertArrayToPermissionRequest(nsIArray
* aSrcArray
,
176 nsTArray
<PermissionRequest
>& aDesArray
)
179 aSrcArray
->GetLength(&len
);
180 for (uint32_t i
= 0; i
< len
; i
++) {
181 nsCOMPtr
<nsIContentPermissionType
> cpt
= do_QueryElementAt(aSrcArray
, i
);
183 nsAutoCString access
;
185 cpt
->GetAccess(access
);
187 nsCOMPtr
<nsIArray
> optionArray
;
188 cpt
->GetOptions(getter_AddRefs(optionArray
));
189 uint32_t optionsLength
= 0;
191 optionArray
->GetLength(&optionsLength
);
193 nsTArray
<nsString
> options
;
194 for (uint32_t j
= 0; j
< optionsLength
; ++j
) {
195 nsCOMPtr
<nsISupportsString
> isupportsString
= do_QueryElementAt(optionArray
, j
);
196 if (isupportsString
) {
198 isupportsString
->GetData(option
);
199 options
.AppendElement(option
);
203 aDesArray
.AppendElement(PermissionRequest(type
, access
, options
));
209 /* static */ nsresult
210 nsContentPermissionUtils::CreatePermissionArray(const nsACString
& aType
,
211 const nsACString
& aAccess
,
212 const nsTArray
<nsString
>& aOptions
,
213 nsIArray
** aTypesArray
)
215 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
216 nsRefPtr
<ContentPermissionType
> permType
= new ContentPermissionType(aType
,
219 types
->AppendElement(permType
, false);
220 types
.forget(aTypesArray
);
225 /* static */ PContentPermissionRequestParent
*
226 nsContentPermissionUtils::CreateContentPermissionRequestParent(const nsTArray
<PermissionRequest
>& aRequests
,
228 const IPC::Principal
& principal
)
230 return new ContentPermissionRequestParent(aRequests
, element
, principal
);
233 /* static */ nsresult
234 nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest
* aRequest
, nsPIDOMWindow
* aWindow
)
236 MOZ_ASSERT(!aWindow
|| aWindow
->IsInnerWindow());
237 NS_ENSURE_STATE(aWindow
&& aWindow
->IsCurrentInnerWindow());
239 // for content process
240 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
242 nsRefPtr
<RemotePermissionRequest
> req
=
243 new RemotePermissionRequest(aRequest
, aWindow
);
245 MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.
247 TabChild
* child
= TabChild::GetFrom(aWindow
->GetDocShell());
248 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
250 nsCOMPtr
<nsIArray
> typeArray
;
251 nsresult rv
= aRequest
->GetTypes(getter_AddRefs(typeArray
));
252 NS_ENSURE_SUCCESS(rv
, rv
);
254 nsTArray
<PermissionRequest
> permArray
;
255 ConvertArrayToPermissionRequest(typeArray
, permArray
);
257 nsCOMPtr
<nsIPrincipal
> principal
;
258 rv
= aRequest
->GetPrincipal(getter_AddRefs(principal
));
259 NS_ENSURE_SUCCESS(rv
, rv
);
262 child
->SendPContentPermissionRequestConstructor(req
,
264 IPC::Principal(principal
));
270 // for chrome process
271 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
=
272 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
274 prompt
->Prompt(aRequest
);
280 } // namespace mozilla
282 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
284 MOZ_COUNT_CTOR(nsContentPermissionRequestProxy
);
287 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
289 MOZ_COUNT_DTOR(nsContentPermissionRequestProxy
);
293 nsContentPermissionRequestProxy::Init(const nsTArray
<PermissionRequest
>& requests
,
294 ContentPermissionRequestParent
* parent
)
296 NS_ASSERTION(parent
, "null parent");
298 mPermissionRequests
= requests
;
300 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
= do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
302 return NS_ERROR_FAILURE
;
305 prompt
->Prompt(this);
310 nsContentPermissionRequestProxy::OnParentDestroyed()
315 NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy
, nsIContentPermissionRequest
)
318 nsContentPermissionRequestProxy::GetTypes(nsIArray
** aTypes
)
320 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
321 if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(mPermissionRequests
, types
)) {
322 types
.forget(aTypes
);
325 return NS_ERROR_FAILURE
;
329 nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow
* *aRequestingWindow
)
331 NS_ENSURE_ARG_POINTER(aRequestingWindow
);
332 *aRequestingWindow
= nullptr; // ipc doesn't have a window
337 nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal
* *aRequestingPrincipal
)
339 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
340 if (mParent
== nullptr) {
341 return NS_ERROR_FAILURE
;
344 NS_ADDREF(*aRequestingPrincipal
= mParent
->mPrincipal
);
349 nsContentPermissionRequestProxy::GetElement(nsIDOMElement
* *aRequestingElement
)
351 NS_ENSURE_ARG_POINTER(aRequestingElement
);
352 if (mParent
== nullptr) {
353 return NS_ERROR_FAILURE
;
356 nsCOMPtr
<nsIDOMElement
> elem
= do_QueryInterface(mParent
->mElement
);
357 elem
.forget(aRequestingElement
);
362 nsContentPermissionRequestProxy::Cancel()
364 if (mParent
== nullptr) {
365 return NS_ERROR_FAILURE
;
368 // Don't send out the delete message when the managing protocol (PBrowser) is
369 // being destroyed and PContentPermissionRequest will soon be.
370 if (mParent
->IsBeingDestroyed()) {
371 return NS_ERROR_FAILURE
;
374 nsTArray
<PermissionChoice
> emptyChoices
;
376 unused
<< ContentPermissionRequestParent::Send__delete__(mParent
, false, emptyChoices
);
382 nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices
)
384 if (mParent
== nullptr) {
385 return NS_ERROR_FAILURE
;
388 // Don't send out the delete message when the managing protocol (PBrowser) is
389 // being destroyed and PContentPermissionRequest will soon be.
390 if (mParent
->IsBeingDestroyed()) {
391 return NS_ERROR_FAILURE
;
394 #ifdef MOZ_WIDGET_GONK
395 uint32_t len
= mPermissionRequests
.Length();
396 for (uint32_t i
= 0; i
< len
; i
++) {
397 if (mPermissionRequests
[i
].type().EqualsLiteral("audio-capture")) {
398 GonkPermissionService::GetInstance()->addGrantInfo(
399 "android.permission.RECORD_AUDIO",
400 static_cast<TabParent
*>(
401 mParent
->Manager())->Manager()->AsContentParent()->Pid());
403 if (mPermissionRequests
[i
].type().EqualsLiteral("video-capture")) {
404 GonkPermissionService::GetInstance()->addGrantInfo(
405 "android.permission.CAMERA",
406 static_cast<TabParent
*>(
407 mParent
->Manager())->Manager()->AsContentParent()->Pid());
412 nsTArray
<PermissionChoice
> choices
;
413 if (aChoices
.isNullOrUndefined()) {
414 // No choice is specified.
415 } else if (aChoices
.isObject()) {
416 // Iterate through all permission types.
417 for (uint32_t i
= 0; i
< mPermissionRequests
.Length(); ++i
) {
418 nsCString type
= mPermissionRequests
[i
].type();
420 mozilla::AutoSafeJSContext cx
;
421 JS::Rooted
<JSObject
*> obj(cx
, &aChoices
.toObject());
422 JSAutoCompartment
ac(cx
, obj
);
424 JS::Rooted
<JS::Value
> val(cx
);
426 if (!JS_GetProperty(cx
, obj
, type
.BeginReading(), &val
) ||
428 // no setting for the permission type, skip it
430 nsAutoJSString choice
;
431 if (!choice
.init(cx
, val
)) {
432 return NS_ERROR_FAILURE
;
434 choices
.AppendElement(PermissionChoice(type
, choice
));
438 MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
439 return NS_ERROR_FAILURE
;
442 unused
<< ContentPermissionRequestParent::Send__delete__(mParent
, true, choices
);
447 // RemotePermissionRequest
449 NS_IMPL_ISUPPORTS0(RemotePermissionRequest
)
451 RemotePermissionRequest::RemotePermissionRequest(
452 nsIContentPermissionRequest
* aRequest
,
453 nsPIDOMWindow
* aWindow
)
461 RemotePermissionRequest::DoCancel()
463 NS_ASSERTION(mRequest
, "We need a request");
468 RemotePermissionRequest::DoAllow(JS::HandleValue aChoices
)
470 NS_ASSERTION(mRequest
, "We need a request");
471 mRequest
->Allow(aChoices
);
474 // PContentPermissionRequestChild
476 RemotePermissionRequest::Recv__delete__(const bool& aAllow
,
477 const nsTArray
<PermissionChoice
>& aChoices
)
479 if (aAllow
&& mWindow
->IsCurrentInnerWindow()) {
480 // Use 'undefined' if no choice is provided.
481 if (aChoices
.IsEmpty()) {
482 DoAllow(JS::UndefinedHandleValue
);
486 // Convert choices to a JS val if any.
487 // {"type1": "choice1", "type2": "choiceA"}
489 if (NS_WARN_IF(!jsapi
.Init(mWindow
))) {
490 return true; // This is not an IPC error.
493 JSContext
* cx
= jsapi
.cx();
494 JS::Rooted
<JSObject
*> obj(cx
);
495 obj
= JS_NewObject(cx
, nullptr, JS::NullPtr(), JS::NullPtr());
496 for (uint32_t i
= 0; i
< aChoices
.Length(); ++i
) {
497 const nsString
& choice
= aChoices
[i
].choice();
498 const nsCString
& type
= aChoices
[i
].type();
499 JS::Rooted
<JSString
*> jChoice(cx
, JS_NewUCStringCopyN(cx
, choice
.get(), choice
.Length()));
500 JS::Rooted
<JS::Value
> vChoice(cx
, StringValue(jChoice
));
501 if (!JS_SetProperty(cx
, obj
, type
.get(), vChoice
)) {
505 JS::RootedValue
val(cx
, JS::ObjectValue(*obj
));