Extract logic

This commit is contained in:
Manav Rathi 2024-05-23 19:06:06 +05:30
parent 69cea6786d
commit 90d0196d47
No known key found for this signature in database
2 changed files with 58 additions and 38 deletions

View file

@ -15,10 +15,9 @@ import MoreHoriz from "@mui/icons-material/MoreHoriz";
import { Button, ButtonBase, Snackbar, TextField } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
import { HOTP, TOTP } from "otpauth";
import { AppContext } from "pages/_app";
import React, { useContext, useEffect, useState } from "react";
import { Code } from "services/code";
import { generateOTPs, type Code } from "services/code";
import { getAuthCodes } from "services/remote";
const AuthenticatorCodesPage = () => {
@ -172,33 +171,13 @@ const CodeDisplay: React.FC<CodeDisplay> = ({ codeInfo }) => {
const [codeErr, setCodeErr] = useState("");
const [hasCopied, setHasCopied] = useState(false);
const generateCodes = () => {
const regen = () => {
try {
const currentTime = new Date().getTime();
if (codeInfo.type === "totp") {
const totp = new TOTP({
secret: codeInfo.secret,
algorithm: codeInfo.algorithm,
period: codeInfo.period,
digits: codeInfo.digits,
});
setOTP(totp.generate());
setNextOTP(
totp.generate({
timestamp: currentTime + codeInfo.period * 1000,
}),
);
} else if (codeInfo.type === "hotp") {
const hotp = new HOTP({
secret: codeInfo.secret,
counter: 0,
algorithm: codeInfo.algorithm,
});
setOTP(hotp.generate());
setNextOTP(hotp.generate({ counter: 1 }));
}
} catch (err) {
setCodeErr(err.message);
const [m, n] = generateOTPs(codeInfo);
setOTP(m);
setNextOTP(n);
} catch (e) {
setCodeErr(e.message);
}
};
@ -211,29 +190,29 @@ const CodeDisplay: React.FC<CodeDisplay> = ({ codeInfo }) => {
};
useEffect(() => {
// this is to set the initial code and nextCode on component mount
generateCodes();
// Generate to set the initial otp and nextOTP on component mount.
regen();
const codeType = codeInfo.type;
const codePeriodInMs = codeInfo.period * 1000;
const timeToNextCode =
codePeriodInMs - (new Date().getTime() % codePeriodInMs);
const intervalId = null;
// wait until we are at the start of the next code period,
// and then start the interval loop
const interval = null;
// Wait until we are at the start of the next code period, and then
// start the interval loop.
setTimeout(() => {
// we need to call generateCodes() once before the interval loop
// to set the initial code and nextCode
generateCodes();
// We need to call regen() once before the interval loop to set the
// initial otp and nextOTP.
regen();
codeType.toLowerCase() === "totp" ||
codeType.toLowerCase() === "hotp"
? setInterval(() => {
generateCodes();
regen();
}, codePeriodInMs)
: null;
}, timeToNextCode);
return () => {
if (intervalId) clearInterval(intervalId);
if (interval) clearInterval(interval);
};
}, [codeInfo]);

View file

@ -1,3 +1,4 @@
import { HOTP, TOTP } from "otpauth";
import { URI } from "vscode-uri";
/**
@ -145,3 +146,43 @@ const _getType = (uriPath: string): Code["type"] => {
const getSanitizedSecret = (uriParams): string => {
return uriParams["secret"].replace(/ /g, "").toUpperCase();
};
/**
* Generate a pair of OTPs (one time passwords) from the given {@link code}.
*
* @param code The parsed code data, including the secret and code type.
*
* @returns a pair of OTPs, the current one and the next one, using the given
* {@link code}.
*/
export const generateOTPs = (code: Code): [otp: string, nextOTP: string] => {
let otp: string;
let nextOTP: string;
switch (code.type) {
case "totp": {
const totp = new TOTP({
secret: code.secret,
algorithm: code.algorithm,
period: code.period,
digits: code.digits,
});
otp = totp.generate();
nextOTP = totp.generate({
timestamp: new Date().getTime() + code.period * 1000,
});
break;
}
case "hotp": {
const hotp = new HOTP({
secret: code.secret,
counter: 0,
algorithm: code.algorithm,
});
otp = hotp.generate();
nextOTP = hotp.generate({ counter: 1 });
break;
}
}
return [otp, nextOTP];
};