Spaces:
Paused
Paused
Upload 60 files
Browse files- server/src/middleware/auth.ts +19 -5
- server/src/middleware/errorHandler.ts +1 -1
- server/src/routes/auth.ts +11 -11
- server/src/routes/upload.ts +6 -6
server/src/middleware/auth.ts
CHANGED
|
@@ -1,17 +1,31 @@
|
|
| 1 |
import { Request, Response, NextFunction } from 'express'
|
| 2 |
import jwt from 'jsonwebtoken'
|
| 3 |
import { prisma } from '../config/database'
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
export interface AuthRequest extends Request {
|
| 7 |
-
user?:
|
| 8 |
}
|
| 9 |
|
| 10 |
export const authMiddleware = async (
|
| 11 |
req: AuthRequest,
|
| 12 |
res: Response,
|
| 13 |
next: NextFunction
|
| 14 |
-
) => {
|
| 15 |
try {
|
| 16 |
const authHeader = req.headers.authorization
|
| 17 |
|
|
@@ -90,7 +104,7 @@ export const adminMiddleware = (
|
|
| 90 |
req: AuthRequest,
|
| 91 |
res: Response,
|
| 92 |
next: NextFunction
|
| 93 |
-
) => {
|
| 94 |
if (!req.user) {
|
| 95 |
return res.status(401).json({
|
| 96 |
success: false,
|
|
@@ -112,7 +126,7 @@ export const optionalAuthMiddleware = async (
|
|
| 112 |
req: AuthRequest,
|
| 113 |
res: Response,
|
| 114 |
next: NextFunction
|
| 115 |
-
) => {
|
| 116 |
try {
|
| 117 |
const authHeader = req.headers.authorization
|
| 118 |
|
|
|
|
| 1 |
import { Request, Response, NextFunction } from 'express'
|
| 2 |
import jwt from 'jsonwebtoken'
|
| 3 |
import { prisma } from '../config/database'
|
| 4 |
+
|
| 5 |
+
export interface AuthUser {
|
| 6 |
+
id: string
|
| 7 |
+
email: string
|
| 8 |
+
username: string
|
| 9 |
+
displayName: string
|
| 10 |
+
avatar: string | null
|
| 11 |
+
bio: string | null
|
| 12 |
+
isOnline: boolean
|
| 13 |
+
lastSeen: Date
|
| 14 |
+
isAdmin: boolean
|
| 15 |
+
isVerified: boolean
|
| 16 |
+
createdAt: Date
|
| 17 |
+
updatedAt: Date
|
| 18 |
+
}
|
| 19 |
|
| 20 |
export interface AuthRequest extends Request {
|
| 21 |
+
user?: AuthUser
|
| 22 |
}
|
| 23 |
|
| 24 |
export const authMiddleware = async (
|
| 25 |
req: AuthRequest,
|
| 26 |
res: Response,
|
| 27 |
next: NextFunction
|
| 28 |
+
): Promise<void> => {
|
| 29 |
try {
|
| 30 |
const authHeader = req.headers.authorization
|
| 31 |
|
|
|
|
| 104 |
req: AuthRequest,
|
| 105 |
res: Response,
|
| 106 |
next: NextFunction
|
| 107 |
+
): void => {
|
| 108 |
if (!req.user) {
|
| 109 |
return res.status(401).json({
|
| 110 |
success: false,
|
|
|
|
| 126 |
req: AuthRequest,
|
| 127 |
res: Response,
|
| 128 |
next: NextFunction
|
| 129 |
+
): Promise<void> => {
|
| 130 |
try {
|
| 131 |
const authHeader = req.headers.authorization
|
| 132 |
|
server/src/middleware/errorHandler.ts
CHANGED
|
@@ -97,7 +97,7 @@ export const notFoundHandler = (req: Request, res: Response) => {
|
|
| 97 |
})
|
| 98 |
}
|
| 99 |
|
| 100 |
-
export const asyncHandler = (fn:
|
| 101 |
return (req: Request, res: Response, next: NextFunction) => {
|
| 102 |
Promise.resolve(fn(req, res, next)).catch(next)
|
| 103 |
}
|
|
|
|
| 97 |
})
|
| 98 |
}
|
| 99 |
|
| 100 |
+
export const asyncHandler = (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) => {
|
| 101 |
return (req: Request, res: Response, next: NextFunction) => {
|
| 102 |
Promise.resolve(fn(req, res, next)).catch(next)
|
| 103 |
}
|
server/src/routes/auth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import { Router } from 'express'
|
| 2 |
import bcrypt from 'bcryptjs'
|
| 3 |
import jwt from 'jsonwebtoken'
|
| 4 |
import Joi from 'joi'
|
|
@@ -28,7 +28,7 @@ const changePasswordSchema = Joi.object({
|
|
| 28 |
})
|
| 29 |
|
| 30 |
// Helper function to generate JWT token
|
| 31 |
-
const generateToken = (userId: string) => {
|
| 32 |
return jwt.sign(
|
| 33 |
{ userId },
|
| 34 |
process.env.JWT_SECRET!,
|
|
@@ -37,12 +37,12 @@ const generateToken = (userId: string) => {
|
|
| 37 |
}
|
| 38 |
|
| 39 |
// Register
|
| 40 |
-
router.post('/register', authRateLimiter, asyncHandler(async (req, res) => {
|
| 41 |
const { error, value } = registerSchema.validate(req.body)
|
| 42 |
if (error) {
|
| 43 |
return res.status(400).json({
|
| 44 |
success: false,
|
| 45 |
-
error: error.details[0].message
|
| 46 |
})
|
| 47 |
}
|
| 48 |
|
|
@@ -105,12 +105,12 @@ router.post('/register', authRateLimiter, asyncHandler(async (req, res) => {
|
|
| 105 |
}))
|
| 106 |
|
| 107 |
// Login
|
| 108 |
-
router.post('/login', authRateLimiter, asyncHandler(async (req, res) => {
|
| 109 |
const { error, value } = loginSchema.validate(req.body)
|
| 110 |
if (error) {
|
| 111 |
return res.status(400).json({
|
| 112 |
success: false,
|
| 113 |
-
error: error.details[0].message
|
| 114 |
})
|
| 115 |
}
|
| 116 |
|
|
@@ -162,7 +162,7 @@ router.post('/login', authRateLimiter, asyncHandler(async (req, res) => {
|
|
| 162 |
}))
|
| 163 |
|
| 164 |
// Logout
|
| 165 |
-
router.post('/logout', authMiddleware, asyncHandler(async (req: AuthRequest, res) => {
|
| 166 |
// Update user offline status
|
| 167 |
await prisma.user.update({
|
| 168 |
where: { id: req.user!.id },
|
|
@@ -179,7 +179,7 @@ router.post('/logout', authMiddleware, asyncHandler(async (req: AuthRequest, res
|
|
| 179 |
}))
|
| 180 |
|
| 181 |
// Get current user
|
| 182 |
-
router.get('/me', authMiddleware, asyncHandler(async (req: AuthRequest, res) => {
|
| 183 |
res.json({
|
| 184 |
success: true,
|
| 185 |
data: req.user
|
|
@@ -187,12 +187,12 @@ router.get('/me', authMiddleware, asyncHandler(async (req: AuthRequest, res) =>
|
|
| 187 |
}))
|
| 188 |
|
| 189 |
// Change password
|
| 190 |
-
router.post('/change-password', authMiddleware, asyncHandler(async (req: AuthRequest, res) => {
|
| 191 |
const { error, value } = changePasswordSchema.validate(req.body)
|
| 192 |
if (error) {
|
| 193 |
return res.status(400).json({
|
| 194 |
success: false,
|
| 195 |
-
error: error.details[0].message
|
| 196 |
})
|
| 197 |
}
|
| 198 |
|
|
@@ -237,7 +237,7 @@ router.post('/change-password', authMiddleware, asyncHandler(async (req: AuthReq
|
|
| 237 |
}))
|
| 238 |
|
| 239 |
// Refresh token (optional - for token refresh functionality)
|
| 240 |
-
router.post('/refresh', asyncHandler(async (req, res) => {
|
| 241 |
const { refreshToken } = req.body
|
| 242 |
|
| 243 |
if (!refreshToken) {
|
|
|
|
| 1 |
+
import { Router, Request, Response } from 'express'
|
| 2 |
import bcrypt from 'bcryptjs'
|
| 3 |
import jwt from 'jsonwebtoken'
|
| 4 |
import Joi from 'joi'
|
|
|
|
| 28 |
})
|
| 29 |
|
| 30 |
// Helper function to generate JWT token
|
| 31 |
+
const generateToken = (userId: string): string => {
|
| 32 |
return jwt.sign(
|
| 33 |
{ userId },
|
| 34 |
process.env.JWT_SECRET!,
|
|
|
|
| 37 |
}
|
| 38 |
|
| 39 |
// Register
|
| 40 |
+
router.post('/register', authRateLimiter, asyncHandler(async (req: Request, res: Response) => {
|
| 41 |
const { error, value } = registerSchema.validate(req.body)
|
| 42 |
if (error) {
|
| 43 |
return res.status(400).json({
|
| 44 |
success: false,
|
| 45 |
+
error: error.details[0]?.message
|
| 46 |
})
|
| 47 |
}
|
| 48 |
|
|
|
|
| 105 |
}))
|
| 106 |
|
| 107 |
// Login
|
| 108 |
+
router.post('/login', authRateLimiter, asyncHandler(async (req: Request, res: Response) => {
|
| 109 |
const { error, value } = loginSchema.validate(req.body)
|
| 110 |
if (error) {
|
| 111 |
return res.status(400).json({
|
| 112 |
success: false,
|
| 113 |
+
error: error.details[0]?.message
|
| 114 |
})
|
| 115 |
}
|
| 116 |
|
|
|
|
| 162 |
}))
|
| 163 |
|
| 164 |
// Logout
|
| 165 |
+
router.post('/logout', authMiddleware, asyncHandler(async (req: AuthRequest, res: Response) => {
|
| 166 |
// Update user offline status
|
| 167 |
await prisma.user.update({
|
| 168 |
where: { id: req.user!.id },
|
|
|
|
| 179 |
}))
|
| 180 |
|
| 181 |
// Get current user
|
| 182 |
+
router.get('/me', authMiddleware, asyncHandler(async (req: AuthRequest, res: Response) => {
|
| 183 |
res.json({
|
| 184 |
success: true,
|
| 185 |
data: req.user
|
|
|
|
| 187 |
}))
|
| 188 |
|
| 189 |
// Change password
|
| 190 |
+
router.post('/change-password', authMiddleware, asyncHandler(async (req: AuthRequest, res: Response) => {
|
| 191 |
const { error, value } = changePasswordSchema.validate(req.body)
|
| 192 |
if (error) {
|
| 193 |
return res.status(400).json({
|
| 194 |
success: false,
|
| 195 |
+
error: error.details[0]?.message
|
| 196 |
})
|
| 197 |
}
|
| 198 |
|
|
|
|
| 237 |
}))
|
| 238 |
|
| 239 |
// Refresh token (optional - for token refresh functionality)
|
| 240 |
+
router.post('/refresh', asyncHandler(async (req: Request, res: Response) => {
|
| 241 |
const { refreshToken } = req.body
|
| 242 |
|
| 243 |
if (!refreshToken) {
|
server/src/routes/upload.ts
CHANGED
|
@@ -26,7 +26,7 @@ const upload = multer({
|
|
| 26 |
limits: {
|
| 27 |
fileSize: 10 * 1024 * 1024, // 10MB limit
|
| 28 |
},
|
| 29 |
-
fileFilter: (req, file, cb) => {
|
| 30 |
// Allow images, videos, audio, and documents
|
| 31 |
const allowedTypes = /jpeg|jpg|png|gif|webp|mp4|webm|mp3|wav|pdf|doc|docx|txt/
|
| 32 |
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase())
|
|
@@ -41,7 +41,7 @@ const upload = multer({
|
|
| 41 |
})
|
| 42 |
|
| 43 |
// Upload single file
|
| 44 |
-
router.post('/single', upload.single('file'), async (req: Request, res: Response) => {
|
| 45 |
try {
|
| 46 |
if (!req.file) {
|
| 47 |
return res.status(400).json({
|
|
@@ -72,7 +72,7 @@ router.post('/single', upload.single('file'), async (req: Request, res: Response
|
|
| 72 |
})
|
| 73 |
|
| 74 |
// Upload multiple files
|
| 75 |
-
router.post('/multiple', upload.array('files', 10), async (req: Request, res: Response) => {
|
| 76 |
try {
|
| 77 |
const files = req.files as Express.Multer.File[]
|
| 78 |
|
|
@@ -105,7 +105,7 @@ router.post('/multiple', upload.array('files', 10), async (req: Request, res: Re
|
|
| 105 |
})
|
| 106 |
|
| 107 |
// Upload avatar
|
| 108 |
-
router.post('/avatar', upload.single('avatar'), async (req: Request, res: Response) => {
|
| 109 |
try {
|
| 110 |
if (!req.file) {
|
| 111 |
return res.status(400).json({
|
|
@@ -142,10 +142,10 @@ router.post('/avatar', upload.single('avatar'), async (req: Request, res: Respon
|
|
| 142 |
})
|
| 143 |
|
| 144 |
// Delete file
|
| 145 |
-
router.delete('/:filename', async (req: Request, res: Response) => {
|
| 146 |
try {
|
| 147 |
const { filename } = req.params
|
| 148 |
-
const filePath = path.join(__dirname, '../../uploads', filename)
|
| 149 |
|
| 150 |
if (fs.existsSync(filePath)) {
|
| 151 |
fs.unlinkSync(filePath)
|
|
|
|
| 26 |
limits: {
|
| 27 |
fileSize: 10 * 1024 * 1024, // 10MB limit
|
| 28 |
},
|
| 29 |
+
fileFilter: (req, file, cb): void => {
|
| 30 |
// Allow images, videos, audio, and documents
|
| 31 |
const allowedTypes = /jpeg|jpg|png|gif|webp|mp4|webm|mp3|wav|pdf|doc|docx|txt/
|
| 32 |
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase())
|
|
|
|
| 41 |
})
|
| 42 |
|
| 43 |
// Upload single file
|
| 44 |
+
router.post('/single', upload.single('file'), async (req: Request, res: Response): Promise<void> => {
|
| 45 |
try {
|
| 46 |
if (!req.file) {
|
| 47 |
return res.status(400).json({
|
|
|
|
| 72 |
})
|
| 73 |
|
| 74 |
// Upload multiple files
|
| 75 |
+
router.post('/multiple', upload.array('files', 10), async (req: Request, res: Response): Promise<void> => {
|
| 76 |
try {
|
| 77 |
const files = req.files as Express.Multer.File[]
|
| 78 |
|
|
|
|
| 105 |
})
|
| 106 |
|
| 107 |
// Upload avatar
|
| 108 |
+
router.post('/avatar', upload.single('avatar'), async (req: Request, res: Response): Promise<void> => {
|
| 109 |
try {
|
| 110 |
if (!req.file) {
|
| 111 |
return res.status(400).json({
|
|
|
|
| 142 |
})
|
| 143 |
|
| 144 |
// Delete file
|
| 145 |
+
router.delete('/:filename', async (req: Request, res: Response): Promise<void> => {
|
| 146 |
try {
|
| 147 |
const { filename } = req.params
|
| 148 |
+
const filePath = path.join(__dirname, '../../uploads', filename!)
|
| 149 |
|
| 150 |
if (fs.existsSync(filePath)) {
|
| 151 |
fs.unlinkSync(filePath)
|