enh
This commit is contained in:
parent
a0a05615b1
commit
b49015b446
4 changed files with 53 additions and 24 deletions
|
|
@ -16,7 +16,7 @@ import signedUrlCache from '@/src/lib/signed-url-cache';
|
|||
import { seed } from '@/src/db/seed';
|
||||
import '@/src/jobs/jobs-index';
|
||||
import { startAutomatedJobs } from '@/src/lib/automatedJobs';
|
||||
import { verifyToken } from '@/src/lib/jwt-utils';
|
||||
import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils';
|
||||
|
||||
seed()
|
||||
initFunc()
|
||||
|
|
@ -77,30 +77,35 @@ app.use('/api/trpc', createExpressMiddleware({
|
|||
if (authHeader?.startsWith('Bearer ')) {
|
||||
const token = authHeader.substring(7);
|
||||
try {
|
||||
const decoded = (await verifyToken(token)) as any;
|
||||
const decoded = await verifyToken(token);
|
||||
|
||||
// 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
|
||||
const staff = await db.query.staffUsers.findFirst({
|
||||
where: eq(staffUsers.id, decoded.staffId),
|
||||
where: eq(staffUsers.id, staffPayload.staffId),
|
||||
});
|
||||
|
||||
if (staff) {
|
||||
user=staffUser
|
||||
staffUser = {
|
||||
id: staff.id,
|
||||
name: staff.name,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
||||
const userPayload = decoded as UserJWTPayload;
|
||||
// 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
|
||||
const details = await db.query.userDetails.findFirst({
|
||||
where: eq(userDetails.userId, user.userId),
|
||||
where: eq(userDetails.userId, userPayload.userId),
|
||||
});
|
||||
|
||||
if (details?.isSuspended) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,20 @@
|
|||
import { SignJWT, jwtVerify, errors } from 'jose';
|
||||
import { SignJWT, jwtVerify, errors, JWTPayload } from 'jose';
|
||||
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
|
||||
const getSecret = () => {
|
||||
if (!jwtSecret) {
|
||||
|
|
@ -14,7 +28,7 @@ const getSecret = () => {
|
|||
* Compatible with tokens signed by jsonwebtoken library
|
||||
*/
|
||||
export const signToken = async (
|
||||
payload: Record<string, any>,
|
||||
payload: Record<string, unknown>,
|
||||
expiresIn: string = '7d'
|
||||
): Promise<string> => {
|
||||
const secret = getSecret();
|
||||
|
|
@ -30,7 +44,7 @@ export const signToken = async (
|
|||
* Verify a JWT token
|
||||
* 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 {
|
||||
const secret = getSecret();
|
||||
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
|
||||
*/
|
||||
export const isJWTError = (error: any): boolean => {
|
||||
export const isJWTError = (error: unknown): boolean => {
|
||||
return error instanceof errors.JOSEError ||
|
||||
error?.message?.includes('token') ||
|
||||
error?.message?.includes('JWT');
|
||||
(error instanceof Error && (
|
||||
error.message.includes('token') ||
|
||||
error.message.includes('JWT')
|
||||
));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index'
|
|||
import { staffUsers, userDetails } from '@/src/db/schema'
|
||||
import { eq } from 'drizzle-orm';
|
||||
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 {
|
||||
user?: {
|
||||
|
|
@ -29,13 +29,14 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
|
|||
const token = authHeader.substring(7);
|
||||
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)
|
||||
if (decoded.staffId) {
|
||||
if ('staffId' in decoded) {
|
||||
const staffPayload = decoded as StaffJWTPayload;
|
||||
// This is a staff token, verify staff exists
|
||||
const staff = await db.query.staffUsers.findFirst({
|
||||
where: eq(staffUsers.id, decoded.staffId),
|
||||
where: eq(staffUsers.id, staffPayload.staffId),
|
||||
});
|
||||
|
||||
if (!staff) {
|
||||
|
|
@ -47,12 +48,18 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
|
|||
name: staff.name,
|
||||
};
|
||||
} else {
|
||||
const userPayload = decoded as UserJWTPayload;
|
||||
// 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
|
||||
const details = await db.query.userDetails.findFirst({
|
||||
where: eq(userDetails.userId, decoded.userId),
|
||||
where: eq(userDetails.userId, userPayload.userId),
|
||||
});
|
||||
|
||||
if (details?.isSuspended) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { db } from '@/src/db/db_index'
|
|||
import { staffUsers } from '@/src/db/schema'
|
||||
import { eq } from 'drizzle-orm';
|
||||
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
|
||||
declare global {
|
||||
|
|
@ -20,9 +20,10 @@ declare global {
|
|||
/**
|
||||
* Verify JWT token and extract payload
|
||||
*/
|
||||
const verifyStaffToken = async (token: string) => {
|
||||
const verifyStaffToken = async (token: string): Promise<StaffJWTPayload> => {
|
||||
try {
|
||||
return await verifyToken(token);
|
||||
const payload = await verifyToken(token);
|
||||
return payload as StaffJWTPayload;
|
||||
} catch (error) {
|
||||
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
|
||||
const decoded = (await verifyStaffToken(token)) as any;
|
||||
const decoded = await verifyStaffToken(token);
|
||||
|
||||
// Verify staffId exists in token
|
||||
if (!decoded.staffId) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue