1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/nsContentPermissionHelper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,358 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef MOZ_WIDGET_GONK 1.9 +#include "GonkPermission.h" 1.10 +#include "mozilla/dom/ContentParent.h" 1.11 +#endif // MOZ_WIDGET_GONK 1.12 +#include "nsCOMPtr.h" 1.13 +#include "nsIDOMElement.h" 1.14 +#include "nsIPrincipal.h" 1.15 +#include "mozilla/dom/Element.h" 1.16 +#include "mozilla/dom/PContentPermission.h" 1.17 +#include "mozilla/dom/PermissionMessageUtils.h" 1.18 +#include "mozilla/dom/PContentPermissionRequestParent.h" 1.19 +#include "mozilla/dom/TabParent.h" 1.20 +#include "mozilla/unused.h" 1.21 +#include "nsComponentManagerUtils.h" 1.22 +#include "nsArrayUtils.h" 1.23 +#include "nsIMutableArray.h" 1.24 +#include "nsContentPermissionHelper.h" 1.25 +#include "nsCxPusher.h" 1.26 +#include "nsJSUtils.h" 1.27 +#include "nsISupportsPrimitives.h" 1.28 + 1.29 +using mozilla::unused; // <snicker> 1.30 +using namespace mozilla::dom; 1.31 +using namespace mozilla; 1.32 + 1.33 +namespace mozilla { 1.34 +namespace dom { 1.35 + 1.36 +class ContentPermissionRequestParent : public PContentPermissionRequestParent 1.37 +{ 1.38 + public: 1.39 + ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, 1.40 + Element* element, 1.41 + const IPC::Principal& principal); 1.42 + virtual ~ContentPermissionRequestParent(); 1.43 + 1.44 + bool IsBeingDestroyed(); 1.45 + 1.46 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.47 + nsCOMPtr<Element> mElement; 1.48 + nsRefPtr<nsContentPermissionRequestProxy> mProxy; 1.49 + nsTArray<PermissionRequest> mRequests; 1.50 + 1.51 + private: 1.52 + virtual bool Recvprompt(); 1.53 + virtual void ActorDestroy(ActorDestroyReason why); 1.54 +}; 1.55 + 1.56 +ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, 1.57 + Element* aElement, 1.58 + const IPC::Principal& aPrincipal) 1.59 +{ 1.60 + MOZ_COUNT_CTOR(ContentPermissionRequestParent); 1.61 + 1.62 + mPrincipal = aPrincipal; 1.63 + mElement = aElement; 1.64 + mRequests = aRequests; 1.65 +} 1.66 + 1.67 +ContentPermissionRequestParent::~ContentPermissionRequestParent() 1.68 +{ 1.69 + MOZ_COUNT_DTOR(ContentPermissionRequestParent); 1.70 +} 1.71 + 1.72 +bool 1.73 +ContentPermissionRequestParent::Recvprompt() 1.74 +{ 1.75 + mProxy = new nsContentPermissionRequestProxy(); 1.76 + NS_ASSERTION(mProxy, "Alloc of request proxy failed"); 1.77 + if (NS_FAILED(mProxy->Init(mRequests, this))) { 1.78 + mProxy->Cancel(); 1.79 + } 1.80 + return true; 1.81 +} 1.82 + 1.83 +void 1.84 +ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) 1.85 +{ 1.86 + if (mProxy) { 1.87 + mProxy->OnParentDestroyed(); 1.88 + } 1.89 +} 1.90 + 1.91 +bool 1.92 +ContentPermissionRequestParent::IsBeingDestroyed() 1.93 +{ 1.94 + // When TabParent::Destroy() is called, we are being destroyed. It's unsafe 1.95 + // to send out any message now. 1.96 + TabParent* tabParent = static_cast<TabParent*>(Manager()); 1.97 + return tabParent->IsDestroyed(); 1.98 +} 1.99 + 1.100 +NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType) 1.101 + 1.102 +ContentPermissionType::ContentPermissionType(const nsACString& aType, 1.103 + const nsACString& aAccess, 1.104 + const nsTArray<nsString>& aOptions) 1.105 +{ 1.106 + mType = aType; 1.107 + mAccess = aAccess; 1.108 + mOptions = aOptions; 1.109 +} 1.110 + 1.111 +ContentPermissionType::~ContentPermissionType() 1.112 +{ 1.113 +} 1.114 + 1.115 +NS_IMETHODIMP 1.116 +ContentPermissionType::GetType(nsACString& aType) 1.117 +{ 1.118 + aType = mType; 1.119 + return NS_OK; 1.120 +} 1.121 + 1.122 +NS_IMETHODIMP 1.123 +ContentPermissionType::GetAccess(nsACString& aAccess) 1.124 +{ 1.125 + aAccess = mAccess; 1.126 + return NS_OK; 1.127 +} 1.128 + 1.129 +NS_IMETHODIMP 1.130 +ContentPermissionType::GetOptions(nsIArray** aOptions) 1.131 +{ 1.132 + NS_ENSURE_ARG_POINTER(aOptions); 1.133 + 1.134 + *aOptions = nullptr; 1.135 + 1.136 + nsresult rv; 1.137 + nsCOMPtr<nsIMutableArray> options = 1.138 + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); 1.139 + NS_ENSURE_SUCCESS(rv, rv); 1.140 + 1.141 + // copy options into JS array 1.142 + for (uint32_t i = 0; i < mOptions.Length(); ++i) { 1.143 + nsCOMPtr<nsISupportsString> isupportsString = 1.144 + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); 1.145 + NS_ENSURE_SUCCESS(rv, rv); 1.146 + 1.147 + rv = isupportsString->SetData(mOptions[i]); 1.148 + NS_ENSURE_SUCCESS(rv, rv); 1.149 + 1.150 + rv = options->AppendElement(isupportsString, false); 1.151 + NS_ENSURE_SUCCESS(rv, rv); 1.152 + } 1.153 + 1.154 + NS_ADDREF(*aOptions = options); 1.155 + return NS_OK; 1.156 +} 1.157 + 1.158 +uint32_t 1.159 +ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray, 1.160 + nsIMutableArray* aDesArray) 1.161 +{ 1.162 + uint32_t len = aSrcArray.Length(); 1.163 + for (uint32_t i = 0; i < len; i++) { 1.164 + nsRefPtr<ContentPermissionType> cpt = 1.165 + new ContentPermissionType(aSrcArray[i].type(), 1.166 + aSrcArray[i].access(), 1.167 + aSrcArray[i].options()); 1.168 + aDesArray->AppendElement(cpt, false); 1.169 + } 1.170 + return len; 1.171 +} 1.172 + 1.173 +nsresult 1.174 +CreatePermissionArray(const nsACString& aType, 1.175 + const nsACString& aAccess, 1.176 + const nsTArray<nsString>& aOptions, 1.177 + nsIArray** aTypesArray) 1.178 +{ 1.179 + nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); 1.180 + nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType, 1.181 + aAccess, 1.182 + aOptions); 1.183 + types->AppendElement(permType, false); 1.184 + types.forget(aTypesArray); 1.185 + 1.186 + return NS_OK; 1.187 +} 1.188 + 1.189 +PContentPermissionRequestParent* 1.190 +CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests, 1.191 + Element* element, 1.192 + const IPC::Principal& principal) 1.193 +{ 1.194 + return new ContentPermissionRequestParent(aRequests, element, principal); 1.195 +} 1.196 + 1.197 +} // namespace dom 1.198 +} // namespace mozilla 1.199 + 1.200 +nsContentPermissionRequestProxy::nsContentPermissionRequestProxy() 1.201 +{ 1.202 + MOZ_COUNT_CTOR(nsContentPermissionRequestProxy); 1.203 +} 1.204 + 1.205 +nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() 1.206 +{ 1.207 + MOZ_COUNT_DTOR(nsContentPermissionRequestProxy); 1.208 +} 1.209 + 1.210 +nsresult 1.211 +nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests, 1.212 + ContentPermissionRequestParent* parent) 1.213 +{ 1.214 + NS_ASSERTION(parent, "null parent"); 1.215 + mParent = parent; 1.216 + mPermissionRequests = requests; 1.217 + 1.218 + nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); 1.219 + if (!prompt) { 1.220 + return NS_ERROR_FAILURE; 1.221 + } 1.222 + 1.223 + prompt->Prompt(this); 1.224 + return NS_OK; 1.225 +} 1.226 + 1.227 +void 1.228 +nsContentPermissionRequestProxy::OnParentDestroyed() 1.229 +{ 1.230 + mParent = nullptr; 1.231 +} 1.232 + 1.233 +NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest) 1.234 + 1.235 +NS_IMETHODIMP 1.236 +nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) 1.237 +{ 1.238 + nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); 1.239 + if (ConvertPermissionRequestToArray(mPermissionRequests, types)) { 1.240 + types.forget(aTypes); 1.241 + return NS_OK; 1.242 + } 1.243 + return NS_ERROR_FAILURE; 1.244 +} 1.245 + 1.246 +NS_IMETHODIMP 1.247 +nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow * *aRequestingWindow) 1.248 +{ 1.249 + NS_ENSURE_ARG_POINTER(aRequestingWindow); 1.250 + *aRequestingWindow = nullptr; // ipc doesn't have a window 1.251 + return NS_OK; 1.252 +} 1.253 + 1.254 +NS_IMETHODIMP 1.255 +nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) 1.256 +{ 1.257 + NS_ENSURE_ARG_POINTER(aRequestingPrincipal); 1.258 + if (mParent == nullptr) { 1.259 + return NS_ERROR_FAILURE; 1.260 + } 1.261 + 1.262 + NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal); 1.263 + return NS_OK; 1.264 +} 1.265 + 1.266 +NS_IMETHODIMP 1.267 +nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement) 1.268 +{ 1.269 + NS_ENSURE_ARG_POINTER(aRequestingElement); 1.270 + if (mParent == nullptr) { 1.271 + return NS_ERROR_FAILURE; 1.272 + } 1.273 + 1.274 + nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mParent->mElement); 1.275 + elem.forget(aRequestingElement); 1.276 + return NS_OK; 1.277 +} 1.278 + 1.279 +NS_IMETHODIMP 1.280 +nsContentPermissionRequestProxy::Cancel() 1.281 +{ 1.282 + if (mParent == nullptr) { 1.283 + return NS_ERROR_FAILURE; 1.284 + } 1.285 + 1.286 + // Don't send out the delete message when the managing protocol (PBrowser) is 1.287 + // being destroyed and PContentPermissionRequest will soon be. 1.288 + if (mParent->IsBeingDestroyed()) { 1.289 + return NS_ERROR_FAILURE; 1.290 + } 1.291 + 1.292 + nsTArray<PermissionChoice> emptyChoices; 1.293 + 1.294 + unused << ContentPermissionRequestParent::Send__delete__(mParent, false, emptyChoices); 1.295 + mParent = nullptr; 1.296 + return NS_OK; 1.297 +} 1.298 + 1.299 +NS_IMETHODIMP 1.300 +nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices) 1.301 +{ 1.302 + if (mParent == nullptr) { 1.303 + return NS_ERROR_FAILURE; 1.304 + } 1.305 + 1.306 + // Don't send out the delete message when the managing protocol (PBrowser) is 1.307 + // being destroyed and PContentPermissionRequest will soon be. 1.308 + if (mParent->IsBeingDestroyed()) { 1.309 + return NS_ERROR_FAILURE; 1.310 + } 1.311 + 1.312 +#ifdef MOZ_WIDGET_GONK 1.313 + uint32_t len = mPermissionRequests.Length(); 1.314 + for (uint32_t i = 0; i < len; i++) { 1.315 + if (mPermissionRequests[i].type().Equals("audio-capture")) { 1.316 + GonkPermissionService::GetInstance()->addGrantInfo( 1.317 + "android.permission.RECORD_AUDIO", 1.318 + static_cast<TabParent*>(mParent->Manager())->Manager()->Pid()); 1.319 + } 1.320 + if (mPermissionRequests[i].type().Equals("video-capture")) { 1.321 + GonkPermissionService::GetInstance()->addGrantInfo( 1.322 + "android.permission.CAMERA", 1.323 + static_cast<TabParent*>(mParent->Manager())->Manager()->Pid()); 1.324 + } 1.325 + } 1.326 +#endif 1.327 + 1.328 + nsTArray<PermissionChoice> choices; 1.329 + if (aChoices.isNullOrUndefined()) { 1.330 + // No choice is specified. 1.331 + } else if (aChoices.isObject()) { 1.332 + // Iterate through all permission types. 1.333 + for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) { 1.334 + nsCString type = mPermissionRequests[i].type(); 1.335 + 1.336 + mozilla::AutoSafeJSContext cx; 1.337 + JS::Rooted<JSObject*> obj(cx, &aChoices.toObject()); 1.338 + JSAutoCompartment ac(cx, obj); 1.339 + 1.340 + JS::Rooted<JS::Value> val(cx); 1.341 + 1.342 + if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) || 1.343 + !val.isString()) { 1.344 + // no setting for the permission type, skip it 1.345 + } else { 1.346 + nsDependentJSString choice; 1.347 + if (!choice.init(cx, val)) { 1.348 + return NS_ERROR_FAILURE; 1.349 + } 1.350 + choices.AppendElement(PermissionChoice(type, choice)); 1.351 + } 1.352 + } 1.353 + } else { 1.354 + MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object"); 1.355 + return NS_ERROR_FAILURE; 1.356 + } 1.357 + 1.358 + unused << ContentPermissionRequestParent::Send__delete__(mParent, true, choices); 1.359 + mParent = nullptr; 1.360 + return NS_OK; 1.361 +}