test_ext_native_messaging_permissions.js (5676B)
1 "use strict"; 2 3 const server = createHttpServer({ hosts: ["example.com"] }); 4 server.registerPathHandler("/dum", (request, response) => { 5 response.setStatusLine(request.httpVersion, 200, "OK"); 6 response.setHeader("Content-Type", "text/html; charset=utf-8", false); 7 response.write("<!DOCTYPE html><html></html>"); 8 }); 9 10 async function testNativeMessaging({ 11 isPrivileged = false, 12 permissions, 13 testBackground, 14 testContent, 15 }) { 16 async function runTest(testFn, completionMessage) { 17 try { 18 dump(`Running test before sending ${completionMessage}\n`); 19 await testFn(); 20 } catch (e) { 21 browser.test.fail(`Unexpected error: ${e}`); 22 } 23 browser.test.sendMessage(completionMessage); 24 } 25 const extension = ExtensionTestUtils.loadExtension({ 26 isPrivileged, 27 background: `(${runTest})(${testBackground}, "background_done");`, 28 manifest: { 29 content_scripts: [ 30 { 31 run_at: "document_end", 32 js: ["test.js"], 33 matches: ["http://example.com/dummy"], 34 }, 35 ], 36 permissions, 37 }, 38 files: { 39 "test.js": `(${runTest})(${testContent}, "content_done");`, 40 }, 41 }); 42 43 // Run background script. 44 await extension.startup(); 45 await extension.awaitMessage("background_done"); 46 47 // Run content script. 48 const page = await ExtensionTestUtils.loadContentPage( 49 "http://example.com/dummy" 50 ); 51 await extension.awaitMessage("content_done"); 52 await page.close(); 53 54 await extension.unload(); 55 } 56 57 // Checks that unprivileged extensions cannot use any of the nativeMessaging 58 // APIs on Android. 59 add_task(async function test_nativeMessaging_unprivileged() { 60 function testScript() { 61 browser.test.assertEq( 62 browser.runtime.connectNative, 63 undefined, 64 "connectNative should not be available in unprivileged extensions" 65 ); 66 browser.test.assertEq( 67 browser.runtime.sendNativeMessage, 68 undefined, 69 "sendNativeMessage should not be available in unprivileged extensions" 70 ); 71 } 72 73 const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { 74 await testNativeMessaging({ 75 isPrivileged: false, 76 permissions: [ 77 "geckoViewAddons", 78 "nativeMessaging", 79 "nativeMessagingFromContent", 80 ], 81 testBackground: testScript, 82 testContent: testScript, 83 }); 84 }); 85 AddonTestUtils.checkMessages(messages, { 86 expected: [ 87 { message: /Invalid extension permission: geckoViewAddons/ }, 88 { message: /Invalid extension permission: nativeMessaging/ }, 89 { message: /Invalid extension permission: nativeMessagingFromContent/ }, 90 ], 91 }); 92 }); 93 94 // Checks that privileged extensions can still not use native messaging without 95 // the geckoViewAddons permission. 96 add_task(async function test_geckoViewAddons_missing() { 97 const ERROR_NATIVE_MESSAGE_FROM_BACKGROUND = 98 "Native manifests are not supported on android"; 99 const ERROR_NATIVE_MESSAGE_FROM_CONTENT = 100 /^Native messaging not allowed: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\,"origin":"http:\/\/example\.com"}$/; 101 102 async function testBackground() { 103 await browser.test.assertRejects( 104 browser.runtime.sendNativeMessage("dummy_nativeApp", "DummyMsg"), 105 // Redacted error: ERROR_NATIVE_MESSAGE_FROM_BACKGROUND 106 "An unexpected error occurred", 107 "Background script cannot use nativeMessaging without geckoViewAddons" 108 ); 109 } 110 async function testContent() { 111 await browser.test.assertRejects( 112 browser.runtime.sendNativeMessage("dummy_nativeApp", "DummyMsg"), 113 // Redacted error: ERROR_NATIVE_MESSAGE_FROM_CONTENT 114 "An unexpected error occurred", 115 "Content script cannot use nativeMessaging without geckoViewAddons" 116 ); 117 } 118 119 const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { 120 await testNativeMessaging({ 121 isPrivileged: true, 122 permissions: ["nativeMessaging", "nativeMessagingFromContent"], 123 testBackground, 124 testContent, 125 }); 126 }); 127 AddonTestUtils.checkMessages(messages, { 128 expected: [ 129 { errorMessage: ERROR_NATIVE_MESSAGE_FROM_BACKGROUND }, 130 { errorMessage: ERROR_NATIVE_MESSAGE_FROM_CONTENT }, 131 ], 132 }); 133 }); 134 135 // Checks that privileged extensions cannot use native messaging from content 136 // without the nativeMessagingFromContent permission. 137 add_task(async function test_nativeMessagingFromContent_missing() { 138 const ERROR_NATIVE_MESSAGE_FROM_CONTENT_NO_PERM = 139 /^Unexpected messaging sender: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\,"origin":"http:\/\/example\.com"}$/; 140 function testBackground() { 141 // sendNativeMessage / connectNative are expected to succeed, but we 142 // are not testing that here because XpcshellTestRunnerService does not 143 // have a WebExtension.MessageDelegate that handles the message. 144 // There are plenty of mochitests that rely on connectNative, so we are 145 // not testing that here. 146 } 147 async function testContent() { 148 await browser.test.assertRejects( 149 browser.runtime.sendNativeMessage("dummy_nativeApp", "DummyMsg"), 150 // Redacted error: ERROR_NATIVE_MESSAGE_FROM_CONTENT_NO_PERM 151 "An unexpected error occurred", 152 "Trying to get through to native messaging but without luck" 153 ); 154 } 155 156 const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { 157 await testNativeMessaging({ 158 isPrivileged: true, 159 permissions: ["geckoViewAddons", "nativeMessaging"], 160 testBackground, 161 testContent, 162 }); 163 }); 164 AddonTestUtils.checkMessages(messages, { 165 expected: [{ errorMessage: ERROR_NATIVE_MESSAGE_FROM_CONTENT_NO_PERM }], 166 }); 167 });