This commit is contained in:
shafi54 2026-03-22 16:38:37 +05:30
parent a0a05615b1
commit b49015b446
4 changed files with 53 additions and 24 deletions

View file

@ -16,7 +16,7 @@ import signedUrlCache from '@/src/lib/signed-url-cache';
import { seed } from '@/src/db/seed'; import { seed } from '@/src/db/seed';
import '@/src/jobs/jobs-index'; import '@/src/jobs/jobs-index';
import { startAutomatedJobs } from '@/src/lib/automatedJobs'; import { startAutomatedJobs } from '@/src/lib/automatedJobs';
import { verifyToken } from '@/src/lib/jwt-utils'; import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils';
seed() seed()
initFunc() initFunc()
@ -77,30 +77,35 @@ app.use('/api/trpc', createExpressMiddleware({
if (authHeader?.startsWith('Bearer ')) { if (authHeader?.startsWith('Bearer ')) {
const token = authHeader.substring(7); const token = authHeader.substring(7);
try { try {
const decoded = (await verifyToken(token)) as any; const decoded = await verifyToken(token);
// Check if this is a staff token (has staffId) // Check if this is a staff token (has staffId)
if (decoded.staffId) { if ('staffId' in decoded) {
const staffPayload = decoded as StaffJWTPayload;
// This is a staff token, verify staff exists // This is a staff token, verify staff exists
const staff = await db.query.staffUsers.findFirst({ const staff = await db.query.staffUsers.findFirst({
where: eq(staffUsers.id, decoded.staffId), where: eq(staffUsers.id, staffPayload.staffId),
}); });
if (staff) { if (staff) {
user=staffUser
staffUser = { staffUser = {
id: staff.id, id: staff.id,
name: staff.name, name: staff.name,
}; };
} }
} else { } else {
const userPayload = decoded as UserJWTPayload;
// This is a regular user token // This is a regular user token
user = decoded; user = {
userId: userPayload.userId,
name: userPayload.name,
email: userPayload.email,
mobile: userPayload.mobile,
};
// Check if user is suspended // Check if user is suspended
const details = await db.query.userDetails.findFirst({ const details = await db.query.userDetails.findFirst({
where: eq(userDetails.userId, user.userId), where: eq(userDetails.userId, userPayload.userId),
}); });
if (details?.isSuspended) { if (details?.isSuspended) {

View file

@ -1,6 +1,20 @@
import { SignJWT, jwtVerify, errors } from 'jose'; import { SignJWT, jwtVerify, errors, JWTPayload } from 'jose';
import { jwtSecret } from './env-exporter'; import { jwtSecret } from './env-exporter';
// JWT Payload Types
export interface UserJWTPayload extends JWTPayload {
userId: number;
name?: string;
email?: string;
mobile?: string;
roles?: string[];
}
export interface StaffJWTPayload extends JWTPayload {
staffId: number;
name: string;
}
// Convert string secret to Uint8Array // Convert string secret to Uint8Array
const getSecret = () => { const getSecret = () => {
if (!jwtSecret) { if (!jwtSecret) {
@ -14,7 +28,7 @@ const getSecret = () => {
* Compatible with tokens signed by jsonwebtoken library * Compatible with tokens signed by jsonwebtoken library
*/ */
export const signToken = async ( export const signToken = async (
payload: Record<string, any>, payload: Record<string, unknown>,
expiresIn: string = '7d' expiresIn: string = '7d'
): Promise<string> => { ): Promise<string> => {
const secret = getSecret(); const secret = getSecret();
@ -30,7 +44,7 @@ export const signToken = async (
* Verify a JWT token * Verify a JWT token
* Compatible with tokens signed by jsonwebtoken library * Compatible with tokens signed by jsonwebtoken library
*/ */
export const verifyToken = async (token: string): Promise<Record<string, any>> => { export const verifyToken = async (token: string): Promise<JWTPayload> => {
try { try {
const secret = getSecret(); const secret = getSecret();
const { payload } = await jwtVerify(token, secret); const { payload } = await jwtVerify(token, secret);
@ -49,8 +63,10 @@ export const verifyToken = async (token: string): Promise<Record<string, any>> =
/** /**
* Check if an error is a JWT-related error * Check if an error is a JWT-related error
*/ */
export const isJWTError = (error: any): boolean => { export const isJWTError = (error: unknown): boolean => {
return error instanceof errors.JOSEError || return error instanceof errors.JOSEError ||
error?.message?.includes('token') || (error instanceof Error && (
error?.message?.includes('JWT'); error.message.includes('token') ||
error.message.includes('JWT')
));
}; };

View file

@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index'
import { staffUsers, userDetails } from '@/src/db/schema' import { staffUsers, userDetails } from '@/src/db/schema'
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
import { ApiError } from '@/src/lib/api-error' import { ApiError } from '@/src/lib/api-error'
import { verifyToken } from '@/src/lib/jwt-utils' import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils'
interface AuthenticatedRequest extends Request { interface AuthenticatedRequest extends Request {
user?: { user?: {
@ -29,13 +29,14 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
const token = authHeader.substring(7); const token = authHeader.substring(7);
console.log(req.headers) console.log(req.headers)
const decoded = (await verifyToken(token)) as any; const decoded = await verifyToken(token);
// Check if this is a staff token (has staffId) // Check if this is a staff token (has staffId)
if (decoded.staffId) { if ('staffId' in decoded) {
const staffPayload = decoded as StaffJWTPayload;
// This is a staff token, verify staff exists // This is a staff token, verify staff exists
const staff = await db.query.staffUsers.findFirst({ const staff = await db.query.staffUsers.findFirst({
where: eq(staffUsers.id, decoded.staffId), where: eq(staffUsers.id, staffPayload.staffId),
}); });
if (!staff) { if (!staff) {
@ -47,12 +48,18 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
name: staff.name, name: staff.name,
}; };
} else { } else {
const userPayload = decoded as UserJWTPayload;
// This is a regular user token // This is a regular user token
req.user = decoded; req.user = {
userId: userPayload.userId,
name: userPayload.name,
email: userPayload.email,
mobile: userPayload.mobile,
};
// Check if user is suspended // Check if user is suspended
const details = await db.query.userDetails.findFirst({ const details = await db.query.userDetails.findFirst({
where: eq(userDetails.userId, decoded.userId), where: eq(userDetails.userId, userPayload.userId),
}); });
if (details?.isSuspended) { if (details?.isSuspended) {

View file

@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index'
import { staffUsers } from '@/src/db/schema' import { staffUsers } from '@/src/db/schema'
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
import { ApiError } from '@/src/lib/api-error' import { ApiError } from '@/src/lib/api-error'
import { verifyToken } from '@/src/lib/jwt-utils' import { verifyToken, StaffJWTPayload } from '@/src/lib/jwt-utils'
// Extend Request interface to include staffUser // Extend Request interface to include staffUser
declare global { declare global {
@ -20,9 +20,10 @@ declare global {
/** /**
* Verify JWT token and extract payload * Verify JWT token and extract payload
*/ */
const verifyStaffToken = async (token: string) => { const verifyStaffToken = async (token: string): Promise<StaffJWTPayload> => {
try { try {
return await verifyToken(token); const payload = await verifyToken(token);
return payload as StaffJWTPayload;
} catch (error) { } catch (error) {
throw new ApiError('Access denied. Invalid auth credentials', 401); throw new ApiError('Access denied. Invalid auth credentials', 401);
} }
@ -47,7 +48,7 @@ export const authenticateStaff = async (req: Request, res: Response, next: NextF
} }
// Verify token and extract payload // Verify token and extract payload
const decoded = (await verifyStaffToken(token)) as any; const decoded = await verifyStaffToken(token);
// Verify staffId exists in token // Verify staffId exists in token
if (!decoded.staffId) { if (!decoded.staffId) {