utils.sub.js (6729B)
1 const PAYMENT_DETAILS = { 2 total: {label: 'Total', amount: {value: '0.01', currency: 'USD'}} 3 }; 4 const AUTHENTICATOR_OPTS = { 5 protocol: 'ctap2_1', 6 transport: 'internal', 7 hasResidentKey: true, 8 hasUserVerification: true, 9 isUserVerified: true, 10 }; 11 12 const ICON_URL = 'https://{{hosts[][www]}}:{{ports[https][0]}}/secure-payment-confirmation/troy.png'; 13 const NONEXISTENT_ICON_URL = 'https://{{hosts[][www]}}:{{ports[https][0]}}/secure-payment-confirmation/nonexistent.png'; 14 15 const ICON_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAUCAYAAADskT9PAAAAAXNSR0IArs4c6QAAA+lJREFUSEvtlmtQVGUYx3/n7I1dLgtSsIm4ss1EogM4Uanp6IeGqQ81Do0xECyWxKTkWAxDOkmCDYSOmUZjph8wyj7gTDT1oYnJC3ITYrSLkgMul1lCLsouugvs7tnd5pwJx6ZZ40NDfeg5H95z5rzzPv/n8v+/j2C1Wsubmpr26nQ6FQtoHo/Hn5mZWSmYTCbJ6XSqZmdnF9A96PV6jEajXzCbzcGhoaEFdT7nzGw28z+AkBmIioyguLCAXtsAX37zLcFg8B8vU8gSqFQiqSnLOXGkhkH7b+QV7USSJDRaDT6fhCAIqESRWY8HjSigFUU8gQAiAt5AAK1Wg0qlwu/34/X6lP06nVZZJZ+ET5KUYEICyFiVSumOIh6xWLjjcnHmQhtnW9rJ2fQ8Z1vbUKnUrExJpurAEfIS4ticEM9hm52Hw8M4OTRCbl4O6SnJ/HT1GsfrvyBx8UO8sa0Qg17HZ6e/or2z+/4ArNkvUJifTWR4BMNjo3R2/4hjcootuVncdk0jCkE6f+7hZt2nHEg2MyKIvHWlj/oUC7X2US6lpvP6ViujYzfJshbxZvGrvPjcMwwOj7J1Rym3Xa77AzAY9ByqKicjLZWyvdW0dHSxv3I3G9Y8wa+9NuobGhnp7+e75cswCAKbu69w3TXN92tXYdKoyR6+xa6DVQR9EiXl71K9p4xwg5491e9zrqX9bi+FLIFOp+N03VEWm+IpKC6hzzbAqU8+xGJOpKyyhjPNrcRpVfQ/u4HxGQ8Z57sQgMbVaayN1LP+hx62VVWSnLSU1o4uNq5bw8Xuy5S8vQ+P1/v3AIxRETTUHSM22khzRxefNzTy0f59+P0BNuUXMulwKo33cfqjFMQt4uWrNp56IJqC+BguuGbJar9Mbn4Or215iWAgiGPKyc5dFfT0Xv8Tk0JmQKNRU2TN5cnH0hHVao6fPMX2V/IZHZ+g9J0qhRGypRkjKU1K4OsJB9stS7jlclM7PEbzhIP1qx/n8HsVSmbOtV7kYO0xboxPzA+ATJfIiHCijVEIgojD6SR2UQwej1eJXvJLzMmCUaPGHwhiCtPi8PqwrFzBssQE0lNX8PTGdQwM2fng6AkmHVNc67PND4AoiiQtXYLBYFC4OzMzo/Da5Z5WgEAQr1dSKGqMivrj0CBut5uait2YHowlTKfD4bxDxf5DXPqlR9nj8/nmB0DepdFoFLGRHcvCISuhnE75W36XH7knRFFQQMqm1WgpLrQSYTBgH7nB+bYO+gftf3E878tIPlhxfM96bwhz8jwHQP4XE21UgHt9PtzT00iSP6SE/zduQ3kgmZqaUsl1Xki7O5D82yPZ7y210ZoMhOgBAAAAAElFTkSuQmCC'; 16 const INVALID_ICON_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAUCAYAAADskT9PAAAAAXNSR0IArs4c6QAAA+lJREFUSEvtlmtQVGUYx3/n7I1dLgtSsIm4ss1EogM4Uanp6IeGqQ81Do0xECyWxKTkWAxDOkmCDYSOmUZjph8wyj7gTDT1oYnJC3ITYrSLkgMul1lCLsouugvs7tnd5pwJx6ZZ40NDfeg5H95z5rzzPv/n8v+/j2C1Wsubmpr26nQ6FQtoHo/Hn5mZWSmYTCbJ6XSqZmdnF9A96PV6jEajXzCbzcGhoaEFdT7nzGw28z+AkBmIioyguLCAXtsAX37zLcFg8B8vU8gSqFQiqSnLOXGkhkH7b+QV7USSJDRaDT6fhCAIqESRWY8HjSigFUU8gQAiAt5AAK1Wg0qlwu/34/X6lP06nVZZJZ+ET5KUYEICyFiVSumOIh6xWLjjcnHmQhtnW9rJ2fQ8Z1vbUKnUrExJpurAEfIS4ticEM9hm52Hw8M4OTRCbl4O6SnJ/HT1GsfrvyBx8UO8sa0Qg17HZ6e/or2z+/4ArNkvUJifTWR4BMNjo3R2/4hjcootuVncdk0jCkE6f+7hZt2nHEg2MyKIvHWlj/oUC7X2US6lpvP6ViujYzfJshbxZvGrvPjcThisIsNonsenseG9Y8wa+9NuobGhnp7+e75cswCAKbu69w3TXN92tXYdKoyR6+xa6DVQR9EiXl71K9p4xwg5491e9zrqX9bi+FLIFOp+N03VEWm+IpKC6hzzbAqU8+xGJOpKyyhjPNrcRpVfQ/u4HxGQ8Z57sQgMbVaayN1LP+hx62VVWSnLSU1o4uNq5bw8Xuy5S8vQ+P1/v3AIxRETTUHSM22khzRxefNzTy0f59+P0BNuUXMulwKo33cfqjFMQt4uWrNp56IJqC+BguuGbJar9Mbn4Or215iWAgiGPKyc5dFfT0Xv8Tk0JmQKNRU2TN5cnH0hHVao6fPMX2V/IZHZ+g9J0qhRGypRkjKU1K4OsJB9stS7jlclM7PEbzhIP1qx/n8HsVSmbOtV7kYO0xboxPzA+ATJfIiHCijVEIgojD6SR2UQwej1eJXvJLzMmCUaPGHwhiCtPi8PqwrFzBssQE0lNX8PTGdQwM2fng6AkmHVNc67PND4AoiiQtXYLBYFC4OzMzo/Da5Z5WgEAQr1dSKGqMivrj0CBut5uait2YHowlTKfD4bxDxf5DXPqlR9nj8/nmB0DepdFoFLGRHcvCISuhnE75W36XH7knRFFQQMqm1WgpLrQSYTBgH7nB+bYO+gftf3E878tIPlhxfM96bwhz8jwHQP4XE21UgHt9PtzT00iSP6SE/zduQ3kgmZqaUsl1Xki7O5D82yPZ7y210ZoMhOgBAAAAAElFTkSuQmCC'; 17 18 const PAYMENT_ENTITY_LOGO_URL = 'https://{{hosts[][www]}}:{{ports[https][0]}}/secure-payment-confirmation/sync-network-logo.png'; 19 const NONEXISTENT_PAYMENT_ENTITY_LOGO_URL = 'https://{{hosts[][www]}}:{{ports[https][0]}}/secure-payment-confirmation/nonexistent.png'; 20 21 // Creates and returns a WebAuthn credential, optionally with the payment 22 // extension set. 23 // 24 // `options` is object containing additional options for creating the request. 25 // The options include the following: 26 // 27 // * "browserBoundPubKeyCredParams": The credential creation parameters to set 28 // on the payment extension. set_payment_extension must be set to true in 29 // order for this option to apply. 30 // 31 // Assumes that a virtual authenticator has already been created. 32 async function createCredential(set_payment_extension = true, options = {}) { 33 options = Object.assign({browserBoundPubKeyCredParams: []}, options); 34 const challengeBytes = new Uint8Array(16); 35 window.crypto.getRandomValues(challengeBytes); 36 37 const publicKey = { 38 challenge: challengeBytes, 39 rp: { 40 name: 'Acme', 41 }, 42 user: { 43 id: new Uint8Array(16), 44 name: 'jane.doe@example.com', 45 displayName: 'Jane Doe', 46 }, 47 pubKeyCredParams: [{ 48 type: 'public-key', 49 alg: -7, // 'ES256' 50 }], 51 authenticatorSelection: { 52 userVerification: 'required', 53 residentKey: 'required', 54 authenticatorAttachment: 'platform', 55 }, 56 timeout: 30000, 57 }; 58 59 if (set_payment_extension) { 60 publicKey.extensions = { 61 payment: { 62 isPayment: true, 63 browserBoundPubKeyCredParams: options.browserBoundPubKeyCredParams 64 }, 65 }; 66 } 67 68 return navigator.credentials.create({publicKey}); 69 } 70 71 // Creates a SPC credential in an iframe for the WPT 'alt' domain. Returns a 72 // promise that resolves with the created credential id. 73 // 74 // Assumes that a virtual authenticator has already been created. 75 async function createCredentialForAltDomain() { 76 const frame = document.createElement('iframe'); 77 frame.allow = 'payment'; 78 frame.src = 'https://{{hosts[alt][]}}:{{ports[https][0]}}' + 79 '/secure-payment-confirmation/resources/iframe-enroll.html'; 80 81 // Wait for the iframe to load. 82 const readyPromise = new Promise(resolve => { 83 window.addEventListener('message', function handler(evt) { 84 if (evt.source === frame.contentWindow && evt.data.type == 'loaded') { 85 window.removeEventListener('message', handler); 86 87 resolve(evt.data); 88 } 89 }); 90 }); 91 document.body.appendChild(frame); 92 await readyPromise; 93 94 // Setup the result promise, and then trigger credential creation. 95 const resultPromise = new Promise(resolve => { 96 window.addEventListener('message', function handler(evt) { 97 if (evt.source === frame.contentWindow && evt.data.type == 'spc_result') { 98 document.body.removeChild(frame); 99 window.removeEventListener('message', handler); 100 101 resolve(evt.data); 102 } 103 }); 104 }); 105 frame.contentWindow.postMessage({ userActivation: true }, '*'); 106 return resultPromise; 107 } 108 109 function arrayBufferToString(buffer) { 110 return String.fromCharCode(...new Uint8Array(buffer)); 111 } 112 113 function base64UrlEncode(data) { 114 let result = btoa(data); 115 return result.replace(/=+$/g, '').replace(/\+/g, "-").replace(/\//g, "_"); 116 }