@@ -14,58 +14,26 @@ type MailOptions = {
14
14
} [ ] ;
15
15
} ;
16
16
17
- const RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000 ;
18
- const RATE_LIMIT_MAX_REQUESTS = 3 ;
19
-
20
- const rateLimitStore : Record < string , { count : number ; lastRequest : number } > =
21
- { } ;
22
- function isRateLimited ( ip : string ) {
23
- const currentTime = Date . now ( ) ;
24
- const record = rateLimitStore [ ip ] ;
25
-
26
- if ( record ) {
27
- if ( currentTime - record . lastRequest > RATE_LIMIT_WINDOW_MS ) {
28
- rateLimitStore [ ip ] = { count : 1 , lastRequest : currentTime } ;
29
- return false ;
30
- } else {
31
- if ( record . count >= RATE_LIMIT_MAX_REQUESTS ) {
32
- return true ;
33
- } else {
34
- record . count ++ ;
35
- record . lastRequest = currentTime ;
36
- return false ;
37
- }
38
- }
39
- } else {
40
- rateLimitStore [ ip ] = { count : 1 , lastRequest : currentTime } ;
41
- return false ;
42
- }
43
- }
17
+ // Allowed MIME types for PDF and image files
18
+ const ALLOWED_MIME_TYPES = [ "application/pdf" , "image/jpeg" , "image/png" , "image/gif" ] ;
19
+ const MAX_FILE_SIZE_MB = 5 ; // Limit file size to 5 MB
44
20
45
21
export async function POST ( request : Request ) {
46
22
try {
47
23
const formData = await request . formData ( ) ;
48
24
49
25
const ip =
50
- request . headers . get ( "x-real-ip" ) ??
51
- request . headers . get ( "x-forwarded-for" ) ??
26
+ request . headers . get ( "x-real-ip" ) ??
27
+ request . headers . get ( "x-forwarded-for" ) ??
52
28
request . headers . get ( "remote-addr" ) ;
53
29
54
30
if ( ! ip ) {
55
31
return NextResponse . json (
56
- { message : "IP address not found" } ,
57
- { status : 400 } ,
32
+ { message : "IP address not found" } ,
33
+ { status : 400 }
58
34
) ;
59
35
}
60
36
61
- // Uncomment to enable rate-limiter
62
- // if (isRateLimited(ip)) {
63
- // return NextResponse.json(
64
- // { message: "Too many requests. Please try again later." },
65
- // { status: 429 },
66
- // );
67
- // }
68
-
69
37
const transporter = nodemailer . createTransport ( {
70
38
host : process . env . EMAIL_HOST ,
71
39
port : parseInt ( process ! . env . EMAIL_PORT as string ) ,
@@ -76,11 +44,10 @@ export async function POST(request: Request) {
76
44
} ,
77
45
} ) ;
78
46
79
- const zipFile = formData . get ( "zipFile" ) ;
80
- const slot = formData . get ( "slot" ) ?. toString ( ) ?? '' ;
81
- const subject = formData . get ( "subject" ) ?. toString ( ) ?? '' ;
82
- const exam = formData . get ( "exam" ) ?. toString ( ) ?? '' ;
83
- const year = formData . get ( "year" ) ?. toString ( ) ?? '' ;
47
+ const slot = formData . get ( "slot" ) ?. toString ( ) ?? "" ;
48
+ const subject = formData . get ( "subject" ) ?. toString ( ) ?? "" ;
49
+ const exam = formData . get ( "exam" ) ?. toString ( ) ?? "" ;
50
+ const year = formData . get ( "year" ) ?. toString ( ) ?? "" ;
84
51
85
52
const htmlContent = `
86
53
<div style="font-family: Arial, sans-serif; line-height: 1.5;">
@@ -92,32 +59,52 @@ export async function POST(request: Request) {
92
59
</div>
93
60
` ;
94
61
62
+ const attachments : { filename : string ; content : Buffer } [ ] = [ ] ;
63
+ const files = formData . getAll ( "files" ) ;
64
+
65
+ // Validate files and prepare attachments
66
+ for ( const file of files ) {
67
+ if ( file instanceof Blob ) {
68
+ const fileType = file . type ;
69
+ const fileSizeMB = file . size / ( 1024 * 1024 ) ; // Convert size to MB
70
+
71
+ if ( ! ALLOWED_MIME_TYPES . includes ( fileType ) ) {
72
+ return NextResponse . json (
73
+ { message : `File type not allowed: ${ fileType } ` } ,
74
+ { status : 400 }
75
+ ) ;
76
+ }
77
+
78
+ if ( fileSizeMB > MAX_FILE_SIZE_MB ) {
79
+ return NextResponse . json (
80
+ { message : `File ${ file . name } exceeds the 5MB size limit` } ,
81
+ { status : 400 }
82
+ ) ;
83
+ }
84
+
85
+ const buffer = await file . arrayBuffer ( ) ;
86
+ attachments . push ( {
87
+ filename : ( file as any ) . name ,
88
+ content : Buffer . from ( buffer ) ,
89
+ } ) ;
90
+ }
91
+ }
92
+
95
93
const mailOptions : MailOptions = {
96
94
from : process . env . EMAIL_USER ! ,
97
95
to : process . env . EMAIL_USER ! ,
98
96
subject : subject ,
99
97
html : htmlContent ,
100
- attachments : [ ] ,
98
+ attachments,
101
99
} ;
102
100
103
- if ( zipFile instanceof Blob ) {
104
- const buffer = await zipFile . arrayBuffer ( ) ;
105
- const content = Buffer . from ( buffer ) ;
106
-
107
- mailOptions . attachments ! . push ( {
108
- filename : "files.zip" ,
109
- content : content ,
110
- } ) ;
111
- }
112
-
113
101
await transporter . sendMail ( mailOptions ) ;
114
102
115
103
return NextResponse . json ( { message : "Email sent successfully!" } , { status : 200 } ) ;
116
104
} catch ( error ) {
117
105
return NextResponse . json (
118
106
{ message : "Error sending email" , error : error } ,
119
- { status : 422 } ,
107
+ { status : 422 }
120
108
) ;
121
109
}
122
110
}
123
-
0 commit comments