/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var CaptivePortalWatcher = { // This is the value used to identify the captive portal notification.
PORTAL_NOTIFICATION_VALUE: "captive-portal-detected",
// This holds a weak reference to the captive portal tab so that we // don't leak it if the user closes it.
_captivePortalTab: null,
/** * If a portal is detected when we don't have focus, we first wait for focus * and then add the tab if, after a recheck, the portal is still active. This * is set to true while we wait so that in the unlikely event that we receive * another notification while waiting, we don't do things twice.
*/
_delayedCaptivePortalDetectedInProgress: false,
// In the situation above, this is set to true while we wait for the recheck. // This flag exists so that tests can appropriately simulate a recheck.
_waitingForRecheck: false,
// This holds a weak reference to the captive portal tab so we can close the tab // after successful login if we're redirected to the canonicalURL.
_previousCaptivePortalTab: null,
// Stores the time at which the banner was displayed
_bannerDisplayTime: Date.now(),
get _captivePortalNotification() { return gNotificationBox.getNotificationWithValue( this.PORTAL_NOTIFICATION_VALUE
);
},
get canonicalURL() { return Services.prefs.getCharPref("captivedetect.canonicalURL");
},
if (this._cps.state == this._cps.LOCKED_PORTAL) { // A captive portal has already been detected. this._captivePortalDetected();
// Automatically open a captive portal tab if there's no other browser window. if (BrowserWindowTracker.windowCount == 1) { this.ensureCaptivePortalTab();
}
} elseif (this._cps.state == this._cps.UNKNOWN) { // We trigger a portal check after delayed startup to avoid doing a network // request before first paint. this._delayedRecheckPending = true;
}
// This constant is chosen to be large enough for a portal recheck to complete, // and small enough that the delay in opening a tab isn't too noticeable. // Please see comments for _delayedCaptivePortalDetected for more details.
XPCOMUtils.defineLazyPreferenceGetter( this, "PORTAL_RECHECK_DELAY_MS", "captivedetect.portalRecheckDelayMS",
500
);
},
onLocationChange(browser) { if (!this._previousCaptivePortalTab) { return;
}
let tab = this._previousCaptivePortalTab.get(); if (!tab || !tab.linkedBrowser) { return;
}
if (browser != tab.linkedBrowser) { return;
}
// There is a race between the release of captive portal i.e. // the time when success/abort events are fired and the time when // the captive portal tab redirects to the canonicalURL. We check for // both conditions to be true and also check that we haven't already removed // the captive portal tab in the success/abort event handlers before we remove // it in the callback below. A tick is added to avoid removing the tab before // onLocationChange handlers across browser code are executed.
Services.tm.dispatchToMainThread(() => { if (!this._previousCaptivePortalTab) { return;
}
_captivePortalDetected() { if (this._delayedCaptivePortalDetectedInProgress) { return;
}
// Add an explicit permission for the last detected URI such that https-only / https-first do not // attempt to upgrade the URI to https when following the "open network login page" button. // We set explicit permissions for regular and private browsing windows to keep permissions // separate.
let canonicalURI = Services.io.newURI(this.canonicalURL);
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
let principal = Services.scriptSecurityManager.createContentPrincipal(
canonicalURI,
{
userContextId: gBrowser.contentPrincipal.userContextId,
privateBrowsingId: isPrivate ? 1 : 0,
}
);
Services.perms.addFromPrincipal(
principal, "https-only-load-insecure",
Ci.nsIPermissionManager.ALLOW_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION
);
let win = BrowserWindowTracker.getTopWindow(); // Used by tests: ignore the main test window in order to enable testing of // the case where we have no open windows. if (win.document.documentElement.getAttribute("ignorecaptiveportal")) {
win = null;
}
// If no browser window has focus, open and show the tab when we regain focus. // This is so that if a different application was focused, when the user // (re-)focuses a browser window, we open the tab immediately in that window // so they can log in before continuing to browse. if (win != Services.focus.activeWindow) { this._delayedCaptivePortalDetectedInProgress = true;
window.addEventListener("activate", this, { once: true });
Services.obs.addObserver(this, "delayed-captive-portal-handled");
}
this._showNotification();
},
/** * Called after we regain focus if we detect a portal while a browser window * doesn't have focus. Triggers a portal recheck to reaffirm state, and adds * the tab if needed after a short delay to allow the recheck to complete.
*/
_delayedCaptivePortalDetected() { if (!this._delayedCaptivePortalDetectedInProgress) { return;
}
// Used by tests: ignore the main test window in order to enable testing of // the case where we have no open windows. if (window.document.documentElement.getAttribute("ignorecaptiveportal")) { return;
}
// Trigger a portal recheck. The user may have logged into the portal via // another client, or changed networks. this._cps.recheckCaptivePortal(); this._waitingForRecheck = true;
let requestTime = Date.now();
let observer = () => {
let time = Date.now() - requestTime;
Services.obs.removeObserver(observer, "captive-portal-check-complete"); this._waitingForRecheck = false; if (this._cps.state != this._cps.LOCKED_PORTAL) { // We're free of the portal! return;
}
if (time <= this.PORTAL_RECHECK_DELAY_MS) { // The amount of time elapsed since we requested a recheck (i.e. since // the browser window was focused) was small enough that we can add and // focus a tab with the login page with no noticeable delay. this.ensureCaptivePortalTab();
}
};
Services.obs.addObserver(observer, "captive-portal-check-complete");
},
_removeNotification() {
let n = this._captivePortalNotification; if (!n || !n.parentNode) { return;
}
n.close();
},
ensureCaptivePortalTab() {
let tab; if (this._captivePortalTab) {
tab = this._captivePortalTab.get();
}
// If the tab is gone or going, we need to open a new one. if (!tab || tab.closing || !tab.parentNode) {
tab = gBrowser.addWebTab(this.canonicalURL, {
ownerTab: gBrowser.selectedTab,
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
{
userContextId: gBrowser.contentPrincipal.userContextId,
}
),
disableTRR: true,
}); this._captivePortalTab = Cu.getWeakReference(tab); this._previousCaptivePortalTab = Cu.getWeakReference(tab);
}
gBrowser.selectedTab = tab;
},
};
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.