MCPcopy Create free account
hub / github.com/027xiguapi/code-box / TOTP

Class TOTP

utils/totp.ts:3–104  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1import * as CryptoJS from "crypto-js"
2
3export class TOTP {
4 private static readonly DIGITS: number = 6
5 private static readonly PERIOD: number = 30
6
7 /**
8 * Generate a TOTP code from a secret key
9 * @param secret Base32 encoded secret key
10 * @returns TOTP code
11 */
12 public static generateTOTP(secret: string): string {
13 const epoch = Math.floor(Date.now() / 1000)
14 const timeCounter = Math.floor(epoch / this.PERIOD)
15 return this.generateTOTPAtCounter(secret, timeCounter)
16 }
17
18 /**
19 * Validate if a secret key is in valid Base32 format
20 * @param secret The secret key to validate
21 * @returns boolean indicating if the secret is valid
22 */
23 public static isValidSecret(secret: string): boolean {
24 const base32Regex = /^[A-Z2-7]+=*$/
25 return base32Regex.test(secret.toUpperCase())
26 }
27
28 /**
29 * Generate TOTP at a specific counter value
30 * @param secret Base32 encoded secret key
31 * @param counter Time counter
32 * @returns TOTP code
33 */
34 private static generateTOTPAtCounter(
35 secret: string,
36 counter: number
37 ): string {
38 const decodedSecret = this.base32ToHex(secret)
39 const timeHex = this.leftPad(counter.toString(16), 16)
40
41 // Convert hex to WordArray for crypto-js
42 const key = CryptoJS.enc.Hex.parse(decodedSecret)
43 const message = CryptoJS.enc.Hex.parse(timeHex)
44
45 // Calculate HMAC-SHA1
46 const hmac = CryptoJS.HmacSHA1(message, key)
47 const hmacResult = hmac.toString()
48
49 const offset = parseInt(hmacResult.slice(-1), 16)
50 const code = parseInt(hmacResult.substr(offset * 2, 8), 16) & 0x7fffffff
51
52 return this.leftPad(
53 (code % Math.pow(10, this.DIGITS)).toString(),
54 this.DIGITS
55 )
56 }
57
58 /**
59 * Convert Base32 string to hexadecimal
60 * @param base32 Base32 encoded string

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected