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 "mozilla/dom/PushManager.h"
8 :
9 : #include "mozilla/Base64.h"
10 : #include "mozilla/Preferences.h"
11 : #include "mozilla/Services.h"
12 : #include "mozilla/Unused.h"
13 : #include "mozilla/dom/PushManagerBinding.h"
14 : #include "mozilla/dom/PushSubscription.h"
15 : #include "mozilla/dom/PushSubscriptionOptionsBinding.h"
16 : #include "mozilla/dom/PushUtil.h"
17 :
18 : #include "mozilla/dom/Promise.h"
19 : #include "mozilla/dom/PromiseWorkerProxy.h"
20 :
21 : #include "nsIGlobalObject.h"
22 : #include "nsIPermissionManager.h"
23 : #include "nsIPrincipal.h"
24 : #include "nsIPushService.h"
25 :
26 : #include "nsComponentManagerUtils.h"
27 : #include "nsContentUtils.h"
28 :
29 : #include "WorkerRunnable.h"
30 : #include "WorkerPrivate.h"
31 : #include "WorkerScope.h"
32 :
33 : namespace mozilla {
34 : namespace dom {
35 :
36 : using namespace workers;
37 :
38 : namespace {
39 :
40 : nsresult
41 0 : GetPermissionState(nsIPrincipal* aPrincipal,
42 : PushPermissionState& aState)
43 : {
44 : nsCOMPtr<nsIPermissionManager> permManager =
45 0 : mozilla::services::GetPermissionManager();
46 :
47 0 : if (!permManager) {
48 0 : return NS_ERROR_FAILURE;
49 : }
50 0 : uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
51 0 : nsresult rv = permManager->TestExactPermissionFromPrincipal(
52 : aPrincipal,
53 : "desktop-notification",
54 0 : &permission);
55 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
56 0 : return rv;
57 : }
58 :
59 0 : if (permission == nsIPermissionManager::ALLOW_ACTION ||
60 0 : Preferences::GetBool("dom.push.testing.ignorePermission", false)) {
61 0 : aState = PushPermissionState::Granted;
62 0 : } else if (permission == nsIPermissionManager::DENY_ACTION) {
63 0 : aState = PushPermissionState::Denied;
64 : } else {
65 0 : aState = PushPermissionState::Prompt;
66 : }
67 :
68 0 : return NS_OK;
69 : }
70 :
71 : // A helper class that frees an `nsIPushSubscription` key buffer when it
72 : // goes out of scope.
73 : class MOZ_RAII AutoFreeKeyBuffer final
74 : {
75 : uint8_t** mKeyBuffer;
76 :
77 : public:
78 0 : explicit AutoFreeKeyBuffer(uint8_t** aKeyBuffer)
79 0 : : mKeyBuffer(aKeyBuffer)
80 : {
81 0 : MOZ_ASSERT(mKeyBuffer);
82 0 : }
83 :
84 0 : ~AutoFreeKeyBuffer()
85 0 : {
86 0 : NS_Free(*mKeyBuffer);
87 0 : }
88 : };
89 :
90 : // Copies a subscription key buffer into an array.
91 : nsresult
92 0 : CopySubscriptionKeyToArray(nsIPushSubscription* aSubscription,
93 : const nsAString& aKeyName,
94 : nsTArray<uint8_t>& aKey)
95 : {
96 0 : uint8_t* keyBuffer = nullptr;
97 0 : AutoFreeKeyBuffer autoFree(&keyBuffer);
98 :
99 : uint32_t keyLen;
100 0 : nsresult rv = aSubscription->GetKey(aKeyName, &keyLen, &keyBuffer);
101 0 : if (NS_FAILED(rv)) {
102 0 : return rv;
103 : }
104 0 : if (!aKey.SetCapacity(keyLen, fallible) ||
105 0 : !aKey.InsertElementsAt(0, keyBuffer, keyLen, fallible)) {
106 0 : return NS_ERROR_OUT_OF_MEMORY;
107 : }
108 0 : return NS_OK;
109 : }
110 :
111 : nsresult
112 0 : GetSubscriptionParams(nsIPushSubscription* aSubscription,
113 : nsAString& aEndpoint,
114 : nsTArray<uint8_t>& aRawP256dhKey,
115 : nsTArray<uint8_t>& aAuthSecret,
116 : nsTArray<uint8_t>& aAppServerKey)
117 : {
118 0 : if (!aSubscription) {
119 0 : return NS_OK;
120 : }
121 :
122 0 : nsresult rv = aSubscription->GetEndpoint(aEndpoint);
123 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
124 0 : return rv;
125 : }
126 :
127 0 : rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("p256dh"),
128 0 : aRawP256dhKey);
129 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
130 0 : return rv;
131 : }
132 0 : rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("auth"),
133 0 : aAuthSecret);
134 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
135 0 : return rv;
136 : }
137 0 : rv = CopySubscriptionKeyToArray(aSubscription, NS_LITERAL_STRING("appServer"),
138 0 : aAppServerKey);
139 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
140 0 : return rv;
141 : }
142 :
143 0 : return NS_OK;
144 : }
145 :
146 : class GetSubscriptionResultRunnable final : public WorkerRunnable
147 : {
148 : public:
149 0 : GetSubscriptionResultRunnable(WorkerPrivate* aWorkerPrivate,
150 : already_AddRefed<PromiseWorkerProxy>&& aProxy,
151 : nsresult aStatus,
152 : const nsAString& aEndpoint,
153 : const nsAString& aScope,
154 : nsTArray<uint8_t>&& aRawP256dhKey,
155 : nsTArray<uint8_t>&& aAuthSecret,
156 : nsTArray<uint8_t>&& aAppServerKey)
157 0 : : WorkerRunnable(aWorkerPrivate)
158 0 : , mProxy(Move(aProxy))
159 : , mStatus(aStatus)
160 : , mEndpoint(aEndpoint)
161 : , mScope(aScope)
162 0 : , mRawP256dhKey(Move(aRawP256dhKey))
163 0 : , mAuthSecret(Move(aAuthSecret))
164 0 : , mAppServerKey(Move(aAppServerKey))
165 0 : { }
166 :
167 : bool
168 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
169 : {
170 0 : RefPtr<Promise> promise = mProxy->WorkerPromise();
171 0 : if (NS_SUCCEEDED(mStatus)) {
172 0 : if (mEndpoint.IsEmpty()) {
173 0 : promise->MaybeResolve(JS::NullHandleValue);
174 : } else {
175 : RefPtr<PushSubscription> sub =
176 : new PushSubscription(nullptr, mEndpoint, mScope,
177 0 : Move(mRawP256dhKey), Move(mAuthSecret),
178 0 : Move(mAppServerKey));
179 0 : promise->MaybeResolve(sub);
180 : }
181 0 : } else if (NS_ERROR_GET_MODULE(mStatus) == NS_ERROR_MODULE_DOM_PUSH ) {
182 0 : promise->MaybeReject(mStatus);
183 : } else {
184 0 : promise->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
185 : }
186 :
187 0 : mProxy->CleanUp();
188 :
189 0 : return true;
190 : }
191 : private:
192 0 : ~GetSubscriptionResultRunnable()
193 0 : {}
194 :
195 : RefPtr<PromiseWorkerProxy> mProxy;
196 : nsresult mStatus;
197 : nsString mEndpoint;
198 : nsString mScope;
199 : nsTArray<uint8_t> mRawP256dhKey;
200 : nsTArray<uint8_t> mAuthSecret;
201 : nsTArray<uint8_t> mAppServerKey;
202 : };
203 :
204 : class GetSubscriptionCallback final : public nsIPushSubscriptionCallback
205 : {
206 : public:
207 : NS_DECL_ISUPPORTS
208 :
209 0 : explicit GetSubscriptionCallback(PromiseWorkerProxy* aProxy,
210 : const nsAString& aScope)
211 0 : : mProxy(aProxy)
212 0 : , mScope(aScope)
213 0 : {}
214 :
215 : NS_IMETHOD
216 0 : OnPushSubscription(nsresult aStatus,
217 : nsIPushSubscription* aSubscription) override
218 : {
219 0 : AssertIsOnMainThread();
220 0 : MOZ_ASSERT(mProxy, "OnPushSubscription() called twice?");
221 :
222 0 : MutexAutoLock lock(mProxy->Lock());
223 0 : if (mProxy->CleanedUp()) {
224 0 : return NS_OK;
225 : }
226 :
227 0 : nsAutoString endpoint;
228 0 : nsTArray<uint8_t> rawP256dhKey, authSecret, appServerKey;
229 0 : if (NS_SUCCEEDED(aStatus)) {
230 : aStatus = GetSubscriptionParams(aSubscription, endpoint, rawP256dhKey,
231 0 : authSecret, appServerKey);
232 : }
233 :
234 0 : WorkerPrivate* worker = mProxy->GetWorkerPrivate();
235 : RefPtr<GetSubscriptionResultRunnable> r =
236 : new GetSubscriptionResultRunnable(worker,
237 0 : mProxy.forget(),
238 : aStatus,
239 : endpoint,
240 : mScope,
241 : Move(rawP256dhKey),
242 : Move(authSecret),
243 0 : Move(appServerKey));
244 0 : MOZ_ALWAYS_TRUE(r->Dispatch());
245 :
246 0 : return NS_OK;
247 : }
248 :
249 : // Convenience method for use in this file.
250 : void
251 0 : OnPushSubscriptionError(nsresult aStatus)
252 : {
253 0 : Unused << NS_WARN_IF(NS_FAILED(
254 : OnPushSubscription(aStatus, nullptr)));
255 0 : }
256 :
257 : protected:
258 0 : ~GetSubscriptionCallback()
259 0 : {}
260 :
261 : private:
262 : RefPtr<PromiseWorkerProxy> mProxy;
263 : nsString mScope;
264 : };
265 :
266 0 : NS_IMPL_ISUPPORTS(GetSubscriptionCallback, nsIPushSubscriptionCallback)
267 :
268 : class GetSubscriptionRunnable final : public Runnable
269 : {
270 : public:
271 0 : GetSubscriptionRunnable(PromiseWorkerProxy* aProxy,
272 : const nsAString& aScope,
273 : PushManager::SubscriptionAction aAction,
274 : nsTArray<uint8_t>&& aAppServerKey)
275 0 : : Runnable("dom::GetSubscriptionRunnable")
276 : , mProxy(aProxy)
277 : , mScope(aScope)
278 : , mAction(aAction)
279 0 : , mAppServerKey(Move(aAppServerKey))
280 0 : {}
281 :
282 : NS_IMETHOD
283 0 : Run() override
284 : {
285 0 : AssertIsOnMainThread();
286 :
287 0 : nsCOMPtr<nsIPrincipal> principal;
288 :
289 : {
290 : // Bug 1228723: If permission is revoked or an error occurs, the
291 : // subscription callback will be called synchronously. This causes
292 : // `GetSubscriptionCallback::OnPushSubscription` to deadlock when
293 : // it tries to acquire the lock.
294 0 : MutexAutoLock lock(mProxy->Lock());
295 0 : if (mProxy->CleanedUp()) {
296 0 : return NS_OK;
297 : }
298 0 : principal = mProxy->GetWorkerPrivate()->GetPrincipal();
299 : }
300 :
301 0 : MOZ_ASSERT(principal);
302 :
303 0 : RefPtr<GetSubscriptionCallback> callback = new GetSubscriptionCallback(mProxy, mScope);
304 :
305 : PushPermissionState state;
306 0 : nsresult rv = GetPermissionState(principal, state);
307 0 : if (NS_FAILED(rv)) {
308 0 : callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
309 0 : return NS_OK;
310 : }
311 :
312 0 : if (state != PushPermissionState::Granted) {
313 0 : if (mAction == PushManager::GetSubscriptionAction) {
314 0 : callback->OnPushSubscriptionError(NS_OK);
315 0 : return NS_OK;
316 : }
317 0 : callback->OnPushSubscriptionError(NS_ERROR_DOM_PUSH_DENIED_ERR);
318 0 : return NS_OK;
319 : }
320 :
321 : nsCOMPtr<nsIPushService> service =
322 0 : do_GetService("@mozilla.org/push/Service;1");
323 0 : if (NS_WARN_IF(!service)) {
324 0 : callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
325 0 : return NS_OK;
326 : }
327 :
328 0 : if (mAction == PushManager::SubscribeAction) {
329 0 : if (mAppServerKey.IsEmpty()) {
330 0 : rv = service->Subscribe(mScope, principal, callback);
331 : } else {
332 0 : rv = service->SubscribeWithKey(mScope, principal,
333 0 : mAppServerKey.Length(),
334 0 : mAppServerKey.Elements(), callback);
335 : }
336 : } else {
337 0 : MOZ_ASSERT(mAction == PushManager::GetSubscriptionAction);
338 0 : rv = service->GetSubscription(mScope, principal, callback);
339 : }
340 :
341 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
342 0 : callback->OnPushSubscriptionError(NS_ERROR_FAILURE);
343 0 : return NS_OK;
344 : }
345 :
346 0 : return NS_OK;
347 : }
348 :
349 : private:
350 0 : ~GetSubscriptionRunnable()
351 0 : {}
352 :
353 : RefPtr<PromiseWorkerProxy> mProxy;
354 : nsString mScope;
355 : PushManager::SubscriptionAction mAction;
356 : nsTArray<uint8_t> mAppServerKey;
357 : };
358 :
359 : class PermissionResultRunnable final : public WorkerRunnable
360 : {
361 : public:
362 0 : PermissionResultRunnable(PromiseWorkerProxy *aProxy,
363 : nsresult aStatus,
364 : PushPermissionState aState)
365 0 : : WorkerRunnable(aProxy->GetWorkerPrivate())
366 : , mProxy(aProxy)
367 : , mStatus(aStatus)
368 0 : , mState(aState)
369 : {
370 0 : AssertIsOnMainThread();
371 0 : }
372 :
373 : bool
374 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
375 : {
376 0 : MOZ_ASSERT(aWorkerPrivate);
377 0 : aWorkerPrivate->AssertIsOnWorkerThread();
378 :
379 0 : RefPtr<Promise> promise = mProxy->WorkerPromise();
380 0 : if (NS_SUCCEEDED(mStatus)) {
381 0 : promise->MaybeResolve(mState);
382 : } else {
383 0 : promise->MaybeReject(aCx, JS::UndefinedHandleValue);
384 : }
385 :
386 0 : mProxy->CleanUp();
387 :
388 0 : return true;
389 : }
390 :
391 : private:
392 0 : ~PermissionResultRunnable()
393 0 : {}
394 :
395 : RefPtr<PromiseWorkerProxy> mProxy;
396 : nsresult mStatus;
397 : PushPermissionState mState;
398 : };
399 :
400 : class PermissionStateRunnable final : public Runnable
401 : {
402 : public:
403 0 : explicit PermissionStateRunnable(PromiseWorkerProxy* aProxy)
404 0 : : Runnable("dom::PermissionStateRunnable")
405 0 : , mProxy(aProxy)
406 0 : {}
407 :
408 : NS_IMETHOD
409 0 : Run() override
410 : {
411 0 : AssertIsOnMainThread();
412 0 : MutexAutoLock lock(mProxy->Lock());
413 0 : if (mProxy->CleanedUp()) {
414 0 : return NS_OK;
415 : }
416 :
417 : PushPermissionState state;
418 0 : nsresult rv = GetPermissionState(
419 0 : mProxy->GetWorkerPrivate()->GetPrincipal(),
420 : state
421 0 : );
422 :
423 : RefPtr<PermissionResultRunnable> r =
424 0 : new PermissionResultRunnable(mProxy, rv, state);
425 0 : MOZ_ALWAYS_TRUE(r->Dispatch());
426 :
427 0 : return NS_OK;
428 : }
429 :
430 : private:
431 0 : ~PermissionStateRunnable()
432 0 : {}
433 :
434 : RefPtr<PromiseWorkerProxy> mProxy;
435 : };
436 :
437 : } // anonymous namespace
438 :
439 0 : PushManager::PushManager(nsIGlobalObject* aGlobal, PushManagerImpl* aImpl)
440 : : mGlobal(aGlobal)
441 0 : , mImpl(aImpl)
442 : {
443 0 : AssertIsOnMainThread();
444 0 : MOZ_ASSERT(aImpl);
445 0 : }
446 :
447 0 : PushManager::PushManager(const nsAString& aScope)
448 0 : : mScope(aScope)
449 : {
450 : #ifdef DEBUG
451 : // There's only one global on a worker, so we don't need to pass a global
452 : // object to the constructor.
453 0 : WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
454 0 : MOZ_ASSERT(worker);
455 0 : worker->AssertIsOnWorkerThread();
456 : #endif
457 0 : }
458 :
459 0 : PushManager::~PushManager()
460 0 : {}
461 :
462 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushManager, mGlobal, mImpl)
463 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PushManager)
464 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PushManager)
465 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushManager)
466 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
467 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
468 0 : NS_INTERFACE_MAP_END
469 :
470 : JSObject*
471 0 : PushManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
472 : {
473 0 : return PushManagerBinding::Wrap(aCx, this, aGivenProto);
474 : }
475 :
476 : // static
477 : already_AddRefed<PushManager>
478 0 : PushManager::Constructor(GlobalObject& aGlobal,
479 : const nsAString& aScope,
480 : ErrorResult& aRv)
481 : {
482 0 : if (!NS_IsMainThread()) {
483 0 : RefPtr<PushManager> ret = new PushManager(aScope);
484 0 : return ret.forget();
485 : }
486 :
487 0 : RefPtr<PushManagerImpl> impl = PushManagerImpl::Constructor(aGlobal,
488 : aGlobal.Context(),
489 0 : aScope, aRv);
490 0 : if (aRv.Failed()) {
491 0 : return nullptr;
492 : }
493 :
494 0 : nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
495 0 : RefPtr<PushManager> ret = new PushManager(global, impl);
496 :
497 0 : return ret.forget();
498 : }
499 :
500 : already_AddRefed<Promise>
501 0 : PushManager::Subscribe(const PushSubscriptionOptionsInit& aOptions,
502 : ErrorResult& aRv)
503 : {
504 0 : if (mImpl) {
505 0 : MOZ_ASSERT(NS_IsMainThread());
506 0 : return mImpl->Subscribe(aOptions, aRv);
507 : }
508 :
509 0 : return PerformSubscriptionActionFromWorker(SubscribeAction, aOptions, aRv);
510 : }
511 :
512 : already_AddRefed<Promise>
513 0 : PushManager::GetSubscription(ErrorResult& aRv)
514 : {
515 0 : if (mImpl) {
516 0 : MOZ_ASSERT(NS_IsMainThread());
517 0 : return mImpl->GetSubscription(aRv);
518 : }
519 :
520 0 : return PerformSubscriptionActionFromWorker(GetSubscriptionAction, aRv);
521 : }
522 :
523 : already_AddRefed<Promise>
524 0 : PushManager::PermissionState(const PushSubscriptionOptionsInit& aOptions,
525 : ErrorResult& aRv)
526 : {
527 0 : if (mImpl) {
528 0 : MOZ_ASSERT(NS_IsMainThread());
529 0 : return mImpl->PermissionState(aOptions, aRv);
530 : }
531 :
532 0 : WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
533 0 : MOZ_ASSERT(worker);
534 0 : worker->AssertIsOnWorkerThread();
535 :
536 0 : nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
537 0 : RefPtr<Promise> p = Promise::Create(global, aRv);
538 0 : if (NS_WARN_IF(aRv.Failed())) {
539 0 : return nullptr;
540 : }
541 :
542 0 : RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
543 0 : if (!proxy) {
544 0 : p->MaybeReject(worker->GetJSContext(), JS::UndefinedHandleValue);
545 0 : return p.forget();
546 : }
547 :
548 : RefPtr<PermissionStateRunnable> r =
549 0 : new PermissionStateRunnable(proxy);
550 0 : NS_DispatchToMainThread(r);
551 :
552 0 : return p.forget();
553 : }
554 :
555 : already_AddRefed<Promise>
556 0 : PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
557 : ErrorResult& aRv)
558 : {
559 0 : PushSubscriptionOptionsInit options;
560 0 : return PerformSubscriptionActionFromWorker(aAction, options, aRv);
561 : }
562 :
563 : already_AddRefed<Promise>
564 0 : PushManager::PerformSubscriptionActionFromWorker(SubscriptionAction aAction,
565 : const PushSubscriptionOptionsInit& aOptions,
566 : ErrorResult& aRv)
567 : {
568 0 : WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
569 0 : MOZ_ASSERT(worker);
570 0 : worker->AssertIsOnWorkerThread();
571 :
572 0 : nsCOMPtr<nsIGlobalObject> global = worker->GlobalScope();
573 0 : RefPtr<Promise> p = Promise::Create(global, aRv);
574 0 : if (NS_WARN_IF(aRv.Failed())) {
575 0 : return nullptr;
576 : }
577 :
578 0 : RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, p);
579 0 : if (!proxy) {
580 0 : p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR);
581 0 : return p.forget();
582 : }
583 :
584 0 : nsTArray<uint8_t> appServerKey;
585 0 : if (!aOptions.mApplicationServerKey.IsNull()) {
586 0 : nsresult rv = NormalizeAppServerKey(aOptions.mApplicationServerKey.Value(),
587 0 : appServerKey);
588 0 : if (NS_FAILED(rv)) {
589 0 : p->MaybeReject(rv);
590 0 : return p.forget();
591 : }
592 : }
593 :
594 : RefPtr<GetSubscriptionRunnable> r =
595 0 : new GetSubscriptionRunnable(proxy, mScope, aAction, Move(appServerKey));
596 0 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
597 :
598 0 : return p.forget();
599 : }
600 :
601 : nsresult
602 0 : PushManager::NormalizeAppServerKey(const OwningArrayBufferViewOrArrayBufferOrString& aSource,
603 : nsTArray<uint8_t>& aAppServerKey)
604 : {
605 0 : if (aSource.IsString()) {
606 0 : NS_ConvertUTF16toUTF8 base64Key(aSource.GetAsString());
607 0 : FallibleTArray<uint8_t> decodedKey;
608 : nsresult rv = Base64URLDecode(base64Key,
609 : Base64URLDecodePaddingPolicy::Reject,
610 0 : decodedKey);
611 0 : if (NS_FAILED(rv)) {
612 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
613 : }
614 0 : aAppServerKey = decodedKey;
615 0 : } else if (aSource.IsArrayBuffer()) {
616 0 : if (!PushUtil::CopyArrayBufferToArray(aSource.GetAsArrayBuffer(),
617 : aAppServerKey)) {
618 0 : return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
619 : }
620 0 : } else if (aSource.IsArrayBufferView()) {
621 0 : if (!PushUtil::CopyArrayBufferViewToArray(aSource.GetAsArrayBufferView(),
622 : aAppServerKey)) {
623 0 : return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
624 : }
625 : } else {
626 0 : MOZ_CRASH("Uninitialized union: expected string, buffer, or view");
627 : }
628 0 : if (aAppServerKey.IsEmpty()) {
629 0 : return NS_ERROR_DOM_PUSH_INVALID_KEY_ERR;
630 : }
631 0 : return NS_OK;
632 : }
633 :
634 : } // namespace dom
635 : } // namespace mozilla
|