From 7806111f7deecfc75469f75d21b4c7870511b00e Mon Sep 17 00:00:00 2001 From: sianida26 Date: Sun, 12 May 2024 21:35:06 +0700 Subject: [PATCH] Added docs --- apps/backend/src/errors/DashboardError.ts | 29 ++++++++++++++++++-- apps/backend/src/utils/authUtils.ts | 33 +++++++++++++++++++++-- apps/backend/src/utils/httpErrors.ts | 7 ----- apps/backend/src/utils/passwordUtils.ts | 14 ++++++++++ 4 files changed, 72 insertions(+), 11 deletions(-) delete mode 100644 apps/backend/src/utils/httpErrors.ts diff --git a/apps/backend/src/errors/DashboardError.ts b/apps/backend/src/errors/DashboardError.ts index 41a6fb8..e7767be 100644 --- a/apps/backend/src/errors/DashboardError.ts +++ b/apps/backend/src/errors/DashboardError.ts @@ -1,26 +1,37 @@ import { StatusCode } from "hono/utils/http-status"; import DashboardErrorParameter from "../types/DashboardErrorParameter"; +/** + * Custom error class for handling specific dashboard-related errors with detailed context. + * + * @extends Error + */ class DashboardError extends Error { public readonly errorCode: string; public readonly statusCode: StatusCode = 500; - public readonly message: string; public readonly formErrors?: Record; public readonly severity: "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" = "CRITICAL"; + /** + * Creates an instance of DashboardError. + * @param options - Configuration object for the error. + */ constructor(options: DashboardErrorParameter) { super(options.message); this.errorCode = options.errorCode; this.statusCode = options.statusCode ?? this.statusCode; - this.message = options.message; this.formErrors = options.formErrors; Object.setPrototypeOf(this, new.target.prototype); } } +/** + * Throws a 'not found' error with customizable parameters. + * @param options - Optional parameters to override default not found error properties. + */ export const notFound = (options?: Partial) => { throw new DashboardError({ errorCode: options?.errorCode ?? "NOT_FOUND", @@ -31,6 +42,10 @@ export const notFound = (options?: Partial) => { }); }; +/** + * Throws an 'unauthorized' error with customizable parameters. + * @param options - Optional parameters to override default unauthorized error properties. + */ export const unauthorized = (options?: Partial) => { throw new DashboardError({ errorCode: options?.errorCode ?? "UNAUTHORIZED", @@ -41,4 +56,14 @@ export const unauthorized = (options?: Partial) => { }); }; +export const forbidden = (options?: Partial) => { + throw new DashboardError({ + errorCode: options?.errorCode ?? "FORBIDDEN", + message: options?.message ?? "Forbidden", + formErrors: options?.formErrors, + severity: options?.severity ?? "LOW", + statusCode: options?.statusCode ?? 403, + }); +}; + export default DashboardError; diff --git a/apps/backend/src/utils/authUtils.ts b/apps/backend/src/utils/authUtils.ts index 12807f3..d45e74a 100644 --- a/apps/backend/src/utils/authUtils.ts +++ b/apps/backend/src/utils/authUtils.ts @@ -1,14 +1,19 @@ import jwt from "jsonwebtoken"; +// Environment variables for secrets, defaulting to a random secret if not set. const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET ?? "some-random-secret"; const refreshTokenSecret = process.env.REFRESH_TOKEN_SECRET ?? "some-very-random-secret"; + +// Algorithm to be used for JWT encoding. const algorithm: jwt.Algorithm = "HS256"; -export const accessTokenExpiry: number | string | null = null; // null for no expiry -export const refreshTokenExpiry: number | string | null = "30d"; // null for no expiry +// Expiry settings for tokens. 'null' signifies no expiry. +export const accessTokenExpiry: number | string | null = null; +export const refreshTokenExpiry: number | string | null = "30d"; +// Interfaces to describe the payload structure for access and refresh tokens. interface AccessTokenPayload { uid: string; } @@ -17,6 +22,12 @@ interface RefreshTokenPayload { uid: string; } +/** + * Generates a JSON Web Token (JWT) for access control using a specified payload. + * + * @param payload - The payload containing user-specific data for the token. + * @returns A promise that resolves to the generated JWT string. + */ export const generateAccessToken = async (payload: AccessTokenPayload) => { const token = jwt.sign(payload, accessTokenSecret, { algorithm, @@ -25,6 +36,12 @@ export const generateAccessToken = async (payload: AccessTokenPayload) => { return token; }; +/** + * Generates a JSON Web Token (JWT) for refresh purposes using a specified payload. + * + * @param payload - The payload containing user-specific data for the token. + * @returns A promise that resolves to the generated JWT string. + */ export const generateRefreshToken = async (payload: RefreshTokenPayload) => { const token = jwt.sign(payload, refreshTokenSecret, { algorithm, @@ -33,6 +50,12 @@ export const generateRefreshToken = async (payload: RefreshTokenPayload) => { return token; }; +/** + * Verifies a given access token and decodes the payload if the token is valid. + * + * @param token - The JWT string to verify. + * @returns A promise that resolves to the decoded payload or null if verification fails. + */ export const verifyAccessToken = async (token: string) => { try { const payload = jwt.verify( @@ -45,6 +68,12 @@ export const verifyAccessToken = async (token: string) => { } }; +/** + * Verifies a given refresh token and decodes the payload if the token is valid. + * + * @param token - The JWT string to verify. + * @returns A promise that resolves to the decoded payload or null if verification fails. + */ export const verifyRefreshToken = async (token: string) => { try { const payload = jwt.verify( diff --git a/apps/backend/src/utils/httpErrors.ts b/apps/backend/src/utils/httpErrors.ts deleted file mode 100644 index a08795b..0000000 --- a/apps/backend/src/utils/httpErrors.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HTTPException } from "hono/http-exception"; - -export const forbidden = () => { - throw new HTTPException(403, { - message: "You are not allowed nor authorized to do this action", - }); -}; diff --git a/apps/backend/src/utils/passwordUtils.ts b/apps/backend/src/utils/passwordUtils.ts index 85ba823..69a3855 100644 --- a/apps/backend/src/utils/passwordUtils.ts +++ b/apps/backend/src/utils/passwordUtils.ts @@ -1,11 +1,25 @@ import bcrypt from "bcrypt"; +// Number of rounds for generating the salt. const saltRounds = 10; +/** + * Hashes a password using bcrypt with a predefined number of salt rounds. + * + * @param password - The plaintext password to hash. + * @returns A promise that resolves to the hashed password string. + */ export const hashPassword = async (password: string) => { return await bcrypt.hash(password, saltRounds); }; +/** + * Checks if a plaintext password matches a given hash. + * + * @param password - The plaintext password to verify. + * @param hash - The hash to compare against the password. + * @returns A promise that resolves to a boolean indicating whether the password matches the hash. + */ export const checkPassword = async (password: string, hash: string) => { return await bcrypt.compare(password, hash); };