Line data Source code
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "PermissionRequestBase.h"
8 :
9 : #include "MainThreadUtils.h"
10 : #include "mozilla/Assertions.h"
11 : #include "mozilla/Services.h"
12 : #include "mozilla/dom/Element.h"
13 : #include "nsIDOMWindow.h"
14 : #include "nsIObserverService.h"
15 : #include "nsIPrincipal.h"
16 : #include "nsPIDOMWindow.h"
17 : #include "nsXULAppAPI.h"
18 :
19 : namespace mozilla {
20 : namespace dom {
21 : namespace indexedDB {
22 :
23 : using namespace mozilla::services;
24 :
25 : namespace {
26 :
27 : #define IDB_PREFIX "indexedDB"
28 : #define TOPIC_PREFIX IDB_PREFIX "-permissions-"
29 :
30 : const char kPermissionString[] = IDB_PREFIX;
31 :
32 : const char kPermissionPromptTopic[] = TOPIC_PREFIX "prompt";
33 :
34 : #ifdef DEBUG
35 : const char kPermissionResponseTopic[] = TOPIC_PREFIX "response";
36 : #endif
37 :
38 : #undef TOPIC_PREFIX
39 : #undef IDB_PREFIX
40 :
41 : const uint32_t kPermissionDefault = nsIPermissionManager::UNKNOWN_ACTION;
42 :
43 : void
44 0 : AssertSanity()
45 : {
46 0 : MOZ_ASSERT(XRE_IsParentProcess());
47 0 : MOZ_ASSERT(NS_IsMainThread());
48 0 : }
49 :
50 : } // namespace
51 :
52 0 : PermissionRequestBase::PermissionRequestBase(Element* aOwnerElement,
53 0 : nsIPrincipal* aPrincipal)
54 : : mOwnerElement(aOwnerElement)
55 0 : , mPrincipal(aPrincipal)
56 : {
57 0 : AssertSanity();
58 0 : MOZ_ASSERT(aOwnerElement);
59 0 : MOZ_ASSERT(aPrincipal);
60 0 : }
61 :
62 0 : PermissionRequestBase::~PermissionRequestBase()
63 : {
64 0 : AssertSanity();
65 0 : }
66 :
67 : // static
68 : nsresult
69 0 : PermissionRequestBase::GetCurrentPermission(nsIPrincipal* aPrincipal,
70 : PermissionValue* aCurrentValue)
71 : {
72 0 : AssertSanity();
73 0 : MOZ_ASSERT(aPrincipal);
74 0 : MOZ_ASSERT(aCurrentValue);
75 :
76 0 : nsCOMPtr<nsIPermissionManager> permMan = GetPermissionManager();
77 0 : if (NS_WARN_IF(!permMan)) {
78 0 : return NS_ERROR_FAILURE;
79 : }
80 :
81 : uint32_t intPermission;
82 0 : nsresult rv = permMan->TestExactPermissionFromPrincipal(
83 : aPrincipal,
84 : kPermissionString,
85 0 : &intPermission);
86 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
87 0 : return rv;
88 : }
89 :
90 : PermissionValue permission =
91 0 : PermissionValueForIntPermission(intPermission);
92 :
93 0 : MOZ_ASSERT(permission == kPermissionAllowed ||
94 : permission == kPermissionDenied ||
95 : permission == kPermissionPrompt);
96 :
97 0 : *aCurrentValue = permission;
98 0 : return NS_OK;
99 : }
100 :
101 : // static
102 : auto
103 0 : PermissionRequestBase::PermissionValueForIntPermission(uint32_t aIntPermission)
104 : -> PermissionValue
105 : {
106 0 : AssertSanity();
107 :
108 0 : switch (aIntPermission) {
109 : case kPermissionDefault:
110 0 : return kPermissionPrompt;
111 : case kPermissionAllowed:
112 0 : return kPermissionAllowed;
113 : case kPermissionDenied:
114 0 : return kPermissionDenied;
115 : default:
116 0 : MOZ_CRASH("Bad permission!");
117 : }
118 :
119 : MOZ_CRASH("Should never get here!");
120 : }
121 :
122 : nsresult
123 0 : PermissionRequestBase::PromptIfNeeded(PermissionValue* aCurrentValue)
124 : {
125 0 : AssertSanity();
126 0 : MOZ_ASSERT(aCurrentValue);
127 0 : MOZ_ASSERT(mPrincipal);
128 :
129 : // Tricky, we want to release the window and principal in all cases except
130 : // when we successfully prompt.
131 0 : nsCOMPtr<Element> element;
132 0 : mOwnerElement.swap(element);
133 :
134 0 : nsCOMPtr<nsIPrincipal> principal;
135 0 : mPrincipal.swap(principal);
136 :
137 : PermissionValue currentValue;
138 0 : nsresult rv = GetCurrentPermission(principal, ¤tValue);
139 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
140 0 : return rv;
141 : }
142 :
143 0 : MOZ_ASSERT(currentValue != kPermissionDefault);
144 :
145 0 : if (currentValue == kPermissionPrompt) {
146 0 : nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
147 0 : if (NS_WARN_IF(!obsSvc)) {
148 0 : return NS_ERROR_FAILURE;
149 : }
150 :
151 : // We're about to prompt so swap the members back.
152 0 : element.swap(mOwnerElement);
153 0 : principal.swap(mPrincipal);
154 :
155 0 : rv = obsSvc->NotifyObservers(static_cast<nsIObserver*>(this),
156 : kPermissionPromptTopic,
157 0 : nullptr);
158 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
159 : // Finally release if we failed the prompt.
160 0 : mOwnerElement = nullptr;
161 0 : mPrincipal = nullptr;
162 0 : return rv;
163 : }
164 : }
165 :
166 0 : *aCurrentValue = currentValue;
167 0 : return NS_OK;
168 : }
169 :
170 : void
171 0 : PermissionRequestBase::SetExplicitPermission(nsIPrincipal* aPrincipal,
172 : uint32_t aIntPermission)
173 : {
174 0 : AssertSanity();
175 0 : MOZ_ASSERT(aPrincipal);
176 0 : MOZ_ASSERT(aIntPermission == kPermissionAllowed ||
177 : aIntPermission == kPermissionDenied);
178 :
179 0 : nsCOMPtr<nsIPermissionManager> permMan = GetPermissionManager();
180 0 : if (NS_WARN_IF(!permMan)) {
181 0 : return;
182 : }
183 :
184 0 : nsresult rv = permMan->AddFromPrincipal(aPrincipal,
185 : kPermissionString,
186 : aIntPermission,
187 : nsIPermissionManager::EXPIRE_NEVER,
188 0 : /* aExpireTime */ 0);
189 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
190 0 : return;
191 : }
192 : }
193 :
194 0 : NS_IMPL_ISUPPORTS(PermissionRequestBase, nsIObserver, nsIInterfaceRequestor)
195 :
196 : NS_IMETHODIMP
197 0 : PermissionRequestBase::GetInterface(const nsIID& aIID,
198 : void** aResult)
199 : {
200 0 : AssertSanity();
201 :
202 0 : if (aIID.Equals(NS_GET_IID(nsIObserver))) {
203 0 : return QueryInterface(aIID, aResult);
204 : }
205 :
206 0 : if (aIID.Equals(NS_GET_IID(nsIDOMNode)) && mOwnerElement) {
207 0 : return mOwnerElement->QueryInterface(aIID, aResult);
208 : }
209 :
210 0 : *aResult = nullptr;
211 0 : return NS_ERROR_NOT_AVAILABLE;
212 : }
213 :
214 : NS_IMETHODIMP
215 0 : PermissionRequestBase::Observe(nsISupports* aSubject,
216 : const char* aTopic,
217 : const char16_t* aData)
218 : {
219 0 : AssertSanity();
220 0 : MOZ_ASSERT(!strcmp(aTopic, kPermissionResponseTopic));
221 0 : MOZ_ASSERT(mOwnerElement);
222 0 : MOZ_ASSERT(mPrincipal);
223 :
224 0 : nsCOMPtr<Element> element;
225 0 : element.swap(mOwnerElement);
226 :
227 0 : nsCOMPtr<nsIPrincipal> principal;
228 0 : mPrincipal.swap(principal);
229 :
230 : nsresult rv;
231 0 : uint32_t promptResult = nsDependentString(aData).ToInteger(&rv);
232 0 : MOZ_ALWAYS_SUCCEEDS(rv);
233 :
234 : // The UI prompt code will only return one of these three values. We have to
235 : // transform it to our values.
236 0 : MOZ_ASSERT(promptResult == kPermissionDefault ||
237 : promptResult == kPermissionAllowed ||
238 : promptResult == kPermissionDenied);
239 :
240 0 : if (promptResult != kPermissionDefault) {
241 : // Save explicitly allowed or denied permissions now.
242 0 : SetExplicitPermission(principal, promptResult);
243 : }
244 :
245 : PermissionValue permission;
246 0 : switch (promptResult) {
247 : case kPermissionDefault:
248 0 : permission = kPermissionPrompt;
249 0 : break;
250 :
251 : case kPermissionAllowed:
252 0 : permission = kPermissionAllowed;
253 0 : break;
254 :
255 : case kPermissionDenied:
256 0 : permission = kPermissionDenied;
257 0 : break;
258 :
259 : default:
260 0 : MOZ_CRASH("Bad prompt result!");
261 : }
262 :
263 0 : OnPromptComplete(permission);
264 0 : return NS_OK;
265 : }
266 :
267 : } // namespace indexedDB
268 : } // namespace dom
269 : } // namespace mozilla
|