StorageAccessPermissionRequest.cpp (5716B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "StorageAccessPermissionRequest.h" 8 9 #include <cstdlib> 10 11 #include "mozilla/StaticPrefs_dom.h" 12 #include "nsGlobalWindowInner.h" 13 14 namespace mozilla::dom { 15 16 NS_IMPL_CYCLE_COLLECTION_INHERITED(StorageAccessPermissionRequest, 17 ContentPermissionRequestBase) 18 19 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(StorageAccessPermissionRequest, 20 ContentPermissionRequestBase) 21 22 StorageAccessPermissionRequest::StorageAccessPermissionRequest( 23 nsPIDOMWindowInner* aWindow, nsIPrincipal* aNodePrincipal, 24 const Maybe<nsCString>& aTopLevelBaseDomain, bool aFrameOnly, 25 AllowCallback&& aAllowCallback, CancelCallback&& aCancelCallback) 26 : ContentPermissionRequestBase(aNodePrincipal, aWindow, 27 "dom.storage_access"_ns, 28 "storage-access"_ns), 29 mAllowCallback(std::move(aAllowCallback)), 30 mCancelCallback(std::move(aCancelCallback)), 31 mCallbackCalled(false) { 32 mOptions.SetLength(2); 33 if (aTopLevelBaseDomain.isSome()) { 34 nsCString option = aTopLevelBaseDomain.value(); 35 mOptions.ElementAt(0) = NS_ConvertUTF8toUTF16(option); 36 } 37 if (aFrameOnly) { 38 mOptions.ElementAt(1) = u"1"_ns; 39 } 40 mPermissionRequests.AppendElement(PermissionRequest(mType, mOptions)); 41 } 42 43 NS_IMETHODIMP 44 StorageAccessPermissionRequest::Cancel() { 45 if (!mCallbackCalled) { 46 mCallbackCalled = true; 47 mCancelCallback(); 48 } 49 return NS_OK; 50 } 51 52 NS_IMETHODIMP 53 StorageAccessPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) { 54 nsTArray<PermissionChoice> choices; 55 nsresult rv = TranslateChoices(aChoices, mPermissionRequests, choices); 56 if (NS_FAILED(rv)) { 57 return rv; 58 } 59 60 // There is no support to allow grants automatically from the prompting code 61 // path. 62 63 if (!mCallbackCalled) { 64 mCallbackCalled = true; 65 if (choices.Length() == 1 && choices[0].choice().EqualsLiteral("allow")) { 66 mAllowCallback(); 67 } 68 } 69 return NS_OK; 70 } 71 72 NS_IMETHODIMP 73 StorageAccessPermissionRequest::GetTypes(nsIArray** aTypes) { 74 return nsContentPermissionUtils::CreatePermissionArray(mType, mOptions, 75 aTypes); 76 } 77 78 RefPtr<StorageAccessPermissionRequest::AutoGrantDelayPromise> 79 StorageAccessPermissionRequest::MaybeDelayAutomaticGrants() { 80 RefPtr<AutoGrantDelayPromise::Private> p = 81 new AutoGrantDelayPromise::Private(__func__); 82 83 unsigned simulatedDelay = CalculateSimulatedDelay(); 84 if (simulatedDelay) { 85 nsCOMPtr<nsITimer> timer; 86 RefPtr<AutoGrantDelayPromise::Private> promise = p; 87 nsresult rv = NS_NewTimerWithFuncCallback( 88 getter_AddRefs(timer), 89 [](nsITimer* aTimer, void* aClosure) -> void { 90 auto* promise = 91 static_cast<AutoGrantDelayPromise::Private*>(aClosure); 92 promise->Resolve(true, __func__); 93 NS_RELEASE(aTimer); 94 NS_RELEASE(promise); 95 }, 96 promise, simulatedDelay, nsITimer::TYPE_ONE_SHOT, 97 "DelayedAllowAutoGrantCallback"_ns); 98 if (NS_WARN_IF(NS_FAILED(rv))) { 99 p->Reject(false, __func__); 100 } else { 101 // Leak the references here! We'll release them inside the callback. 102 timer.forget().leak(); 103 promise.forget().leak(); 104 } 105 } else { 106 p->Resolve(false, __func__); 107 } 108 return p; 109 } 110 111 already_AddRefed<StorageAccessPermissionRequest> 112 StorageAccessPermissionRequest::Create(nsPIDOMWindowInner* aWindow, 113 AllowCallback&& aAllowCallback, 114 CancelCallback&& aCancelCallback) { 115 if (!aWindow) { 116 return nullptr; 117 } 118 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(aWindow); 119 120 return Create(aWindow, win->GetPrincipal(), std::move(aAllowCallback), 121 std::move(aCancelCallback)); 122 } 123 124 already_AddRefed<StorageAccessPermissionRequest> 125 StorageAccessPermissionRequest::Create(nsPIDOMWindowInner* aWindow, 126 nsIPrincipal* aPrincipal, 127 AllowCallback&& aAllowCallback, 128 CancelCallback&& aCancelCallback) { 129 return Create(aWindow, aPrincipal, Nothing(), true, std::move(aAllowCallback), 130 std::move(aCancelCallback)); 131 } 132 133 already_AddRefed<StorageAccessPermissionRequest> 134 StorageAccessPermissionRequest::Create( 135 nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal, 136 const Maybe<nsCString>& aTopLevelBaseDomain, bool aFrameOnly, 137 AllowCallback&& aAllowCallback, CancelCallback&& aCancelCallback) { 138 if (!aWindow) { 139 return nullptr; 140 } 141 142 if (!aPrincipal) { 143 return nullptr; 144 } 145 146 RefPtr<StorageAccessPermissionRequest> request = 147 new StorageAccessPermissionRequest( 148 aWindow, aPrincipal, aTopLevelBaseDomain, aFrameOnly, 149 std::move(aAllowCallback), std::move(aCancelCallback)); 150 return request.forget(); 151 } 152 153 unsigned StorageAccessPermissionRequest::CalculateSimulatedDelay() { 154 if (!StaticPrefs::dom_storage_access_auto_grants_delayed()) { 155 return 0; 156 } 157 158 // Generate a random time value that is at least 0 and and most 3 seconds. 159 std::srand(static_cast<unsigned>(PR_Now())); 160 161 const unsigned kMin = 0; 162 const unsigned kMax = 3000; 163 const unsigned random = std::abs(std::rand()); 164 165 return kMin + random % (kMax - kMin); 166 } 167 168 } // namespace mozilla::dom