44import base32Encode from 'base32-encode'
55import base32Decode from 'base32-decode'
66
7+ /**
8+ * @typedef {'SHA-1' | 'SHA-256' | 'SHA-386' | 'SHA-512' | string & {} } HashAlgorithm
9+ *
10+ * For all available algorithms, refer to the following:
11+ * https://developer.mozilla.org/en-US/docs/Web/API/HmacImportParams#hash
12+ */
13+
714// SHA-1 is not secure, but in the context of TOTPs, it's unrealistic to expect
815// security issues. Also, it's the default for compatibility with OTP apps.
916// That said, if you're acting the role of both client and server and your TOTP
@@ -25,7 +32,7 @@ const DEFAULT_PERIOD = 30
2532 * Defaults to 0.
2633 * @param {number } [options.digits=6] - The number of digits to use for the
2734 * HOTP. Defaults to 6.
28- * @param {string } [options.algorithm='SHA-1'] - The algorithm to use for the
35+ * @param {HashAlgorithm } [options.algorithm='SHA-1'] - The algorithm to use for the
2936 * HOTP. Defaults to 'SHA-1'.
3037 * @param {string } [options.charSet='0123456789'] - The character set to use, defaults to the numbers 0-9.
3138 * @returns {Promise<string> } The generated HOTP.
@@ -37,15 +44,15 @@ async function generateHOTP(
3744 digits = DEFAULT_DIGITS ,
3845 algorithm = DEFAULT_ALGORITHM ,
3946 charSet = DEFAULT_CHAR_SET ,
40- } = { }
47+ } = { } ,
4148) {
4249 const byteCounter = intToBytes ( counter )
4350 const key = await crypto . subtle . importKey (
4451 'raw' ,
4552 secret ,
4653 { name : 'HMAC' , hash : algorithm } ,
4754 false ,
48- [ 'sign' ]
55+ [ 'sign' ] ,
4956 )
5057 const signature = await crypto . subtle . sign ( 'HMAC' , key , byteCounter )
5158 const hashBytes = new Uint8Array ( signature )
@@ -76,7 +83,7 @@ async function generateHOTP(
7683 * Defaults to 0.
7784 * @param {number } [options.digits=6] - The number of digits to use for the
7885 * HOTP. Defaults to 6.
79- * @param {string } [options.algorithm='SHA-1'] - The algorithm to use for the
86+ * @param {HashAlgorithm } [options.algorithm='SHA-1'] - The algorithm to use for the
8087 * HOTP. Defaults to 'SHA-1'.
8188 * @param {string } [options.charSet='0123456789'] - The character set to use, defaults to the numbers 0-9.
8289 * @param {number } [options.window=1] - The number of counter values to check
@@ -94,11 +101,16 @@ async function verifyHOTP(
94101 algorithm = DEFAULT_ALGORITHM ,
95102 charSet = DEFAULT_CHAR_SET ,
96103 window = DEFAULT_WINDOW ,
97- } = { }
104+ } = { } ,
98105) {
99106 for ( let i = counter - window ; i <= counter + window ; ++ i ) {
100107 if (
101- await generateHOTP ( secret , { counter : i , digits, algorithm, charSet } ) === otp
108+ ( await generateHOTP ( secret , {
109+ counter : i ,
110+ digits,
111+ algorithm,
112+ charSet,
113+ } ) ) === otp
102114 ) {
103115 return { delta : i - counter }
104116 }
@@ -115,7 +127,7 @@ async function verifyHOTP(
115127 * @param {number } [options.period=30] The number of seconds for the OTP to be
116128 * valid. Defaults to 30.
117129 * @param {number } [options.digits=6] The length of the OTP. Defaults to 6.
118- * @param {string } [options.algorithm='SHA-1'] The algorithm to use. Defaults to
130+ * @param {HashAlgorithm } [options.algorithm='SHA-1'] The algorithm to use. Defaults to
119131 * SHA-1.
120132 * @param {string } [options.charSet='0123456789'] - The character set to use, defaults to the numbers 0-9.
121133 * @param {string } [options.secret] The secret to use for the TOTP. It should be
@@ -148,7 +160,7 @@ export async function generateTOTP({
148160 * @param {Object } options Configuration options for the TOTP Auth URI.
149161 * @param {number } options.period The number of seconds for the OTP to be valid.
150162 * @param {number } options.digits The length of the OTP.
151- * @param {string } options.algorithm The algorithm to use.
163+ * @param {HashAlgorithm } options.algorithm The algorithm to use.
152164 * @param {string } options.secret The secret to use for the TOTP Auth URI.
153165 * @param {string } options.accountName A way to uniquely identify this Auth URI
154166 * (in case they have multiple of these).
@@ -189,7 +201,7 @@ export function getTOTPAuthUri({
189201 * @param {string } options.secret The secret to use for the TOTP.
190202 * @param {number } [options.period] The number of seconds for the OTP to be valid.
191203 * @param {number } [options.digits] The length of the OTP.
192- * @param {string } [options.algorithm] The algorithm to use.
204+ * @param {HashAlgorithm } [options.algorithm] The algorithm to use.
193205 * @param {string } [options.charSet] - The character set to use, defaults to the numbers 0-9.
194206 * @param {number } [options.window] The number of OTPs to check before and after
195207 * the current OTP. Defaults to 1.
@@ -250,4 +262,4 @@ function getCounter(period = DEFAULT_PERIOD) {
250262 const now = new Date ( ) . getTime ( )
251263 const counter = Math . floor ( now / 1000 / period )
252264 return counter
253- }
265+ }
0 commit comments