Source code

Revision control

Copy as Markdown

Other Tools

/* Any copyright is dedicated to the Public Domain.
*/
"use strict";
const { AddonTestUtils } = ChromeUtils.importESModule(
);
AddonTestUtils.initMochitest(this);
const ADDON_ID = "amosigned-xpi@tests.mozilla.org";
// Test whether an install succeeds when authentication is required
// This verifies bug 312473.
async function testAuthRequiredInstall({ authInfo, expectFailure }) {
// This test depends on InstallTrigger.install availability.
setInstallTriggerPrefs();
const deferredInstallCompleted = Promise.withResolvers();
let promiseAddonStarted;
Harness.installConfirmCallback = () => {
promiseAddonStarted = AddonTestUtils.promiseWebExtensionStartup(ADDON_ID);
return true;
};
Harness.authenticationCallback = () => {
return authInfo;
};
Harness.downloadFailedCallback = () => {
ok(
expectFailure,
expectFailure
? "Install should have failed"
: "Install should have NOT failed"
);
};
if (!expectFailure) {
Harness.installEndedCallback = (install, addon) => {
return promiseAddonStarted.then(() => addon.uninstall());
};
}
Harness.installsCompletedCallback = deferredInstallCompleted.resolve;
Harness.setup();
registerCleanupFunction(() => Harness.finish());
PermissionTestUtils.add(
"install",
Services.perms.ALLOW_ACTION
);
const server = AddonTestUtils.createHttpServer({
hosts: ["authredirect.example.com"],
});
let gotTabNavigationRequest = false;
server.registerPathHandler("/", (request, response) => {
if (!gotTabNavigationRequest) {
// The first request is expected to be the one intercepted by amContentHandler.sys.mjs,
// which will just look to the content-type to detect it as an add-on installation,
// then the request is cancelled and a new one retriggered as part of the actual
// add-on install flow.
gotTabNavigationRequest = true;
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/x-xpinstall");
return;
}
// This second request is the one handled by the DownloadAddonInstall instance,
// and for this second request we require authentication to explicitly trigger
// the nsIAuthPrompt2 interface to be retrieved from the DownloadAddonInstall,
// see DownloadAddonInstall getInterface method.
if (request.hasHeader("Authorization")) {
if (
request.getHeader("Authorization") == "Basic dGVzdHVzZXI6dGVzdHBhc3M="
) {
response.setStatusLine(request.httpVersion, 302, "Found");
response.setHeader("Location", request.queryString);
response.write("See " + request.queryString);
} else {
response.setStatusLine(request.httpVersion, 403, "Forbidden");
response.write("Invalid credentials");
}
} else {
response.setStatusLine(
request.httpVersion,
401,
"Authentication required"
);
response.setHeader("WWW-Authenticate", 'basic realm="XPInstall"', false);
response.write("Unauthenticated request");
}
});
var triggers = encodeURIComponent(
"http://authredirect.example.com/?" + TESTROOT + "amosigned.xpi"
);
await BrowserTestUtils.withNewTab({ gBrowser }, async () => {
BrowserTestUtils.startLoadingURIString(
gBrowser,
SECURE_TESTROOT + "navigate.html?" + triggers
);
info("Wait for the install to be completed");
const count = await deferredInstallCompleted.promise;
if (expectFailure) {
is(count, 0, "Add-on should have NOT been successfully installed");
} else {
is(count, 1, "1 Add-on should have been successfully installed");
}
});
var authMgr = Cc["@mozilla.org/network/http-auth-manager;1"].getService(
Ci.nsIHttpAuthManager
);
authMgr.clearAll();
PermissionTestUtils.remove("https://example.com", "install");
}
add_task(async function test_failure_on_invalid_authInfo() {
await testAuthRequiredInstall({
authInfo: ["baduser", "badpass"],
expectFailure: true,
});
});
add_task(async function test_failure_on_no_authInfo() {
await testAuthRequiredInstall({
authInfo: null,
expectFailure: true,
});
});
add_task(async function test_success_on_valid_authInfo() {
await testAuthRequiredInstall({
authInfo: ["testuser", "testpass"],
expectFailure: false,
});
});