From a104f36561198f4b7df92c19d8d31233523fb53b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 23 May 2024 12:06:54 +0530 Subject: [PATCH] Inline --- web/apps/auth/src/components/OTPDisplay.tsx | 274 ------------------- web/apps/auth/src/pages/auth.tsx | 275 +++++++++++++++++++- 2 files changed, 273 insertions(+), 276 deletions(-) diff --git a/web/apps/auth/src/components/OTPDisplay.tsx b/web/apps/auth/src/components/OTPDisplay.tsx index 1168fe8cb5..e69de29bb2 100644 --- a/web/apps/auth/src/components/OTPDisplay.tsx +++ b/web/apps/auth/src/components/OTPDisplay.tsx @@ -1,274 +0,0 @@ -import { ButtonBase, Snackbar } from "@mui/material"; -import { t } from "i18next"; -import { HOTP, TOTP } from "otpauth"; -import { useEffect, useState } from "react"; -import { Code } from "types/code"; - -const TOTPDisplay = ({ issuer, account, code, nextCode, period }) => { - return ( -
- -
-
-

- {issuer} -

-

- {account} -

-

- {code} -

-
-
-
-

- {t("AUTH_NEXT")} -

-

- {nextCode} -

-
-
-
- ); -}; - -function BadCodeInfo({ codeInfo, codeErr }) { - const [showRawData, setShowRawData] = useState(false); - - return ( -
-
{codeInfo.title}
-
{codeErr}
-
- {showRawData ? ( -
setShowRawData(false)}> - {codeInfo.rawData ?? "no raw data"} -
- ) : ( -
setShowRawData(true)}>Show rawData
- )} -
-
- ); -} - -interface OTPDisplayProps { - codeInfo: Code; -} - -const OTPDisplay = (props: OTPDisplayProps) => { - const { codeInfo } = props; - const [code, setCode] = useState(""); - const [nextCode, setNextCode] = useState(""); - const [codeErr, setCodeErr] = useState(""); - const [hasCopied, setHasCopied] = useState(false); - - const generateCodes = () => { - try { - const currentTime = new Date().getTime(); - if (codeInfo.type.toLowerCase() === "totp") { - const totp = new TOTP({ - secret: codeInfo.secret, - algorithm: codeInfo.algorithm ?? Code.defaultAlgo, - period: codeInfo.period ?? Code.defaultPeriod, - digits: codeInfo.digits ?? Code.defaultDigits, - }); - setCode(totp.generate()); - setNextCode( - totp.generate({ - timestamp: currentTime + codeInfo.period * 1000, - }), - ); - } else if (codeInfo.type.toLowerCase() === "hotp") { - const hotp = new HOTP({ - secret: codeInfo.secret, - counter: 0, - algorithm: codeInfo.algorithm, - }); - setCode(hotp.generate()); - setNextCode(hotp.generate({ counter: 1 })); - } - } catch (err) { - setCodeErr(err.message); - } - }; - - const copyCode = () => { - navigator.clipboard.writeText(code); - setHasCopied(true); - setTimeout(() => { - setHasCopied(false); - }, 2000); - }; - - useEffect(() => { - // this is to set the initial code and nextCode on component mount - generateCodes(); - 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 - setTimeout(() => { - // we need to call generateCodes() once before the interval loop - // to set the initial code and nextCode - generateCodes(); - codeType.toLowerCase() === "totp" || - codeType.toLowerCase() === "hotp" - ? setInterval(() => { - generateCodes(); - }, codePeriodInMs) - : null; - }, timeToNextCode); - - return () => { - if (intervalId) clearInterval(intervalId); - }; - }, [codeInfo]); - - return ( -
- {codeErr === "" ? ( - { - copyCode(); - }} - > - - - - ) : ( - - )} -
- ); -}; - -export default OTPDisplay; - -const TimerProgress = ({ period }) => { - const [progress, setProgress] = useState(0); - const [ticker, setTicker] = useState(null); - const microSecondsInPeriod = period * 1000000; - - const startTicker = () => { - const ticker = setInterval(() => { - updateTimeRemaining(); - }, 10); - setTicker(ticker); - }; - - const updateTimeRemaining = () => { - const timeRemaining = - microSecondsInPeriod - - ((new Date().getTime() * 1000) % microSecondsInPeriod); - setProgress(timeRemaining / microSecondsInPeriod); - }; - - useEffect(() => { - startTicker(); - return () => clearInterval(ticker); - }, []); - - const color = progress > 0.4 ? "green" : "orange"; - - return ( -
- ); -}; diff --git a/web/apps/auth/src/pages/auth.tsx b/web/apps/auth/src/pages/auth.tsx index 14135e20df..ad614c2f4a 100644 --- a/web/apps/auth/src/pages/auth.tsx +++ b/web/apps/auth/src/pages/auth.tsx @@ -12,13 +12,14 @@ import { CustomError } from "@ente/shared/error"; import InMemoryStore, { MS_KEYS } from "@ente/shared/storage/InMemoryStore"; import LogoutOutlined from "@mui/icons-material/LogoutOutlined"; import MoreHoriz from "@mui/icons-material/MoreHoriz"; -import { Button, TextField } from "@mui/material"; -import OTPDisplay from "components/OTPDisplay"; +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 { getAuthCodes } from "services"; +import { Code } from "types/code"; const AuthenticatorCodesPage = () => { const appContext = useContext(AppContext); @@ -181,3 +182,273 @@ const AuthFooter: React.FC = () => {
); }; + +const TOTPDisplay = ({ issuer, account, code, nextCode, period }) => { + return ( +
+ +
+
+

+ {issuer} +

+

+ {account} +

+

+ {code} +

+
+
+
+

+ {t("AUTH_NEXT")} +

+

+ {nextCode} +

+
+
+
+ ); +}; + +function BadCodeInfo({ codeInfo, codeErr }) { + const [showRawData, setShowRawData] = useState(false); + + return ( +
+
{codeInfo.title}
+
{codeErr}
+
+ {showRawData ? ( +
setShowRawData(false)}> + {codeInfo.rawData ?? "no raw data"} +
+ ) : ( +
setShowRawData(true)}>Show rawData
+ )} +
+
+ ); +} + +interface OTPDisplayProps { + codeInfo: Code; +} + +const OTPDisplay: React.FC = ({ codeInfo }) => { + const [code, setCode] = useState(""); + const [nextCode, setNextCode] = useState(""); + const [codeErr, setCodeErr] = useState(""); + const [hasCopied, setHasCopied] = useState(false); + + const generateCodes = () => { + try { + const currentTime = new Date().getTime(); + if (codeInfo.type.toLowerCase() === "totp") { + const totp = new TOTP({ + secret: codeInfo.secret, + algorithm: codeInfo.algorithm ?? Code.defaultAlgo, + period: codeInfo.period ?? Code.defaultPeriod, + digits: codeInfo.digits ?? Code.defaultDigits, + }); + setCode(totp.generate()); + setNextCode( + totp.generate({ + timestamp: currentTime + codeInfo.period * 1000, + }), + ); + } else if (codeInfo.type.toLowerCase() === "hotp") { + const hotp = new HOTP({ + secret: codeInfo.secret, + counter: 0, + algorithm: codeInfo.algorithm, + }); + setCode(hotp.generate()); + setNextCode(hotp.generate({ counter: 1 })); + } + } catch (err) { + setCodeErr(err.message); + } + }; + + const copyCode = () => { + navigator.clipboard.writeText(code); + setHasCopied(true); + setTimeout(() => { + setHasCopied(false); + }, 2000); + }; + + useEffect(() => { + // this is to set the initial code and nextCode on component mount + generateCodes(); + 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 + setTimeout(() => { + // we need to call generateCodes() once before the interval loop + // to set the initial code and nextCode + generateCodes(); + codeType.toLowerCase() === "totp" || + codeType.toLowerCase() === "hotp" + ? setInterval(() => { + generateCodes(); + }, codePeriodInMs) + : null; + }, timeToNextCode); + + return () => { + if (intervalId) clearInterval(intervalId); + }; + }, [codeInfo]); + + return ( +
+ {codeErr === "" ? ( + { + copyCode(); + }} + > + + + + ) : ( + + )} +
+ ); +}; + +interface TimerProgressProps { + period: number; +} + +const TimerProgress: React.FC = ({ period }) => { + const [progress, setProgress] = useState(0); + const [ticker, setTicker] = useState(null); + const microSecondsInPeriod = period * 1000000; + + const startTicker = () => { + const ticker = setInterval(() => { + updateTimeRemaining(); + }, 10); + setTicker(ticker); + }; + + const updateTimeRemaining = () => { + const timeRemaining = + microSecondsInPeriod - + ((new Date().getTime() * 1000) % microSecondsInPeriod); + setProgress(timeRemaining / microSecondsInPeriod); + }; + + useEffect(() => { + startTicker(); + return () => clearInterval(ticker); + }, []); + + const color = progress > 0.4 ? "green" : "orange"; + + return ( +
+ ); +};