common.js (4688B)
1 const executor_path = '/common/dispatcher/executor.html?pipe='; 2 const executor_worker_path = '/common/dispatcher/executor-worker.js?pipe='; 3 const executor_service_worker_path = '/common/dispatcher/executor-service-worker.js?pipe='; 4 5 // COEP 6 const coep_none = 7 '|header(Cross-Origin-Embedder-Policy,none)'; 8 const coep_credentialless = 9 '|header(Cross-Origin-Embedder-Policy,credentialless)'; 10 const coep_require_corp = 11 '|header(Cross-Origin-Embedder-Policy,require-corp)'; 12 13 // COEP-Report-Only 14 const coep_report_only_credentialless = 15 '|header(Cross-Origin-Embedder-Policy-Report-Only,credentialless)'; 16 17 // COOP 18 const coop_same_origin = 19 '|header(Cross-Origin-Opener-Policy,same-origin)'; 20 21 // CORP 22 const corp_cross_origin = 23 '|header(Cross-Origin-Resource-Policy,cross-origin)'; 24 25 const cookie_same_site_none = ';SameSite=None;Secure'; 26 27 // Test using the modern async/await primitives are easier to read/write. 28 // However they run sequentially, contrary to async_test. This is the parallel 29 // version, to avoid timing out. 30 let promise_test_parallel = (promise, description) => { 31 async_test(test => { 32 promise(test) 33 .then(() => test.done()) 34 .catch(test.step_func(error => { throw error; })); 35 }, description); 36 }; 37 38 // Add a cookie |cookie_key|=|cookie_value| on an |origin|. 39 // Note: cookies visibility depends on the path of the document. Those are set 40 // from a document from: /html/cross-origin-embedder-policy/credentialless/. So 41 // the cookie is visible to every path underneath. 42 const setCookie = async (origin, cookie_key, cookie_value) => { 43 const popup_token = token(); 44 const popup_url = origin + executor_path + `&uuid=${popup_token}`; 45 const popup = window.open(popup_url); 46 47 const reply_token = token(); 48 send(popup_token, ` 49 document.cookie = "${cookie_key}=${cookie_value}"; 50 send("${reply_token}", "done"); 51 `); 52 assert_equals(await receive(reply_token), "done"); 53 popup.close(); 54 } 55 56 let parseCookies = function(headers_json) { 57 if (!headers_json["cookie"]) 58 return {}; 59 60 return headers_json["cookie"] 61 .split(';') 62 .map(v => v.split('=')) 63 .reduce((acc, v) => { 64 acc[v[0].trim()] = v[1].trim(); 65 return acc; 66 }, {}); 67 } 68 69 // Open a new window with a given |origin|, loaded with COEP:credentialless. The 70 // new document will execute any scripts sent toward the token it returns. 71 const newCredentiallessWindow = (origin) => { 72 const main_document_token = token(); 73 const url = origin + executor_path + coep_credentialless + 74 `&uuid=${main_document_token}`; 75 const context = window.open(url); 76 add_completion_callback(() => w.close()); 77 return main_document_token; 78 }; 79 80 // Create a new iframe, loaded with COEP:credentialless. 81 // The new document will execute any scripts sent toward the token it returns. 82 const newCredentiallessIframe = (parent_token, child_origin) => { 83 const sub_document_token = token(); 84 const iframe_url = child_origin + executor_path + coep_credentialless + 85 `&uuid=${sub_document_token}`; 86 send(parent_token, ` 87 let iframe = document.createElement("iframe"); 88 iframe.src = "${iframe_url}"; 89 document.body.appendChild(iframe); 90 `) 91 return sub_document_token; 92 }; 93 94 // A common interface for building the 4 type of execution contexts: 95 // It outputs: [ 96 // - The token to communicate with the environment. 97 // - A promise resolved when the environment encounters an error. 98 // ] 99 const environments = { 100 document: headers => { 101 const tok = token(); 102 const url = window.origin + executor_path + headers + `&uuid=${tok}`; 103 const context = window.open(url); 104 add_completion_callback(() => context.close()); 105 return [tok, new Promise(resolve => {})]; 106 }, 107 108 dedicated_worker: headers => { 109 const tok = token(); 110 const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`; 111 const context = new Worker(url); 112 return [tok, new Promise(resolve => context.onerror = resolve)]; 113 }, 114 115 shared_worker: headers => { 116 const tok = token(); 117 const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`; 118 const context = new SharedWorker(url); 119 return [tok, new Promise(resolve => context.onerror = resolve)]; 120 }, 121 122 service_worker: headers => { 123 const tok = token(); 124 const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`; 125 const scope = url; // Generate a one-time scope for service worker. 126 const error = new Promise(resolve => { 127 navigator.serviceWorker.register(url, {scope: scope}) 128 .then(registration => { 129 add_completion_callback(() => registration.unregister()); 130 }, /* catch */ resolve); 131 }); 132 return [tok, error]; 133 }, 134 };