getcredential-nested-frame.https.html (4336B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>WebAuthn credential.get() in a nested frame</title> 4 <link rel="help" href="https://w3c.github.io/webauthn/#publickey-credentials-create-feature"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/resources/testdriver.js"></script> 8 <script src="/resources/testdriver-vendor.js"></script> 9 <script src="/resources/common-inputs.js"></script> 10 <script src=helpers.js></script> 11 12 <body></body> 13 <script> 14 15 standardSetup(async function () { 16 "use strict"; 17 18 let credential; 19 function getCredentialScript() { 20 // Convert the credential ID into a string that can be safely embedded 21 // into our get assertion script. 22 // First, turn the buffer into a byte string. 23 const idBytes = String.fromCharCode(...new Uint8Array(credential.rawId)); 24 // Then, encode it into base64 so it can be safely embedded as a string. 25 const id = btoa(idBytes); 26 return ` 27 try { 28 // Reverse the process: decode the embedded string into a byte string. 29 const decoded = atob("${id}"); 30 // Then, copy each byte into a Uint8Array that we can pass to WebAuthn. 31 const id = Uint8Array.from([...decoded].map(c => c.charCodeAt())); 32 navigator.credentials.get({ 33 publicKey: { 34 challenge: Uint8Array.from([]), 35 allowCredentials: [{type: "public-key", id}], 36 userVerification: "discouraged", 37 } 38 }).then(c => window.parent.postMessage("OK", "*")) 39 .catch(e => window.parent.postMessage("Error: " + e.toString(), "*")); 40 } catch(e) { 41 window.parent.postMessage("Error: " + e.toString(), "*"); 42 } 43 `; 44 } 45 promise_test(async t => { 46 credential = await createCredential(); 47 }, "Setup: create a credential to test with"); 48 49 promise_test(async t => { 50 let frame = document.createElement("iframe"); 51 const loadPromise = new EventWatcher(t, frame, "load").wait_for("load"); 52 document.body.append(frame); 53 await loadPromise; 54 frame.contentWindow.location = "javascript:" + encodeURI(getCredentialScript()); 55 56 const messageWatcher = new EventWatcher(t, window, "message"); 57 const { data } = await messageWatcher.wait_for("message"); 58 assert_equals(data, "OK"); 59 }, "navigator.credentials.get({publicKey}) in a javascript url should should succeed."); 60 61 promise_test(async t => { 62 let frame = document.createElement("iframe"); 63 const loadPromise = new EventWatcher(t, frame, "load").wait_for("load"); 64 frame.srcdoc = ""; 65 document.body.append(frame); 66 await loadPromise; 67 frame.contentWindow.eval(getCredentialScript()); 68 69 const eventWatcher = new EventWatcher(t, window, "message"); 70 const { data } = await eventWatcher.wait_for("message"); 71 assert_equals(data, "OK"); 72 }, "navigator.credentials.get({publicKey}) in srcdoc should succeed."); 73 74 promise_test(async t => { 75 let frame = document.createElement("iframe"); 76 const loadPromise = new EventWatcher(t, frame, "load").wait_for("load"); 77 frame.src = "about:blank"; 78 document.body.append(frame); 79 await loadPromise; 80 frame.contentDocument.write("<script>" + getCredentialScript() + "<\/script>"); 81 82 const eventWatcher = new EventWatcher(t, window, "message"); 83 const { data } = await eventWatcher.wait_for("message"); 84 assert_equals(data, "OK"); 85 }, "navigator.credentials.get({publicKey}) in about:blank embedded in a secure context should succeed."); 86 87 promise_test(async t => { 88 let frame = document.createElement("iframe"); 89 const eventWatcher = new EventWatcher(t, window, "message"); 90 frame.src = "resources/webauthn-subframe.sub.html"; 91 document.body.append(frame); 92 assert_equals((await eventWatcher.wait_for("message")).data.type, "subframe-loaded"); 93 94 frame.contentWindow.postMessage({ type: "get-credential", addUserActivation: false }); 95 const { data } = await eventWatcher.wait_for("message"); 96 assert_equals(data.result, "success", "Error: " + data.error); 97 }, "navigator.credentials.get({publicKey}) in a same-origin frame should succeed without requiring user activation."); 98 99 }, { 100 protocol: "ctap2_1", 101 }); 102 </script>