1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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/MIDIPermissionRequest.h"
8 #include "mozilla/dom/MIDIAccessManager.h"
9 #include "nsIGlobalObject.h"
10 #include "mozilla/Preferences.h"
11 #include "nsContentUtils.h"
12 
13 //-------------------------------------------------
14 // MIDI Permission Requests
15 //-------------------------------------------------
16 
NS_IMPL_CYCLE_COLLECTION(MIDIPermissionRequest,mWindow,mPromise)17 NS_IMPL_CYCLE_COLLECTION(MIDIPermissionRequest, mWindow, mPromise)
18 
19 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MIDIPermissionRequest)
20   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
21   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
22   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
23 NS_INTERFACE_MAP_END
24 
25 NS_IMPL_CYCLE_COLLECTING_ADDREF(MIDIPermissionRequest)
26 NS_IMPL_CYCLE_COLLECTING_RELEASE(MIDIPermissionRequest)
27 
28 MIDIPermissionRequest::MIDIPermissionRequest(nsPIDOMWindowInner* aWindow,
29                                              Promise* aPromise,
30                                              const MIDIOptions& aOptions)
31     : mWindow(aWindow),
32       mPromise(aPromise),
33       mNeedsSysex(aOptions.mSysex),
34       mRequester(new nsContentPermissionRequester(mWindow)) {
35   MOZ_ASSERT(aWindow);
36   MOZ_ASSERT(aPromise, "aPromise should not be null!");
37   MOZ_ASSERT(aWindow->GetDoc());
38   mPrincipal = aWindow->GetDoc()->NodePrincipal();
39   MOZ_ASSERT(mPrincipal);
40 }
41 
~MIDIPermissionRequest()42 MIDIPermissionRequest::~MIDIPermissionRequest() {}
43 
44 NS_IMETHODIMP
GetIsHandlingUserInput(bool * aHandlingInput)45 MIDIPermissionRequest::GetIsHandlingUserInput(bool* aHandlingInput) {
46   *aHandlingInput = true;
47   return NS_OK;
48 }
49 
50 NS_IMETHODIMP
GetRequester(nsIContentPermissionRequester ** aRequester)51 MIDIPermissionRequest::GetRequester(
52     nsIContentPermissionRequester** aRequester) {
53   NS_ENSURE_ARG_POINTER(aRequester);
54   nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
55   requester.forget(aRequester);
56   return NS_OK;
57 }
58 
59 NS_IMETHODIMP
GetTypes(nsIArray ** aTypes)60 MIDIPermissionRequest::GetTypes(nsIArray** aTypes) {
61   NS_ENSURE_ARG_POINTER(aTypes);
62   nsTArray<nsString> options;
63   if (mNeedsSysex) {
64     options.AppendElement(NS_LITERAL_STRING("sysex"));
65   }
66   return nsContentPermissionUtils::CreatePermissionArray(
67       NS_LITERAL_CSTRING("midi"), NS_LITERAL_CSTRING("unused"), options,
68       aTypes);
69 }
70 
71 NS_IMETHODIMP
GetPrincipal(nsIPrincipal ** aRequestingPrincipal)72 MIDIPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal) {
73   NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
74   NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
75   return NS_OK;
76 }
77 
78 NS_IMETHODIMP
GetWindow(mozIDOMWindow ** aRequestingWindow)79 MIDIPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow) {
80   NS_ENSURE_ARG_POINTER(aRequestingWindow);
81   NS_IF_ADDREF(*aRequestingWindow = mWindow);
82   return NS_OK;
83 }
84 
85 NS_IMETHODIMP
GetElement(nsIDOMElement ** aRequestingElement)86 MIDIPermissionRequest::GetElement(nsIDOMElement** aRequestingElement) {
87   NS_ENSURE_ARG_POINTER(aRequestingElement);
88   *aRequestingElement = nullptr;
89   return NS_OK;
90 }
91 
92 NS_IMETHODIMP
Cancel()93 MIDIPermissionRequest::Cancel() {
94   mPromise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
95   return NS_OK;
96 }
97 
98 NS_IMETHODIMP
Allow(JS::HandleValue aChoices)99 MIDIPermissionRequest::Allow(JS::HandleValue aChoices) {
100   MOZ_ASSERT(aChoices.isUndefined());
101   MIDIAccessManager* mgr = MIDIAccessManager::Get();
102   mgr->CreateMIDIAccess(mWindow, mNeedsSysex, mPromise);
103   return NS_OK;
104 }
105 
106 NS_IMETHODIMP
Run()107 MIDIPermissionRequest::Run() {
108   // If the testing flag is true, skip dialog
109   if (Preferences::GetBool("midi.prompt.testing", false)) {
110     bool allow =
111         Preferences::GetBool("media.navigator.permission.disabled", false);
112     if (allow) {
113       Allow(JS::UndefinedHandleValue);
114     } else {
115       Cancel();
116     }
117     return NS_OK;
118   }
119 
120   // If we already have sysex perms, allow.
121   if (nsContentUtils::IsExactSitePermAllow(mPrincipal, "midi-sysex")) {
122     Allow(JS::UndefinedHandleValue);
123     return NS_OK;
124   }
125 
126   // If we have no perms, or only have midi and are asking for sysex, pop dialog
127   if (NS_FAILED(nsContentPermissionUtils::AskPermission(this, mWindow))) {
128     Cancel();
129     return NS_ERROR_FAILURE;
130   }
131   return NS_OK;
132 }
133