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 #ifndef nsContentPermissionHelper_h
8 #define nsContentPermissionHelper_h
9 
10 #include "nsIContentPermissionPrompt.h"
11 #include "nsTArray.h"
12 #include "nsIMutableArray.h"
13 #include "mozilla/dom/PContentPermissionRequestChild.h"
14 #include "mozilla/dom/ipc/IdType.h"
15 #include "mozilla/PermissionDelegateHandler.h"
16 
17 // Microsoft's API Name hackery sucks
18 // XXXbz Doing this in a header is a gigantic footgun. See
19 // https://bugzilla.mozilla.org/show_bug.cgi?id=932421#c3 for why.
20 #undef LoadImage
21 
22 class nsPIDOMWindowInner;
23 class nsContentPermissionRequestProxy;
24 
25 // Forward declare IPC::Principal here which is defined in
26 // PermissionMessageUtils.h. Include this file will transitively includes
27 // "windows.h" and it defines
28 //   #define CreateEvent CreateEventW
29 //   #define LoadImage LoadImageW
30 // That will mess up windows build.
31 namespace IPC {
32 class Principal;
33 }  // namespace IPC
34 
35 namespace mozilla {
36 namespace dom {
37 
38 class Element;
39 class PermissionRequest;
40 class ContentPermissionRequestParent;
41 class PContentPermissionRequestParent;
42 
43 class ContentPermissionType : public nsIContentPermissionType {
44  public:
45   NS_DECL_ISUPPORTS
46   NS_DECL_NSICONTENTPERMISSIONTYPE
47 
48   ContentPermissionType(const nsACString& aType,
49                         const nsTArray<nsString>& aOptions);
50 
51  protected:
52   virtual ~ContentPermissionType();
53 
54   nsCString mType;
55   nsTArray<nsString> mOptions;
56 };
57 
58 class nsContentPermissionUtils {
59  public:
60   static uint32_t ConvertPermissionRequestToArray(
61       nsTArray<PermissionRequest>& aSrcArray, nsIMutableArray* aDesArray);
62 
63   // Converts blindly, that is, strings are not matched against any list.
64   //
65   // @param aSrcArray needs to contain elements of type
66   // `nsIContentPermissionType`.
67   static void ConvertArrayToPermissionRequest(
68       nsIArray* aSrcArray, nsTArray<PermissionRequest>& aDesArray);
69 
70   static nsresult CreatePermissionArray(const nsACString& aType,
71                                         const nsTArray<nsString>& aOptions,
72                                         nsIArray** aTypesArray);
73 
74   // @param aIsRequestDelegatedToUnsafeThirdParty see
75   // ContentPermissionRequestParent.
76   static PContentPermissionRequestParent* CreateContentPermissionRequestParent(
77       const nsTArray<PermissionRequest>& aRequests, Element* aElement,
78       nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
79       const bool aHasValidTransientUserGestureActivation,
80       const bool aIsRequestDelegatedToUnsafeThirdParty, const TabId& aTabId);
81 
82   static nsresult AskPermission(nsIContentPermissionRequest* aRequest,
83                                 nsPIDOMWindowInner* aWindow);
84 
85   static nsTArray<PContentPermissionRequestParent*>
86   GetContentPermissionRequestParentById(const TabId& aTabId);
87 
88   static void NotifyRemoveContentPermissionRequestParent(
89       PContentPermissionRequestParent* aParent);
90 
91   static nsTArray<PContentPermissionRequestChild*>
92   GetContentPermissionRequestChildById(const TabId& aTabId);
93 
94   static void NotifyRemoveContentPermissionRequestChild(
95       PContentPermissionRequestChild* aChild);
96 };
97 
98 nsresult TranslateChoices(
99     JS::HandleValue aChoices,
100     const nsTArray<PermissionRequest>& aPermissionRequests,
101     nsTArray<PermissionChoice>& aTranslatedChoices);
102 
103 class ContentPermissionRequestBase : public nsIContentPermissionRequest {
104  public:
105   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
106   NS_DECL_CYCLE_COLLECTION_CLASS(ContentPermissionRequestBase)
107 
108   NS_IMETHOD GetTypes(nsIArray** aTypes) override;
109   NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal) override;
110   NS_IMETHOD GetDelegatePrincipal(const nsACString& aType,
111                                   nsIPrincipal** aPrincipal) override;
112   NS_IMETHOD GetTopLevelPrincipal(nsIPrincipal** aTopLevelPrincipal) override;
113   NS_IMETHOD GetWindow(mozIDOMWindow** aWindow) override;
114   NS_IMETHOD GetElement(mozilla::dom::Element** aElement) override;
115   NS_IMETHOD GetHasValidTransientUserGestureActivation(
116       bool* aHasValidTransientUserGestureActivation) override;
117   NS_IMETHOD GetIsRequestDelegatedToUnsafeThirdParty(
118       bool* aIsRequestDelegatedToUnsafeThirdParty) override;
119   // Overrides for Allow() and Cancel() aren't provided by this class.
120   // That is the responsibility of the subclasses.
121 
122   enum class PromptResult {
123     Granted,
124     Denied,
125     Pending,
126   };
127   nsresult ShowPrompt(PromptResult& aResult);
128 
129   PromptResult CheckPromptPrefs() const;
130 
131   // Check if the permission has an opportunity to request.
132   bool CheckPermissionDelegate() const;
133 
134   enum class DelayedTaskType {
135     Allow,
136     Deny,
137     Request,
138   };
139   void RequestDelayedTask(nsIEventTarget* aTarget, DelayedTaskType aType);
140 
141  protected:
142   // @param aPrefName see `mPrefName`.
143   // @param aType see `mType`.
144   ContentPermissionRequestBase(nsIPrincipal* aPrincipal,
145                                nsPIDOMWindowInner* aWindow,
146                                const nsACString& aPrefName,
147                                const nsACString& aType);
148   virtual ~ContentPermissionRequestBase() = default;
149 
150   nsCOMPtr<nsIPrincipal> mPrincipal;
151   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
152   nsCOMPtr<nsPIDOMWindowInner> mWindow;
153   RefPtr<PermissionDelegateHandler> mPermissionHandler;
154 
155   // The prefix of a pref which allows tests to bypass showing the prompt.
156   // Tests will have to set both of
157   // ${mPrefName}.prompt.testing and
158   // ${mPrefName}.prompt.testing.allow
159   // to either true or false. If no such testing is required, mPrefName may be
160   // empty.
161   const nsCString mPrefName;
162 
163   // The type of the request, such as "autoplay-media-audible".
164   const nsCString mType;
165 
166   bool mHasValidTransientUserGestureActivation;
167 
168   // See nsIPermissionDelegateHandler.maybeUnsafePermissionDelegate`.
169   bool mIsRequestDelegatedToUnsafeThirdParty;
170 };
171 
172 }  // namespace dom
173 }  // namespace mozilla
174 
175 using mozilla::dom::ContentPermissionRequestParent;
176 
177 class nsContentPermissionRequestProxy : public nsIContentPermissionRequest {
178  public:
179   NS_DECL_ISUPPORTS
180   NS_DECL_NSICONTENTPERMISSIONREQUEST
181 
182   explicit nsContentPermissionRequestProxy(
183       ContentPermissionRequestParent* parent);
184 
185   nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests);
186 
187   void OnParentDestroyed();
188 
189  private:
190   virtual ~nsContentPermissionRequestProxy();
191 
192   // Non-owning pointer to the ContentPermissionRequestParent object which owns
193   // this proxy.
194   ContentPermissionRequestParent* mParent;
195   nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
196 };
197 
198 /**
199  * RemotePermissionRequest will send a prompt ipdl request to the chrome process
200  * (https://wiki.mozilla.org/Security/Sandbox/Process_model#Chrome_process_.28Parent.29).
201  */
202 class RemotePermissionRequest final
203     : public mozilla::dom::PContentPermissionRequestChild {
204  public:
205   NS_INLINE_DECL_REFCOUNTING(RemotePermissionRequest)
206 
207   RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
208                           nsPIDOMWindowInner* aWindow);
209 
210   // It will be called when prompt dismissed.  MOZ_CAN_RUN_SCRIPT_BOUNDARY
211   // because we don't have MOZ_CAN_RUN_SCRIPT bits in IPC code yet.
212   MOZ_CAN_RUN_SCRIPT_BOUNDARY
213   mozilla::ipc::IPCResult RecvNotifyResult(
214       const bool& aAllow, nsTArray<PermissionChoice>&& aChoices);
215 
IPDLAddRef()216   void IPDLAddRef() {
217     mIPCOpen = true;
218     AddRef();
219   }
220 
IPDLRelease()221   void IPDLRelease() {
222     mIPCOpen = false;
223     Release();
224   }
225 
226   void Destroy();
227 
IPCOpen()228   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
229 
230  private:
231   virtual ~RemotePermissionRequest();
232 
233   MOZ_CAN_RUN_SCRIPT
234   void DoAllow(JS::HandleValue aChoices);
235   MOZ_CAN_RUN_SCRIPT
236   void DoCancel();
237 
238   nsCOMPtr<nsIContentPermissionRequest> mRequest;
239   nsCOMPtr<nsPIDOMWindowInner> mWindow;
240   bool mIPCOpen;
241   bool mDestroyed;
242 };
243 
244 #endif  // nsContentPermissionHelper_h
245