U2f.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. <template>
  2. <main>
  3. <h1 class="text-3xl font-bold">
  4. Universal 2-Factor Authentication
  5. </h1>
  6. <div class="main container">
  7. <div class="main row">
  8. <div class="twelve columns">
  9. <h1>U2F Test Page</h1>
  10. <p>
  11. Made by <a href="https://sagen.me/">Alexander Sagen</a>, using code from <a href="https://github.com/ashtuchkin/u2f">ashtuchkin/u2f</a> and <a href="https://github.com/google/u2f-ref-code">google/u2f-ref-code</a>. Styled with <a href="http://getskeleton.com/">Skeleton</a>.
  12. </p>
  13. </div>
  14. </div>
  15. <div class="row">
  16. <div class="twelve columns">
  17. <button @click="handleRequestClick">Generate Request</button>
  18. </div>
  19. </div>
  20. <div class="row">
  21. <div class="twelve columns">
  22. <label for="request">Request</label>
  23. <textarea @change="handleRequestChange" class="u-full-width"></textarea>
  24. </div>
  25. </div>
  26. <div class="row">
  27. <div class="six columns">
  28. <label for="reqAppId">appId</label>
  29. <input class="u-full-width" type="text" id="reqAppId" readonly="">
  30. </div>
  31. <div class="six columns">
  32. <label for="reqKeyHandle">keyHandle</label>
  33. <input class="u-full-width" type="text" id="reqKeyHandle">
  34. </div>
  35. </div>
  36. <div class="row">
  37. <div class="twelve columns">
  38. <button id="btnSign">Sign</button>
  39. <button id="btnRegister">Register</button>
  40. </div>
  41. </div>
  42. <div class="row">
  43. <div class="twelve columns">
  44. <label for="response">Response</label>
  45. <textarea class="u-full-width" id="response" readonly=""></textarea>
  46. </div>
  47. </div>
  48. <div class="row">
  49. <div class="six columns">
  50. <label for="resKeyHandle">keyHandle</label>
  51. <input class="u-full-width" type="text" id="resKeyHandle" readonly="">
  52. </div>
  53. <div class="six columns">
  54. <label for="resPublicKey">publicKey</label>
  55. <input class="u-full-width" type="text" id="resPublicKey" readonly="">
  56. </div>
  57. </div>
  58. <div class="row">
  59. <div class="twelve columns">
  60. <label for="resCertificate">certificate</label>
  61. <input class="u-full-width" type="text" id="resCertificate" readonly="">
  62. </div>
  63. </div>
  64. </div>
  65. </main>
  66. </template>
  67. <script>
  68. /* global chrome */
  69. /**
  70. * This page was sourced from:
  71. * https://alexander.sagen.me/u2f-test-page/
  72. */
  73. /* Import components. */
  74. // import UnderConstruction from '@/components/UnderConstruction'
  75. // export default {
  76. // components: {
  77. // // UnderConstruction,
  78. // },
  79. // data: () => {
  80. // return {
  81. // //
  82. // }
  83. // },
  84. // computed: {
  85. // //
  86. // },
  87. // methods: {
  88. // handleRequestClick() {
  89. // const challenge = new Uint8Array(32)
  90. //
  91. // crypto.getRandomValues(challenge)
  92. //
  93. // request.value = JSON.stringify({
  94. // version: 'U2F_V2',
  95. // appId: location.origin,
  96. // keyHandle: reqKeyHandle.value || undefined,
  97. // challenge: B64_encode(challenge),
  98. // })
  99. //
  100. // },
  101. //
  102. // handleRequestChange(_request) {
  103. // try {
  104. // const value = JSON.parse(_request.value)
  105. //
  106. // if (value.appId != location.origin) {
  107. // _request.value = ''
  108. //
  109. // console.error("Invalid appId in request, either generate one here or use the appId specified on this page when generating one");
  110. // }
  111. // } catch (e) {
  112. // console.error(e);
  113. // _request.value = ''
  114. // console.error("Invalid JSON input for request");
  115. // }
  116. // },
  117. //
  118. // },
  119. // created: async function () {
  120. //
  121. // //Copyright 2014-2015 Google Inc. All rights reserved.
  122. //
  123. // //Use of this source code is governed by a BSD-style
  124. // //license that can be found in the LICENSE file or at
  125. // //https://developers.google.com/open-source/licenses/bsd
  126. //
  127. // var u2f = u2f || {};
  128. //
  129. // /**
  130. // * FIDO U2F Javascript API Version
  131. // * @number
  132. // */
  133. // var js_api_version;
  134. //
  135. // /**
  136. // * The U2F extension id
  137. // * @const {string}
  138. // */
  139. // // The Chrome packaged app extension ID.
  140. // // Uncomment this if you want to deploy a server instance that uses
  141. // // the package Chrome app and does not require installing the U2F Chrome extension.
  142. // u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
  143. // // The U2F Chrome extension ID.
  144. // // Uncomment this if you want to deploy a server instance that uses
  145. // // the U2F Chrome extension to authenticate.
  146. // // u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
  147. //
  148. //
  149. // /**
  150. // * Message types for messsages to/from the extension
  151. // * @const
  152. // * @enum {string}
  153. // */
  154. // u2f.MessageTypes = {
  155. // 'U2F_REGISTER_REQUEST': 'u2f_register_request',
  156. // 'U2F_REGISTER_RESPONSE': 'u2f_register_response',
  157. // 'U2F_SIGN_REQUEST': 'u2f_sign_request',
  158. // 'U2F_SIGN_RESPONSE': 'u2f_sign_response',
  159. // 'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
  160. // 'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
  161. // };
  162. //
  163. //
  164. // /**
  165. // * Response status codes
  166. // * @const
  167. // * @enum {number}
  168. // */
  169. // u2f.ErrorCodes = {
  170. // 'OK': 0,
  171. // 'OTHER_ERROR': 1,
  172. // 'BAD_REQUEST': 2,
  173. // 'CONFIGURATION_UNSUPPORTED': 3,
  174. // 'DEVICE_INELIGIBLE': 4,
  175. // 'TIMEOUT': 5
  176. // };
  177. //
  178. //
  179. // /**
  180. // * A message for registration requests
  181. // * @typedef {{
  182. // * type: u2f.MessageTypes,
  183. // * appId: ?string,
  184. // * timeoutSeconds: ?number,
  185. // * requestId: ?number
  186. // * }}
  187. // */
  188. // u2f.U2fRequest;
  189. //
  190. //
  191. // /**
  192. // * A message for registration responses
  193. // * @typedef {{
  194. // * type: u2f.MessageTypes,
  195. // * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
  196. // * requestId: ?number
  197. // * }}
  198. // */
  199. // u2f.U2fResponse;
  200. //
  201. //
  202. // /**
  203. // * An error object for responses
  204. // * @typedef {{
  205. // * errorCode: u2f.ErrorCodes,
  206. // * errorMessage: ?string
  207. // * }}
  208. // */
  209. // u2f.Error;
  210. //
  211. // /**
  212. // * Data object for a single sign request.
  213. // * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
  214. // */
  215. // u2f.Transport;
  216. //
  217. //
  218. // /**
  219. // * Data object for a single sign request.
  220. // * @typedef {Array<u2f.Transport>}
  221. // */
  222. // u2f.Transports;
  223. //
  224. // /**
  225. // * Data object for a single sign request.
  226. // * @typedef {{
  227. // * version: string,
  228. // * challenge: string,
  229. // * keyHandle: string,
  230. // * appId: string
  231. // * }}
  232. // */
  233. // u2f.SignRequest;
  234. //
  235. //
  236. // /**
  237. // * Data object for a sign response.
  238. // * @typedef {{
  239. // * keyHandle: string,
  240. // * signatureData: string,
  241. // * clientData: string
  242. // * }}
  243. // */
  244. // u2f.SignResponse;
  245. //
  246. //
  247. // /**
  248. // * Data object for a registration request.
  249. // * @typedef {{
  250. // * version: string,
  251. // * challenge: string
  252. // * }}
  253. // */
  254. // u2f.RegisterRequest;
  255. //
  256. //
  257. // /**
  258. // * Data object for a registration response.
  259. // * @typedef {{
  260. // * version: string,
  261. // * keyHandle: string,
  262. // * transports: Transports,
  263. // * appId: string
  264. // * }}
  265. // */
  266. // u2f.RegisterResponse;
  267. //
  268. //
  269. // /**
  270. // * Data object for a registered key.
  271. // * @typedef {{
  272. // * version: string,
  273. // * keyHandle: string,
  274. // * transports: ?Transports,
  275. // * appId: ?string
  276. // * }}
  277. // */
  278. // u2f.RegisteredKey;
  279. //
  280. //
  281. // /**
  282. // * Data object for a get API register response.
  283. // * @typedef {{
  284. // * js_api_version: number
  285. // * }}
  286. // */
  287. // u2f.GetJsApiVersionResponse;
  288. //
  289. //
  290. // //Low level MessagePort API support
  291. //
  292. // /**
  293. // * Sets up a MessagePort to the U2F extension using the
  294. // * available mechanisms.
  295. // * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
  296. // */
  297. // u2f.getMessagePort = function(callback) {
  298. // if (typeof chrome != 'undefined' && chrome.runtime) {
  299. // // The actual message here does not matter, but we need to get a reply
  300. // // for the callback to run. Thus, send an empty signature request
  301. // // in order to get a failure response.
  302. // var msg = {
  303. // type: u2f.MessageTypes.U2F_SIGN_REQUEST,
  304. // signRequests: []
  305. // };
  306. // chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
  307. // if (!chrome.runtime.lastError) {
  308. // // We are on a whitelisted origin and can talk directly
  309. // // with the extension.
  310. // u2f.getChromeRuntimePort_(callback);
  311. // } else {
  312. // // chrome.runtime was available, but we couldn't message
  313. // // the extension directly, use iframe
  314. // u2f.getIframePort_(callback);
  315. // }
  316. // });
  317. // } else if (u2f.isAndroidChrome_()) {
  318. // u2f.getAuthenticatorPort_(callback);
  319. // } else if (u2f.isIosChrome_()) {
  320. // u2f.getIosPort_(callback);
  321. // } else {
  322. // // chrome.runtime was not available at all, which is normal
  323. // // when this origin doesn't have access to any extensions.
  324. // u2f.getIframePort_(callback);
  325. // }
  326. // };
  327. //
  328. // /**
  329. // * Detect chrome running on android based on the browser's useragent.
  330. // * @private
  331. // */
  332. // u2f.isAndroidChrome_ = function() {
  333. // var userAgent = navigator.userAgent;
  334. // return userAgent.indexOf('Chrome') != -1 &&
  335. // userAgent.indexOf('Android') != -1;
  336. // };
  337. //
  338. // /**
  339. // * Detect chrome running on iOS based on the browser's platform.
  340. // * @private
  341. // */
  342. // u2f.isIosChrome_ = function() {
  343. // return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
  344. // };
  345. //
  346. // /**
  347. // * Connects directly to the extension via chrome.runtime.connect.
  348. // * @param {function(u2f.WrappedChromeRuntimePort_)} callback
  349. // * @private
  350. // */
  351. // u2f.getChromeRuntimePort_ = function(callback) {
  352. // var port = chrome.runtime.connect(u2f.EXTENSION_ID,
  353. // {'includeTlsChannelId': true});
  354. // setTimeout(function() {
  355. // callback(new u2f.WrappedChromeRuntimePort_(port));
  356. // }, 0);
  357. // };
  358. //
  359. // /**
  360. // * Return a 'port' abstraction to the Authenticator app.
  361. // * @param {function(u2f.WrappedAuthenticatorPort_)} callback
  362. // * @private
  363. // */
  364. // u2f.getAuthenticatorPort_ = function(callback) {
  365. // setTimeout(function() {
  366. // callback(new u2f.WrappedAuthenticatorPort_());
  367. // }, 0);
  368. // };
  369. //
  370. // /**
  371. // * Return a 'port' abstraction to the iOS client app.
  372. // * @param {function(u2f.WrappedIosPort_)} callback
  373. // * @private
  374. // */
  375. // u2f.getIosPort_ = function(callback) {
  376. // setTimeout(function() {
  377. // callback(new u2f.WrappedIosPort_());
  378. // }, 0);
  379. // };
  380. //
  381. // /**
  382. // * A wrapper for chrome.runtime.Port that is compatible with MessagePort.
  383. // * @param {Port} port
  384. // * @constructor
  385. // * @private
  386. // */
  387. // u2f.WrappedChromeRuntimePort_ = function(port) {
  388. // this.port_ = port;
  389. // };
  390. //
  391. // /**
  392. // * Format and return a sign request compliant with the JS API version supported by the extension.
  393. // * @param {Array<u2f.SignRequest>} signRequests
  394. // * @param {number} timeoutSeconds
  395. // * @param {number} reqId
  396. // * @return {Object}
  397. // */
  398. // u2f.formatSignRequest_ =
  399. // function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
  400. // if (js_api_version === undefined || js_api_version < 1.1) {
  401. // // Adapt request to the 1.0 JS API
  402. // var signRequests = [];
  403. // for (let i = 0; i < registeredKeys.length; i++) {
  404. // signRequests[i] = {
  405. // version: registeredKeys[i].version,
  406. // challenge: challenge,
  407. // keyHandle: registeredKeys[i].keyHandle,
  408. // appId: appId
  409. // };
  410. // }
  411. // return {
  412. // type: u2f.MessageTypes.U2F_SIGN_REQUEST,
  413. // signRequests: signRequests,
  414. // timeoutSeconds: timeoutSeconds,
  415. // requestId: reqId
  416. // };
  417. // }
  418. // // JS 1.1 API
  419. // return {
  420. // type: u2f.MessageTypes.U2F_SIGN_REQUEST,
  421. // appId: appId,
  422. // challenge: challenge,
  423. // registeredKeys: registeredKeys,
  424. // timeoutSeconds: timeoutSeconds,
  425. // requestId: reqId
  426. // };
  427. // };
  428. //
  429. // /**
  430. // * Format and return a register request compliant with the JS API version supported by the extension..
  431. // * @param {Array<u2f.SignRequest>} signRequests
  432. // * @param {Array<u2f.RegisterRequest>} signRequests
  433. // * @param {number} timeoutSeconds
  434. // * @param {number} reqId
  435. // * @return {Object}
  436. // */
  437. // u2f.formatRegisterRequest_ =
  438. // function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
  439. // if (js_api_version === undefined || js_api_version < 1.1) {
  440. // // Adapt request to the 1.0 JS API
  441. // for (let i = 0; i < registerRequests.length; i++) {
  442. // registerRequests[i].appId = appId;
  443. // }
  444. // var signRequests = [];
  445. // for (let i = 0; i < registeredKeys.length; i++) {
  446. // signRequests[i] = {
  447. // version: registeredKeys[i].version,
  448. // challenge: registerRequests[0],
  449. // keyHandle: registeredKeys[i].keyHandle,
  450. // appId: appId
  451. // };
  452. // }
  453. // return {
  454. // type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
  455. // signRequests: signRequests,
  456. // registerRequests: registerRequests,
  457. // timeoutSeconds: timeoutSeconds,
  458. // requestId: reqId
  459. // };
  460. // }
  461. // // JS 1.1 API
  462. // return {
  463. // type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
  464. // appId: appId,
  465. // registerRequests: registerRequests,
  466. // registeredKeys: registeredKeys,
  467. // timeoutSeconds: timeoutSeconds,
  468. // requestId: reqId
  469. // };
  470. // };
  471. //
  472. //
  473. // /**
  474. // * Posts a message on the underlying channel.
  475. // * @param {Object} message
  476. // */
  477. // u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
  478. // this.port_.postMessage(message);
  479. // };
  480. //
  481. //
  482. // /**
  483. // * Emulates the HTML 5 addEventListener interface. Works only for the
  484. // * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
  485. // * @param {string} eventName
  486. // * @param {function({data: Object})} handler
  487. // */
  488. // u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
  489. // function(eventName, handler) {
  490. // var name = eventName.toLowerCase();
  491. // if (name == 'message' || name == 'onmessage') {
  492. // this.port_.onMessage.addListener(function(message) {
  493. // // Emulate a minimal MessageEvent object
  494. // handler({'data': message});
  495. // });
  496. // } else {
  497. // console.error('WrappedChromeRuntimePort only supports onMessage');
  498. // }
  499. // };
  500. //
  501. // /**
  502. // * Wrap the Authenticator app with a MessagePort interface.
  503. // * @constructor
  504. // * @private
  505. // */
  506. // u2f.WrappedAuthenticatorPort_ = function() {
  507. // this.requestId_ = -1;
  508. // this.requestObject_ = null;
  509. // }
  510. //
  511. // /**
  512. // * Launch the Authenticator intent.
  513. // * @param {Object} message
  514. // */
  515. // u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
  516. // var intentUrl =
  517. // u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
  518. // ';S.request=' + encodeURIComponent(JSON.stringify(message)) +
  519. // ';end';
  520. // document.location = intentUrl;
  521. // };
  522. //
  523. // /**
  524. // * Tells what type of port this is.
  525. // * @return {String} port type
  526. // */
  527. // u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
  528. // return "WrappedAuthenticatorPort_";
  529. // };
  530. //
  531. //
  532. // /**
  533. // * Emulates the HTML 5 addEventListener interface.
  534. // * @param {string} eventName
  535. // * @param {function({data: Object})} handler
  536. // */
  537. // u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
  538. // var name = eventName.toLowerCase();
  539. // if (name == 'message') {
  540. // var self = this;
  541. // /* Register a callback to that executes when
  542. // * chrome injects the response. */
  543. // window.addEventListener(
  544. // 'message', self.onRequestUpdate_.bind(self, handler), false);
  545. // } else {
  546. // console.error('WrappedAuthenticatorPort only supports message');
  547. // }
  548. // };
  549. //
  550. // /**
  551. // * Callback invoked when a response is received from the Authenticator.
  552. // * @param function({data: Object}) callback
  553. // * @param {Object} message message Object
  554. // */
  555. // u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
  556. // function(callback, message) {
  557. // var messageObject = JSON.parse(message.data);
  558. // // var intentUrl = messageObject['intentURL'];
  559. //
  560. // // var errorCode = messageObject['errorCode'];
  561. // var responseObject = null;
  562. // if (messageObject.hasOwnProperty('data')) { // eslint-disable-line no-prototype-builtins
  563. // responseObject = /** @type {Object} */ (
  564. // JSON.parse(messageObject['data']));
  565. // }
  566. //
  567. // callback({'data': responseObject});
  568. // };
  569. //
  570. // /**
  571. // * Base URL for intents to Authenticator.
  572. // * @const
  573. // * @private
  574. // */
  575. // u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
  576. // 'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
  577. //
  578. // /**
  579. // * Wrap the iOS client app with a MessagePort interface.
  580. // * @constructor
  581. // * @private
  582. // */
  583. // u2f.WrappedIosPort_ = function() {};
  584. //
  585. // /**
  586. // * Launch the iOS client app request
  587. // * @param {Object} message
  588. // */
  589. // u2f.WrappedIosPort_.prototype.postMessage = function(message) {
  590. // var str = JSON.stringify(message);
  591. // var url = "u2f://auth?" + encodeURI(str);
  592. // location.replace(url);
  593. // };
  594. //
  595. // /**
  596. // * Tells what type of port this is.
  597. // * @return {String} port type
  598. // */
  599. // u2f.WrappedIosPort_.prototype.getPortType = function() {
  600. // return "WrappedIosPort_";
  601. // };
  602. //
  603. // /**
  604. // * Emulates the HTML 5 addEventListener interface.
  605. // * @param {string} eventName
  606. // * @param {function({data: Object})} handler
  607. // */
  608. // u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
  609. // console.log('handler', handler);
  610. // var name = eventName.toLowerCase();
  611. // if (name !== 'message') {
  612. // console.error('WrappedIosPort only supports message');
  613. // }
  614. // };
  615. //
  616. // /**
  617. // * Sets up an embedded trampoline iframe, sourced from the extension.
  618. // * @param {function(MessagePort)} callback
  619. // * @private
  620. // */
  621. // u2f.getIframePort_ = function(callback) {
  622. // // Create the iframe
  623. // var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
  624. // var iframe = document.createElement('iframe');
  625. // iframe.src = iframeOrigin + '/u2f-comms.html';
  626. // iframe.setAttribute('style', 'display:none');
  627. // document.body.appendChild(iframe);
  628. //
  629. // var channel = new MessageChannel();
  630. // var ready = function(message) {
  631. // if (message.data == 'ready') {
  632. // channel.port1.removeEventListener('message', ready);
  633. // callback(channel.port1);
  634. // } else {
  635. // console.error('First event on iframe port was not "ready"');
  636. // }
  637. // };
  638. // channel.port1.addEventListener('message', ready);
  639. // channel.port1.start();
  640. //
  641. // iframe.addEventListener('load', function() {
  642. // // Deliver the port to the iframe and initialize
  643. // iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
  644. // });
  645. // };
  646. //
  647. //
  648. //
  649. // //High-level JS API
  650. //
  651. // /**
  652. // * Default extension response timeout in seconds.
  653. // * @const
  654. // */
  655. // u2f.EXTENSION_TIMEOUT_SEC = 30;
  656. //
  657. // /**
  658. // * A singleton instance for a MessagePort to the extension.
  659. // * @type {MessagePort|u2f.WrappedChromeRuntimePort_}
  660. // * @private
  661. // */
  662. // u2f.port_ = null;
  663. //
  664. // /**
  665. // * Callbacks waiting for a port
  666. // * @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
  667. // * @private
  668. // */
  669. // u2f.waitingForPort_ = [];
  670. //
  671. // /**
  672. // * A counter for requestIds.
  673. // * @type {number}
  674. // * @private
  675. // */
  676. // u2f.reqCounter_ = 0;
  677. //
  678. // /**
  679. // * A map from requestIds to client callbacks
  680. // * @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
  681. // * |function((u2f.Error|u2f.SignResponse)))>}
  682. // * @private
  683. // */
  684. // u2f.callbackMap_ = {};
  685. //
  686. // /**
  687. // * Creates or retrieves the MessagePort singleton to use.
  688. // * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
  689. // * @private
  690. // */
  691. // u2f.getPortSingleton_ = function(callback) {
  692. // if (u2f.port_) {
  693. // callback(u2f.port_);
  694. // } else {
  695. // if (u2f.waitingForPort_.length == 0) {
  696. // u2f.getMessagePort(function(port) {
  697. // u2f.port_ = port;
  698. // u2f.port_.addEventListener('message',
  699. // /** @type {function(Event)} */ (u2f.responseHandler_));
  700. //
  701. // // Careful, here be async callbacks. Maybe.
  702. // while (u2f.waitingForPort_.length)
  703. // u2f.waitingForPort_.shift()(u2f.port_);
  704. // });
  705. // }
  706. // u2f.waitingForPort_.push(callback);
  707. // }
  708. // };
  709. //
  710. // /**
  711. // * Handles response messages from the extension.
  712. // * @param {MessageEvent.<u2f.Response>} message
  713. // * @private
  714. // */
  715. // u2f.responseHandler_ = function(message) {
  716. // var response = message.data;
  717. // var reqId = response['requestId'];
  718. // if (!reqId || !u2f.callbackMap_[reqId]) {
  719. // console.error('Unknown or missing requestId in response.');
  720. // return;
  721. // }
  722. // var cb = u2f.callbackMap_[reqId];
  723. // delete u2f.callbackMap_[reqId];
  724. // cb(response['responseData']);
  725. // };
  726. //
  727. // /**
  728. // * Dispatches an array of sign requests to available U2F tokens.
  729. // * If the JS API version supported by the extension is unknown, it first sends a
  730. // * message to the extension to find out the supported API version and then it sends
  731. // * the sign request.
  732. // * @param {string=} appId
  733. // * @param {string=} challenge
  734. // * @param {Array<u2f.RegisteredKey>} registeredKeys
  735. // * @param {function((u2f.Error|u2f.SignResponse))} callback
  736. // * @param {number=} opt_timeoutSeconds
  737. // */
  738. // u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
  739. // if (js_api_version === undefined) {
  740. // // Send a message to get the extension to JS API version, then send the actual sign request.
  741. // u2f.getApiVersion(
  742. // function (response) {
  743. // js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
  744. // console.log("Extension JS API Version: ", js_api_version);
  745. // u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
  746. // });
  747. // } else {
  748. // // We know the JS API version. Send the actual sign request in the supported API version.
  749. // u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
  750. // }
  751. // };
  752. //
  753. // /**
  754. // * Dispatches an array of sign requests to available U2F tokens.
  755. // * @param {string=} appId
  756. // * @param {string=} challenge
  757. // * @param {Array<u2f.RegisteredKey>} registeredKeys
  758. // * @param {function((u2f.Error|u2f.SignResponse))} callback
  759. // * @param {number=} opt_timeoutSeconds
  760. // */
  761. // u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
  762. // u2f.getPortSingleton_(function(port) {
  763. // var reqId = ++u2f.reqCounter_;
  764. // u2f.callbackMap_[reqId] = callback;
  765. // var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
  766. // opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
  767. // var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
  768. // port.postMessage(req);
  769. // });
  770. // };
  771. //
  772. // /**
  773. // * Dispatches register requests to available U2F tokens. An array of sign
  774. // * requests identifies already registered tokens.
  775. // * If the JS API version supported by the extension is unknown, it first sends a
  776. // * message to the extension to find out the supported API version and then it sends
  777. // * the register request.
  778. // * @param {string=} appId
  779. // * @param {Array<u2f.RegisterRequest>} registerRequests
  780. // * @param {Array<u2f.RegisteredKey>} registeredKeys
  781. // * @param {function((u2f.Error|u2f.RegisterResponse))} callback
  782. // * @param {number=} opt_timeoutSeconds
  783. // */
  784. // u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
  785. // if (js_api_version === undefined) {
  786. // // Send a message to get the extension to JS API version, then send the actual register request.
  787. // u2f.getApiVersion(
  788. // function (response) {
  789. // js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
  790. // console.log("Extension JS API Version: ", js_api_version);
  791. // u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
  792. // callback, opt_timeoutSeconds);
  793. // });
  794. // } else {
  795. // // We know the JS API version. Send the actual register request in the supported API version.
  796. // u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
  797. // callback, opt_timeoutSeconds);
  798. // }
  799. // };
  800. //
  801. // /**
  802. // * Dispatches register requests to available U2F tokens. An array of sign
  803. // * requests identifies already registered tokens.
  804. // * @param {string=} appId
  805. // * @param {Array<u2f.RegisterRequest>} registerRequests
  806. // * @param {Array<u2f.RegisteredKey>} registeredKeys
  807. // * @param {function((u2f.Error|u2f.RegisterResponse))} callback
  808. // * @param {number=} opt_timeoutSeconds
  809. // */
  810. // u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
  811. // u2f.getPortSingleton_(function(port) {
  812. // var reqId = ++u2f.reqCounter_;
  813. // u2f.callbackMap_[reqId] = callback;
  814. // var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
  815. // opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
  816. // var req = u2f.formatRegisterRequest_(
  817. // appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
  818. // port.postMessage(req);
  819. // });
  820. // };
  821. //
  822. //
  823. // /**
  824. // * Dispatches a message to the extension to find out the supported
  825. // * JS API version.
  826. // * If the user is on a mobile phone and is thus using Google Authenticator instead
  827. // * of the Chrome extension, don't send the request and simply return 0.
  828. // * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
  829. // * @param {number=} opt_timeoutSeconds
  830. // */
  831. // u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
  832. // u2f.getPortSingleton_(function(port) {
  833. // // If we are using Android Google Authenticator or iOS client app,
  834. // // do not fire an intent to ask which JS API version to use.
  835. // if (port.getPortType) {
  836. // var apiVersion;
  837. // switch (port.getPortType()) {
  838. // case 'WrappedIosPort_':
  839. // case 'WrappedAuthenticatorPort_':
  840. // apiVersion = 1.1;
  841. // break;
  842. //
  843. // default:
  844. // apiVersion = 0;
  845. // break;
  846. // }
  847. // callback({ 'js_api_version': apiVersion });
  848. // return;
  849. // }
  850. // var reqId = ++u2f.reqCounter_;
  851. // u2f.callbackMap_[reqId] = callback;
  852. // var req = {
  853. // type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
  854. // timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
  855. // opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
  856. // requestId: reqId
  857. // };
  858. // port.postMessage(req);
  859. // });
  860. // };
  861. //
  862. //
  863. //
  864. //
  865. //
  866. // // Copyright 2014 Google Inc. All rights reserved
  867. // //
  868. // // Use of this source code is governed by a BSD-style
  869. // // license that can be found in the LICENSE file or at
  870. // // https://developers.google.com/open-source/licenses/bsd
  871. //
  872. // // WebSafeBase64Escape and Unescape.
  873. // function B64_encode(bytes, opt_length) {
  874. // if (!opt_length) opt_length = bytes.length;
  875. // var b64out =
  876. // 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
  877. // var result = '';
  878. // var shift = 0;
  879. // var accu = 0;
  880. // var inputIndex = 0;
  881. // while (opt_length--) {
  882. // accu <<= 8;
  883. // accu |= bytes[inputIndex++];
  884. // shift += 8;
  885. // while (shift >= 6) {
  886. // let i = (accu >> (shift - 6)) & 63;
  887. // result += b64out.charAt(i);
  888. // shift -= 6;
  889. // }
  890. // }
  891. // if (shift) {
  892. // accu <<= 8;
  893. // shift += 8;
  894. // let i = (accu >> (shift - 6)) & 63;
  895. // result += b64out.charAt(i);
  896. // }
  897. // return result;
  898. // }
  899. //
  900. // // Normal base64 encode; not websafe, including padding.
  901. // // function base64_encode(bytes, opt_length) {
  902. // // if (!opt_length) opt_length = bytes.length;
  903. // // var b64out =
  904. // // 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  905. // // var result = '';
  906. // // var shift = 0;
  907. // // var accu = 0;
  908. // // var inputIndex = 0;
  909. // // while (opt_length--) {
  910. // // accu <<= 8;
  911. // // accu |= bytes[inputIndex++];
  912. // // shift += 8;
  913. // // while (shift >= 6) {
  914. // // let i = (accu >> (shift - 6)) & 63;
  915. // // result += b64out.charAt(i);
  916. // // shift -= 6;
  917. // // }
  918. // // }
  919. // // if (shift) {
  920. // // accu <<= 8;
  921. // // shift += 8;
  922. // // let i = (accu >> (shift - 6)) & 63;
  923. // // result += b64out.charAt(i);
  924. // // }
  925. // // while (result.length % 4) result += '=';
  926. // // return result;
  927. // // }
  928. //
  929. // var B64_inmap =
  930. // [
  931. // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,
  932. // 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0,
  933. // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  934. // 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 64,
  935. // 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
  936. // 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0
  937. // ];
  938. //
  939. // function B64_decode(string) {
  940. // var bytes = [];
  941. // var accu = 0;
  942. // var shift = 0;
  943. // for (let i = 0; i < string.length; ++i) {
  944. // var c = string.charCodeAt(i);
  945. // if (c < 32 || c > 127 || !B64_inmap[c - 32]) return [];
  946. // accu <<= 6;
  947. // accu |= (B64_inmap[c - 32] - 1);
  948. // shift += 6;
  949. // if (shift >= 8) {
  950. // bytes.push((accu >> (shift - 8)) & 255);
  951. // shift -= 8;
  952. // }
  953. // }
  954. // return bytes;
  955. // }
  956. //
  957. //
  958. //
  959. // (function () {
  960. // // https://github.com/ashtuchkin/u2f/blob/05c8bc6cc6d1610fd5bf0d9b9324615897dd6d0d/index.js#L62-L77
  961. // function asnLen(buf) {
  962. // if (buf.length < 2 || buf[0] != 0x30)
  963. // throw new Error("Invalid data: Not a SEQUENCE ASN/DER structure");
  964. //
  965. // var len = buf[1];
  966. // if (len & 0x80) { // long form
  967. // var bytesCnt = len & 0x7F;
  968. // if (buf.length < 2+bytesCnt)
  969. // throw new Error("Invalid data: ASN structure not fully represented");
  970. // len = 0;
  971. // for (let i = 0; i < bytesCnt; i++)
  972. // len = len*0x100 + buf[2+i];
  973. // len += bytesCnt; // add bytes for length itself.
  974. // }
  975. // return len + 2; // add 2 initial bytes: type and length.
  976. // }
  977. //
  978. // // Input fields
  979. // var reqAppId = document.getElementById("reqAppId"); // read only
  980. // var reqKeyHandle = document.getElementById("reqKeyHandle");
  981. //
  982. // // Output fields
  983. // var response = document.getElementById("response");
  984. // var resKeyHandle = document.getElementById("resKeyHandle");
  985. // var resPublicKey = document.getElementById("resPublicKey");
  986. // var resCertificate = document.getElementById("resCertificate");
  987. //
  988. // // Buttons
  989. // var btnGenReq = document.getElementById("btnGenReq");
  990. // var btnSign = document.getElementById("btnSign");
  991. // var btnRegister = document.getElementById("btnRegister");
  992. //
  993. // if (location.protocol != "https:") {
  994. // console.error("U2F requires the use of https.");
  995. // } else {
  996. // reqAppId.value = location.origin;
  997. // }
  998. //
  999. // // Sign
  1000. // btnSign.addEventListener("click", function (e) {
  1001. // console.log('E', e);
  1002. // try {
  1003. // var value = JSON.parse(request.value);
  1004. // u2f.sign(value.appId, value.challenge, [{
  1005. // version: "U2F_V2",
  1006. // appId: value.appId,
  1007. // keyHandle: resKeyHandle.value
  1008. // // keyHandle: value.keyHandle
  1009. // }], function (res) {
  1010. // response.value = JSON.stringify(res);
  1011. // });
  1012. // } catch (e) {
  1013. // console.error("No request specified, generate or input one manually");
  1014. // }
  1015. // });
  1016. //
  1017. // // Register
  1018. // btnRegister.addEventListener("click", function (e) {
  1019. // console.log('E', e);
  1020. // try {
  1021. // var value = JSON.parse(request.value);
  1022. // u2f.register(value.appId, [{
  1023. // version: "U2F_V2",
  1024. // appId: value.appId,
  1025. // challenge: value.challenge
  1026. // }], [], function (res) {
  1027. // response.value = JSON.stringify(res);
  1028. // // https://github.com/ashtuchkin/u2f/blob/05c8bc6cc6d1610fd5bf0d9b9324615897dd6d0d/index.js#L128-L139
  1029. // var buf = B64_decode(res.registrationData);
  1030. // // var reserved = buf[0]; buf = buf.slice(1);
  1031. // buf = buf.slice(1);
  1032. // var publicKey = buf.slice(0, 65); buf = buf.slice(65);
  1033. // var keyHandleLen = buf[0]; buf = buf.slice(1);
  1034. // var keyHandle = buf.slice(0, keyHandleLen); buf = buf.slice(keyHandleLen);
  1035. // var certLen = asnLen(buf);
  1036. // var certificate = buf.slice(0, certLen); buf = buf.slice(certLen);
  1037. // var signLen = asnLen(buf);
  1038. // // var signature = buf.slice(0, signLen); buf = buf.slice(signLen);
  1039. // buf = buf.slice(signLen);
  1040. // if (buf.length !== 0) {
  1041. // console.warn("U2F Registration Warning: registrationData has %s extra bytes: ", buf.length, buf);
  1042. // }
  1043. //
  1044. // resKeyHandle.value = B64_encode(keyHandle);
  1045. // resPublicKey.value = B64_encode(publicKey);
  1046. // resCertificate.value = B64_encode(certificate);
  1047. // });
  1048. // } catch (e) {
  1049. // console.error("No request specified, generate or input one manually");
  1050. // }
  1051. // });
  1052. //
  1053. // document.querySelectorAll("[readonly]:not([disabled])").forEach(function (el) {
  1054. // el.addEventListener("mouseup", function (e) {
  1055. // e.preventDefault();
  1056. // });
  1057. // el.addEventListener("focus", function (e) {
  1058. // console.log('E', e);
  1059. // this.select();
  1060. // });
  1061. // });
  1062. // })();
  1063. //
  1064. //
  1065. //
  1066. //
  1067. //
  1068. //
  1069. // },
  1070. // mounted: function () {
  1071. // //
  1072. // },
  1073. // }
  1074. </script>