WebAuthn.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * MIT License
  3. *
  4. * Copyright (c) Italo Israel Baeza Cabrera
  5. * https://github.com/Laragear/WebAuthn
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. */
  25. export default class WebAuthn {
  26. /**
  27. * Create a new WebAuthn instance.
  28. *
  29. */
  30. constructor () {
  31. }
  32. /**
  33. * Parses the Public Key Options received from the Server for the browser.
  34. *
  35. * @param publicKey {Object}
  36. * @returns {Object}
  37. */
  38. parseIncomingServerOptions(publicKey) {
  39. publicKey.challenge = WebAuthn.uint8Array(publicKey.challenge);
  40. if ('user' in publicKey) {
  41. publicKey.user = {
  42. ...publicKey.user,
  43. id: WebAuthn.uint8Array(publicKey.user.id)
  44. };
  45. }
  46. [
  47. "excludeCredentials",
  48. "allowCredentials"
  49. ]
  50. .filter(key => key in publicKey)
  51. .forEach(key => {
  52. publicKey[key] = publicKey[key].map(data => {
  53. return {...data, id: WebAuthn.uint8Array(data.id)};
  54. });
  55. });
  56. return publicKey;
  57. }
  58. /**
  59. * Parses the outgoing credentials from the browser to the server.
  60. *
  61. * @param credentials {Credential|PublicKeyCredential}
  62. * @return {{response: {string}, rawId: string, id: string, type: string}}
  63. */
  64. parseOutgoingCredentials(credentials) {
  65. let parseCredentials = {
  66. id: credentials.id,
  67. type: credentials.type,
  68. rawId: WebAuthn.arrayToBase64String(credentials.rawId),
  69. response: {}
  70. };
  71. [
  72. "clientDataJSON",
  73. "attestationObject",
  74. "authenticatorData",
  75. "signature",
  76. "userHandle"
  77. ]
  78. .filter(key => key in credentials.response)
  79. .forEach(key => parseCredentials.response[key] = WebAuthn.arrayToBase64String(credentials.response[key]));
  80. return parseCredentials;
  81. }
  82. /**
  83. * Transform a string into Uint8Array instance.
  84. *
  85. * @param input {string}
  86. * @param useAtob {boolean}
  87. * @returns {Uint8Array}
  88. */
  89. static uint8Array(input, useAtob = false) {
  90. return Uint8Array.from(
  91. useAtob ? atob(input) : WebAuthn.base64UrlDecode(input), c => c.charCodeAt(0)
  92. );
  93. }
  94. /**
  95. * Encodes an array of bytes to a BASE64 URL string
  96. *
  97. * @param arrayBuffer {ArrayBuffer|Uint8Array}
  98. * @returns {string}
  99. */
  100. static arrayToBase64String(arrayBuffer) {
  101. return btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
  102. }
  103. /**
  104. * Decodes a BASE64 URL string into a normal string.
  105. *
  106. * @param input {string}
  107. * @returns {string|Iterable}
  108. */
  109. static base64UrlDecode(input) {
  110. input = input.replace(/-/g, "+").replace(/_/g, "/");
  111. const pad = input.length % 4;
  112. if (pad) {
  113. if (pad === 1) {
  114. throw new Error("InvalidLengthError: Input base64url string is the wrong length to determine padding");
  115. }
  116. input += new Array(5 - pad).join("=");
  117. }
  118. return atob(input);
  119. }
  120. /**
  121. * Checks if the browser supports WebAuthn.
  122. *
  123. * @returns {boolean}
  124. */
  125. static supportsWebAuthn() {
  126. return typeof PublicKeyCredential != "undefined";
  127. }
  128. /**
  129. * Checks if the browser doesn't support WebAuthn.
  130. *
  131. * @returns {boolean}
  132. */
  133. static doesntSupportWebAuthn() {
  134. return !this.supportsWebAuthn();
  135. }
  136. }