browser_mixed_content_auth_download.js (5276B)
1 /* Any copyright is dedicated to the Public Domain. 2 * https://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 ChromeUtils.defineESModuleGetters(this, { 7 Downloads: "resource://gre/modules/Downloads.sys.mjs", 8 DownloadsCommon: 9 "moz-src:///browser/components/downloads/DownloadsCommon.sys.mjs", 10 }); 11 12 const { PromptTestUtils } = ChromeUtils.importESModule( 13 "resource://testing-common/PromptTestUtils.sys.mjs" 14 ); 15 16 const downloadMonitoringView = { 17 _listeners: [], 18 onDownloadAdded(download) { 19 for (let listener of this._listeners) { 20 listener(download); 21 } 22 this._listeners = []; 23 }, 24 waitForDownload(listener) { 25 this._listeners.push(listener); 26 }, 27 }; 28 29 let SECURE_BASE_URL = 30 getRootDirectory(gTestPath).replace( 31 "chrome://mochitests/content/", 32 "https://example.com/" 33 ) + "file_auth_download_page.html"; 34 35 /** 36 * Waits until a download is triggered. 37 * It waits until a prompt is shown, 38 * saves and then accepts the dialog. 39 * 40 * @returns {Promise} Resolved once done. 41 */ 42 43 function shouldTriggerDownload() { 44 return new Promise(res => { 45 downloadMonitoringView.waitForDownload(res); 46 }); 47 } 48 function shouldNotifyDownloadUI() { 49 return new Promise(res => { 50 downloadMonitoringView.waitForDownload(async aDownload => { 51 let { error } = aDownload; 52 if ( 53 error.becauseBlockedByReputationCheck && 54 error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE 55 ) { 56 // It's an insecure Download, now Check that it has been cleaned up properly 57 if ((await IOUtils.stat(aDownload.target.path)).size != 0) { 58 throw new Error(`Download target is not empty!`); 59 } 60 if ((await IOUtils.stat(aDownload.target.path)).size != 0) { 61 throw new Error(`Download partFile was not cleaned up properly`); 62 } 63 // Assert that the Referrer is present 64 if (!aDownload.source.referrerInfo) { 65 throw new Error("The Blocked download is missing the ReferrerInfo"); 66 } 67 68 res(aDownload); 69 } else { 70 ok(false, "No error for download that was expected to error!"); 71 } 72 }); 73 }); 74 } 75 76 async function resetDownloads() { 77 // Removes all downloads from the download List 78 const types = new Set(); 79 let publicList = await Downloads.getList(Downloads.ALL); 80 let downloads = await publicList.getAll(); 81 for (let download of downloads) { 82 if (download.contentType) { 83 types.add(download.contentType); 84 } 85 publicList.remove(download); 86 await download.finalize(true); 87 } 88 } 89 90 async function runTest(url, link, checkFunction, description) { 91 await resetDownloads(); 92 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); 93 is( 94 gBrowser.currentURI.schemeIs("https"), 95 true, 96 "Scheme of opened tab should be https" 97 ); 98 info("Checking: " + description); 99 100 let checkPromise = checkFunction(); 101 // Click the Link to trigger the download 102 SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { 103 content.document.getElementById(contentLink).click(); 104 }); 105 // Wait for the auth prompt, enter the login details and close the prompt 106 await PromptTestUtils.handleNextPrompt( 107 gBrowser.selectedBrowser, 108 { modalType: Ci.nsIPrompt.MODAL_TYPE_TAB, promptType: "promptUserAndPass" }, 109 { buttonNumClick: 0, loginInput: "user", passwordInput: "pass" } 110 ); 111 await checkPromise; 112 ok(true, description); 113 // Close download panel 114 DownloadsPanel.hidePanel(); 115 is(DownloadsPanel.panel.state, "closed", "Panel should be closed"); 116 await BrowserTestUtils.removeTab(tab); 117 } 118 119 add_setup(async function () { 120 let list = await Downloads.getList(Downloads.ALL); 121 list.addView(downloadMonitoringView); 122 registerCleanupFunction(() => list.removeView(downloadMonitoringView)); 123 // Ensure to delete all cached credentials before running test 124 await new Promise(resolve => { 125 Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve); 126 }); 127 await SpecialPowers.pushPrefEnv({ 128 set: [["dom.block_download_insecure", true]], 129 }); 130 }); 131 //Test description: 132 // 1. Open "https://example.com". 133 // 2. From "https://example.com" download something, but that download is only available via http 134 // and with authentication. 135 // 3. Login and start download. 136 // 4. Mixed-content blocker blocks download. 137 // 5. Unblock download and verify the downloaded file. 138 add_task(async function test_auth_download() { 139 await runTest( 140 SECURE_BASE_URL, 141 "insecure", 142 async () => { 143 let [, download] = await Promise.all([ 144 shouldTriggerDownload(), 145 shouldNotifyDownloadUI(), 146 ]); 147 await download.unblock(); 148 Assert.equal( 149 download.error, 150 null, 151 "There should be no error after unblocking" 152 ); 153 info( 154 "Start download to be able to validate the size and the success of the download" 155 ); 156 await download.start(); 157 is( 158 download.contentType, 159 "text/html", 160 "File contentType should be correct." 161 ); 162 ok(download.succeeded, "Download succeeded!"); 163 is(download.target.size, 27, "Download has correct size"); 164 }, 165 "A locked Download from an auth server should succeeded to Download after a Manual unblock" 166 ); 167 });