Extract logic
This commit is contained in:
parent
69cea6786d
commit
90d0196d47
|
@ -15,10 +15,9 @@ import MoreHoriz from "@mui/icons-material/MoreHoriz";
|
||||||
import { Button, ButtonBase, Snackbar, TextField } from "@mui/material";
|
import { Button, ButtonBase, Snackbar, TextField } from "@mui/material";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { HOTP, TOTP } from "otpauth";
|
|
||||||
import { AppContext } from "pages/_app";
|
import { AppContext } from "pages/_app";
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import { Code } from "services/code";
|
import { generateOTPs, type Code } from "services/code";
|
||||||
import { getAuthCodes } from "services/remote";
|
import { getAuthCodes } from "services/remote";
|
||||||
|
|
||||||
const AuthenticatorCodesPage = () => {
|
const AuthenticatorCodesPage = () => {
|
||||||
|
@ -172,33 +171,13 @@ const CodeDisplay: React.FC<CodeDisplay> = ({ codeInfo }) => {
|
||||||
const [codeErr, setCodeErr] = useState("");
|
const [codeErr, setCodeErr] = useState("");
|
||||||
const [hasCopied, setHasCopied] = useState(false);
|
const [hasCopied, setHasCopied] = useState(false);
|
||||||
|
|
||||||
const generateCodes = () => {
|
const regen = () => {
|
||||||
try {
|
try {
|
||||||
const currentTime = new Date().getTime();
|
const [m, n] = generateOTPs(codeInfo);
|
||||||
if (codeInfo.type === "totp") {
|
setOTP(m);
|
||||||
const totp = new TOTP({
|
setNextOTP(n);
|
||||||
secret: codeInfo.secret,
|
} catch (e) {
|
||||||
algorithm: codeInfo.algorithm,
|
setCodeErr(e.message);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,29 +190,29 @@ const CodeDisplay: React.FC<CodeDisplay> = ({ codeInfo }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// this is to set the initial code and nextCode on component mount
|
// Generate to set the initial otp and nextOTP on component mount.
|
||||||
generateCodes();
|
regen();
|
||||||
const codeType = codeInfo.type;
|
const codeType = codeInfo.type;
|
||||||
const codePeriodInMs = codeInfo.period * 1000;
|
const codePeriodInMs = codeInfo.period * 1000;
|
||||||
const timeToNextCode =
|
const timeToNextCode =
|
||||||
codePeriodInMs - (new Date().getTime() % codePeriodInMs);
|
codePeriodInMs - (new Date().getTime() % codePeriodInMs);
|
||||||
const intervalId = null;
|
const interval = null;
|
||||||
// wait until we are at the start of the next code period,
|
// Wait until we are at the start of the next code period, and then
|
||||||
// and then start the interval loop
|
// start the interval loop.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// we need to call generateCodes() once before the interval loop
|
// We need to call regen() once before the interval loop to set the
|
||||||
// to set the initial code and nextCode
|
// initial otp and nextOTP.
|
||||||
generateCodes();
|
regen();
|
||||||
codeType.toLowerCase() === "totp" ||
|
codeType.toLowerCase() === "totp" ||
|
||||||
codeType.toLowerCase() === "hotp"
|
codeType.toLowerCase() === "hotp"
|
||||||
? setInterval(() => {
|
? setInterval(() => {
|
||||||
generateCodes();
|
regen();
|
||||||
}, codePeriodInMs)
|
}, codePeriodInMs)
|
||||||
: null;
|
: null;
|
||||||
}, timeToNextCode);
|
}, timeToNextCode);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (intervalId) clearInterval(intervalId);
|
if (interval) clearInterval(interval);
|
||||||
};
|
};
|
||||||
}, [codeInfo]);
|
}, [codeInfo]);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { HOTP, TOTP } from "otpauth";
|
||||||
import { URI } from "vscode-uri";
|
import { URI } from "vscode-uri";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,3 +146,43 @@ const _getType = (uriPath: string): Code["type"] => {
|
||||||
const getSanitizedSecret = (uriParams): string => {
|
const getSanitizedSecret = (uriParams): string => {
|
||||||
return uriParams["secret"].replace(/ /g, "").toUpperCase();
|
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