summaryrefslogtreecommitdiff
path: root/packages/anastasis-webui/src/pages/home/authMethod/totp.ts
blob: 9c26ddcad30f460000f24e048897c46878f9be88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import jssha from "jssha";

const SEARCH_RANGE = 16;
const timeStep = 30;

export function computeTOTPandCheck(
  secretKey: Uint8Array,
  digits: number,
  code: number,
): boolean {
  const now = new Date().getTime();
  const epoch = Math.floor(Math.round(now / 1000.0) / timeStep);

  for (let ms = -SEARCH_RANGE; ms < SEARCH_RANGE; ms++) {
    const movingFactor = (epoch + ms).toString(16).padStart(16, "0");

    const hmacSha = new jssha("SHA-1", "HEX", {
      hmacKey: { value: secretKey, format: "UINT8ARRAY" },
    });
    hmacSha.update(movingFactor);
    const hmac_text = hmacSha.getHMAC("UINT8ARRAY");

    const offset = hmac_text[hmac_text.length - 1] & 0xf;

    const otp =
      (((hmac_text[offset + 0] << 24) +
        (hmac_text[offset + 1] << 16) +
        (hmac_text[offset + 2] << 8) +
        hmac_text[offset + 3]) &
        0x7fffffff) %
      Math.pow(10, digits);

    if (otp == code) return true;
  }
  return false;
}

const encTable__ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".split("");
export function base32enc(buffer: Uint8Array): string {
  let rpos = 0;
  let bits = 0;
  let vbit = 0;

  let result = "";
  while (rpos < buffer.length || vbit > 0) {
    if (rpos < buffer.length && vbit < 5) {
      bits = (bits << 8) | buffer[rpos++];
      vbit += 8;
    }
    if (vbit < 5) {
      bits <<= 5 - vbit;
      vbit = 5;
    }
    result += encTable__[(bits >> (vbit - 5)) & 31];
    vbit -= 5;
  }
  return result;
}

// const array = new Uint8Array(256)
// const secretKey = window.crypto.getRandomValues(array)
// console.log(base32enc(secretKey))