Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* 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
"use strict";
XPCOMUtils.defineLazyServiceGetter(
this,
"gCPS",
"@mozilla.org/network/captive-portal-service;1",
"nsICaptivePortalService"
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gCaptivePortalEnabled",
"network.captive-portal-service.enabled",
false
);
var { ExtensionPreferencesManager } = ChromeUtils.importESModule(
"resource://gre/modules/ExtensionPreferencesManager.sys.mjs"
);
var { getSettingsAPI } = ExtensionPreferencesManager;
const CAPTIVE_URL_PREF = "captivedetect.canonicalURL";
var { ExtensionError } = ExtensionUtils;
this.captivePortal = class extends ExtensionAPIPersistent {
checkCaptivePortalEnabled() {
if (!gCaptivePortalEnabled) {
throw new ExtensionError("Captive Portal detection is not enabled");
}
}
nameForCPSState(state) {
switch (state) {
case gCPS.UNKNOWN:
return "unknown";
case gCPS.NOT_CAPTIVE:
return "not_captive";
case gCPS.UNLOCKED_PORTAL:
return "unlocked_portal";
case gCPS.LOCKED_PORTAL:
return "locked_portal";
default:
return "unknown";
}
}
PERSISTENT_EVENTS = {
onStateChanged({ fire }) {
this.checkCaptivePortalEnabled();
let observer = () => {
fire.async({ state: this.nameForCPSState(gCPS.state) });
};
Services.obs.addObserver(
observer,
"ipc:network:captive-portal-set-state"
);
return {
unregister: () => {
Services.obs.removeObserver(
observer,
"ipc:network:captive-portal-set-state"
);
},
convert(_fire) {
fire = _fire;
},
};
},
onConnectivityAvailable({ fire }) {
this.checkCaptivePortalEnabled();
let observer = (subject, topic, data) => {
fire.async({ status: data });
};
Services.obs.addObserver(observer, "network:captive-portal-connectivity");
return {
unregister: () => {
Services.obs.removeObserver(
observer,
"network:captive-portal-connectivity"
);
},
convert(_fire) {
fire = _fire;
},
};
},
"captiveURL.onChange": ({ fire }) => {
let listener = () => {
fire.async({
levelOfControl: "not_controllable",
value: Services.prefs.getStringPref(CAPTIVE_URL_PREF),
});
};
Services.prefs.addObserver(CAPTIVE_URL_PREF, listener);
return {
unregister: () => {
Services.prefs.removeObserver(CAPTIVE_URL_PREF, listener);
},
convert(_fire) {
fire = _fire;
},
};
},
};
getAPI(context) {
let self = this;
return {
captivePortal: {
getState() {
self.checkCaptivePortalEnabled();
return self.nameForCPSState(gCPS.state);
},
getLastChecked() {
self.checkCaptivePortalEnabled();
return gCPS.lastChecked;
},
onStateChanged: new EventManager({
context,
module: "captivePortal",
event: "onStateChanged",
extensionApi: self,
}).api(),
onConnectivityAvailable: new EventManager({
context,
module: "captivePortal",
event: "onConnectivityAvailable",
extensionApi: self,
}).api(),
canonicalURL: getSettingsAPI({
context,
name: "captiveURL",
callback() {
return Services.prefs.getStringPref(CAPTIVE_URL_PREF);
},
readOnly: true,
onChange: new ExtensionCommon.EventManager({
context,
module: "captivePortal",
event: "captiveURL.onChange",
extensionApi: self,
}).api(),
}),
},
};
}
};