Extract logic
This commit is contained in:
parent
69cea6786d
commit
90d0196d47
2 changed files with 58 additions and 38 deletions
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue