mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1514547 - Timing token to allow external protocol URLs are blocked in iframes without user-interaction, r=smaug
This commit is contained in:
parent
0216704229
commit
89a0cf9c7e
@ -9654,6 +9654,9 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
||||
// events
|
||||
if (PopupBlocker::GetPopupControlState() <= PopupBlocker::openBlocked) {
|
||||
popupBlocked = !PopupBlocker::TryUsePopupOpeningToken();
|
||||
} else if (mIsActive &&
|
||||
PopupBlocker::ConsumeTimerTokenForExternalProtocolIframe()) {
|
||||
popupBlocked = false;
|
||||
} else {
|
||||
nsCOMPtr<nsINode> loadingNode =
|
||||
mScriptGlobal->AsOuter()->GetFrameElementInternal();
|
||||
|
@ -800,6 +800,17 @@ constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
|
||||
return PopupBlocker::IsPopupOpeningTokenUnused();
|
||||
}
|
||||
|
||||
/* static */ double ChromeUtils::LastExternalProtocolIframeAllowed(
|
||||
GlobalObject& aGlobal) {
|
||||
TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
|
||||
if (when.IsNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TimeDuration duration = TimeStamp::Now() - when;
|
||||
return duration.ToMilliseconds();
|
||||
}
|
||||
|
||||
/* static */ void ChromeUtils::RegisterWindowActor(
|
||||
const GlobalObject& aGlobal, const nsAString& aName,
|
||||
const WindowActorOptions& aOptions, ErrorResult& aRv) {
|
||||
|
@ -178,6 +178,8 @@ class ChromeUtils {
|
||||
|
||||
static bool IsPopupTokenUnused(GlobalObject& aGlobal);
|
||||
|
||||
static double LastExternalProtocolIframeAllowed(GlobalObject& aGlobal);
|
||||
|
||||
static void RegisterWindowActor(const GlobalObject& aGlobal,
|
||||
const nsAString& aName,
|
||||
const WindowActorOptions& aOptions,
|
||||
|
@ -7,7 +7,9 @@
|
||||
#include "mozilla/dom/PopupBlocker.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
|
||||
@ -22,6 +24,8 @@ static PopupBlocker::PopupControlState sPopupControlState =
|
||||
PopupBlocker::openAbused;
|
||||
static uint32_t sPopupStatePusherCount = 0;
|
||||
|
||||
static TimeStamp sLastAllowedExternalProtocolIFrameTimeStamp;
|
||||
|
||||
// This token is by default set to false. When a popup/filePicker is shown, it
|
||||
// is set to true.
|
||||
static bool sUnusedPopupToken = false;
|
||||
@ -379,6 +383,27 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
||||
Preferences::UnregisterCallback(OnPrefChange, "dom.popup_allowed_events");
|
||||
}
|
||||
|
||||
/* static */ bool PopupBlocker::ConsumeTimerTokenForExternalProtocolIframe() {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
if (sLastAllowedExternalProtocolIFrameTimeStamp.IsNull()) {
|
||||
sLastAllowedExternalProtocolIFrameTimeStamp = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((now - sLastAllowedExternalProtocolIFrameTimeStamp).ToSeconds() <
|
||||
(StaticPrefs::dom_delay_block_external_protocol_in_iframes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sLastAllowedExternalProtocolIFrameTimeStamp = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ TimeStamp PopupBlocker::WhenLastExternalProtocolIframeAllowed() {
|
||||
return sLastAllowedExternalProtocolIFrameTimeStamp;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -53,6 +53,12 @@ class PopupBlocker final {
|
||||
static PopupBlocker::PopupControlState GetEventPopupControlState(
|
||||
WidgetEvent* aEvent, Event* aDOMEvent = nullptr);
|
||||
|
||||
// Returns if a external protocol iframe is allowed.
|
||||
static bool ConsumeTimerTokenForExternalProtocolIframe();
|
||||
|
||||
// Returns when the last external protocol iframe has been allowed.
|
||||
static TimeStamp WhenLastExternalProtocolIframeAllowed();
|
||||
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
};
|
||||
|
@ -386,6 +386,12 @@ partial namespace ChromeUtils {
|
||||
[ChromeOnly]
|
||||
boolean isPopupTokenUnused();
|
||||
|
||||
/**
|
||||
* Milliseconds from the last iframe loading an external protocol.
|
||||
*/
|
||||
[ChromeOnly]
|
||||
double lastExternalProtocolIframeAllowed();
|
||||
|
||||
[ChromeOnly, Throws]
|
||||
void registerWindowActor(DOMString aName, WindowActorOptions aOptions);
|
||||
};
|
||||
|
@ -10,7 +10,25 @@
|
||||
<div id='foo'><a href='#'>Click here to test this issue</a></div>
|
||||
<script>
|
||||
|
||||
function next() {
|
||||
function test_noUserInteraction() {
|
||||
is(ChromeUtils.getPopupControlState(), "openAbused", "No user-interaction means: abuse state");
|
||||
ok(!ChromeUtils.isPopupTokenUnused(), "Popup token has not been used yet");
|
||||
is(ChromeUtils.lastExternalProtocolIframeAllowed(), 0, "No iframe loaded before this test!");
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
let ifr = document.createElement('iframe');
|
||||
ifr.src = "foo+bar:all_good";
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
is(ChromeUtils.getPopupControlState(), "openAbused", "No user-interaction means: abuse state");
|
||||
ok(!ChromeUtils.isPopupTokenUnused(), "Popup token has been used!");
|
||||
ok(ChromeUtils.lastExternalProtocolIframeAllowed() != 0, "We have 1 iframe loaded");
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function test_userInteraction() {
|
||||
let foo = document.getElementById('foo');
|
||||
foo.addEventListener('click', _ => {
|
||||
is(ChromeUtils.getPopupControlState(), "openAllowed", "Click events allow popups");
|
||||
@ -25,7 +43,7 @@ function next() {
|
||||
ok(ChromeUtils.isPopupTokenUnused(), "Popup token has been used!");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
next();
|
||||
|
||||
}, {once: true});
|
||||
|
||||
@ -34,6 +52,21 @@ function next() {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
test_noUserInteraction,
|
||||
test_userInteraction,
|
||||
];
|
||||
|
||||
function next() {
|
||||
if (tests.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let test = tests.shift();
|
||||
SimpleTest.executeSoon(test);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['dom.block_external_protocol_in_iframes', true],
|
||||
]}, next);
|
||||
|
@ -469,6 +469,14 @@ VARCACHE_PREF(
|
||||
)
|
||||
#undef PREF_VALUE
|
||||
|
||||
// Any how many seconds we allow external protocol URLs in iframe when not in
|
||||
// single events
|
||||
VARCACHE_PREF(
|
||||
"dom.delay.block_external_protocol_in_iframes",
|
||||
dom_delay_block_external_protocol_in_iframes,
|
||||
uint32_t, 10 // in seconds
|
||||
)
|
||||
|
||||
// Block multiple window.open() per single event.
|
||||
VARCACHE_PREF(
|
||||
"dom.block_multiple_popups",
|
||||
|
Loading…
Reference in New Issue
Block a user