From 5e2261f793aa4f69841e0d664af4d49e3f08a23e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 23 May 2024 13:36:16 +0530 Subject: [PATCH] Unclass --- web/apps/auth/src/pages/auth.tsx | 6 +- web/apps/auth/src/services/code.ts | 89 +++++++++++++--------------- web/apps/auth/src/services/remote.ts | 4 +- 3 files changed, 46 insertions(+), 53 deletions(-) diff --git a/web/apps/auth/src/pages/auth.tsx b/web/apps/auth/src/pages/auth.tsx index e1c69f1da..e628050ea 100644 --- a/web/apps/auth/src/pages/auth.tsx +++ b/web/apps/auth/src/pages/auth.tsx @@ -175,7 +175,7 @@ const CodeDisplay: React.FC = ({ codeInfo }) => { const generateCodes = () => { try { const currentTime = new Date().getTime(); - if (codeInfo.type.toLowerCase() === "totp") { + if (codeInfo.type === "totp") { const totp = new TOTP({ secret: codeInfo.secret, algorithm: codeInfo.algorithm, @@ -188,7 +188,7 @@ const CodeDisplay: React.FC = ({ codeInfo }) => { timestamp: currentTime + codeInfo.period * 1000, }), ); - } else if (codeInfo.type.toLowerCase() === "hotp") { + } else if (codeInfo.type === "hotp") { const hotp = new HOTP({ secret: codeInfo.secret, counter: 0, @@ -417,7 +417,7 @@ function BadCodeInfo({ codeInfo, codeErr }) {
{showRawData ? (
setShowRawData(false)}> - {codeInfo.rawData ?? "no raw data"} + {codeInfo.uriString ?? "(no raw data)"}
) : (
setShowRawData(true)}>Show rawData
diff --git a/web/apps/auth/src/services/code.ts b/web/apps/auth/src/services/code.ts index ddac5a920..ca9ba1642 100644 --- a/web/apps/auth/src/services/code.ts +++ b/web/apps/auth/src/services/code.ts @@ -1,54 +1,47 @@ import { URI } from "vscode-uri"; -type Type = "totp" | "TOTP" | "hotp" | "HOTP"; - -type Algorithm = "sha1" | "sha256" | "sha512"; - -export class Code { - // id for the corresponding auth entity +/** + * A parsed representation of an xOTP code URI. + * + * This is all the data we need to drive a OTP generator. + */ +export interface Code { + /** The uniquue id for the corresponding auth entity. */ id?: String; + /** The type of the code. */ + type: "totp" | "hotp"; + /** The user's account or email for which this code is used. */ account: string; + /** The name of the entity that issued this code. */ issuer: string; + /** Number of digits in the code. */ digits: number; + /** + * The time period (in seconds) for which a single OTP generated from this + * code remains valid. + */ period: number; + /** The secret that is used to drive the OTP generator. */ secret: string; - algorithm: Algorithm; - type: Type; - rawData?: string; - - constructor( - account: string, - issuer: string, - digits: number, - period: number, - secret: string, - algorithm: Algorithm, - type: Type, - rawData?: string, - id?: string, - ) { - this.account = account; - this.issuer = issuer; - this.digits = digits; - this.period = period; - this.secret = secret; - this.algorithm = algorithm; - this.type = type; - this.rawData = rawData; - this.id = id; - } + /** The (hashing) algorithim used by the OTP generator. */ + algorithm: "sha1" | "sha256" | "sha512"; + /** The original string from which this code was generated. */ + uriString?: string; } /** - * Convert a "raw" OTP secret URL into its parse representation, a {@link Code}. + * Convert a OTP code URI into its parse representation, a {@link Code}. * - * An example {@link rawData}: + * @param id A unique ID of this code within the auth app. * - * otpauth://totp/account:user@example.org?algorithm=SHA1&digits=6&issuer=issuer&period=30&secret=ALPHANUM + * @param uriString A string specifying how to generate a TOTP/HOTP/Steam OTP + * code. These strings are of the form: * + * - (TOTP) + * otpauth://totp/account:user@example.org?algorithm=SHA1&digits=6&issuer=issuer&period=30&secret=ALPHANUM */ -export const codeFromRawData = (id: string, rawData: string): Code => { - let santizedRawData = rawData +export const codeFromURIString = (id: string, uriString: string): Code => { + let santizedRawData = uriString .replace(/\+/g, "%2B") .replace(/:/g, "%3A") .replaceAll("\r", ""); @@ -78,17 +71,17 @@ export const codeFromRawData = (id: string, rawData: string): Code => { uriPath = uriPath.split("otpauth%3A//")[1]; } - return new Code( - _getAccount(uriPath), - _getIssuer(uriPath, uriParams), - parseDigits(uriParams), - parsePeriod(uriParams), - getSanitizedSecret(uriParams), - parseAlgorithm(uriParams), - _getType(uriPath), - rawData, + return { id, - ); + type: _getType(uriPath), + account: _getAccount(uriPath), + issuer: _getIssuer(uriPath, uriParams), + digits: parseDigits(uriParams), + period: parsePeriod(uriParams), + secret: getSanitizedSecret(uriParams), + algorithm: parseAlgorithm(uriParams), + uriString, + }; }; const _getAccount = (uriPath: string): string => { @@ -135,7 +128,7 @@ const parseDigits = (uriParams): number => const parsePeriod = (uriParams): number => parseInt(uriParams["period"] ?? "", 10) || 30; -const parseAlgorithm = (uriParams): Algorithm => { +const parseAlgorithm = (uriParams): Code["algorithm"] => { switch (uriParams["algorithm"]?.toLowerCase()) { case "sha256": return "sha256"; @@ -146,7 +139,7 @@ const parseAlgorithm = (uriParams): Algorithm => { } }; -const _getType = (uriPath: string): Type => { +const _getType = (uriPath: string): Code["type"] => { const oauthType = uriPath.split("/")[0].substring(0); if (oauthType.toLowerCase() === "totp") { return "totp"; diff --git a/web/apps/auth/src/services/remote.ts b/web/apps/auth/src/services/remote.ts index 325aff2d7..07b15d7d7 100644 --- a/web/apps/auth/src/services/remote.ts +++ b/web/apps/auth/src/services/remote.ts @@ -6,7 +6,7 @@ import { getEndpoint } from "@ente/shared/network/api"; import { getToken } from "@ente/shared/storage/localStorage/helpers"; import { getActualKey } from "@ente/shared/user"; import { HttpStatusCode } from "axios"; -import { Code, codeFromRawData } from "services/code"; +import { codeFromURIString, type Code } from "services/code"; const ENDPOINT = getEndpoint(); @@ -33,7 +33,7 @@ export const getAuthCodes = async (): Promise => { entity.header, authenticatorKey, ); - return codeFromRawData(entity.id, decryptedCode); + return codeFromURIString(entity.id, decryptedCode); } catch (e) { log.error(`failed to parse codeId = ${entity.id}`); return null;