1
1
import { CryptoService } from '#common/helpers/crypto.service.js'
2
2
import { Context , Next } from 'hono'
3
- import { verify } from 'jsonwebtoken'
4
3
5
4
type Role = 'member' | 'moderator' | 'admin'
6
5
7
- const ROLE_PERMISSIONS : Record < Role , string [ ] > = {
8
- member : [ 'GET' ] ,
9
- moderator : [ 'GET' , 'POST' , 'PUT' , 'PATCH' ] ,
10
- admin : [ 'GET' , 'POST' , 'PUT' , 'PATCH' , 'DELETE' ]
6
+ const ROLE_PERMISSIONS : Record < Role , Set < string > > = {
7
+ member : new Set ( [ 'GET' ] ) ,
8
+ moderator : new Set ( [ 'GET' , 'POST' , 'PUT' , 'PATCH' ] ) ,
9
+ admin : new Set ( [ 'GET' , 'POST' , 'PUT' , 'PATCH' , 'DELETE' ] )
11
10
}
12
11
13
- const restrictedMethods = [ 'POST' , 'PUT' , 'PATCH' , 'DELETE' ]
12
+ const RESTRICTED_METHODS = new Set ( [ 'POST' , 'PUT' , 'PATCH' , 'DELETE' ] )
13
+ const VALID_ROLES = new Set ( [ 'member' , 'moderator' , 'admin' ] )
14
14
15
- function isValidRole ( role : string ) : role is Role {
16
- return [ 'member' , 'moderator' , 'admin' ] . includes ( role )
17
- }
18
15
const cryptoService = new CryptoService ( )
19
- const authenticationRoutes = [ '/api/v1/register' , '/api/v1/authenticate' ]
20
16
21
- /**
22
- * NOTE: REGISTRATION OF NEW USER ONLY ALLOWED IN STAGING EVIROMENT
23
- */
17
+ interface RouteConfig {
18
+ path : string
19
+ allowedEnvs : Set < string >
20
+ skipAuth ?: boolean
21
+ message ?: string
22
+ }
23
+
24
+ const ROUTE_CONFIG : RouteConfig [ ] = [
25
+ {
26
+ path : '/api/v1/register' ,
27
+ allowedEnvs : new Set ( [ 'development' , 'staging' ] ) ,
28
+ skipAuth : true ,
29
+ message : 'signup is not allowed in production'
30
+ } ,
31
+ { path : '/api/v1/authenticate' , allowedEnvs : new Set ( [ 'development' , 'staging' , 'production' ] ) , skipAuth : true }
32
+ // Add more routes as needed
33
+ ]
34
+
24
35
export async function authMiddleware ( c : Context , next : Next ) {
25
- const method = c . req . method
26
- const path = c . req . path
27
- // Skip middleware for /register and /authenticate routes
36
+ const { method, path } = c . req
37
+ const currentEnv = process . env . NODE_ENV || 'development'
28
38
29
- if ( authenticationRoutes . includes ( path ) && process . env . NODE_ENV !== 'production' ) {
30
- return next ( )
31
- }
32
- if ( authenticationRoutes . includes ( path ) && process . env . NODE_ENV === 'production' ) {
33
- return c . json ( { success : false , error : 'SIGNUP | LOGIN is not available in the production environment.' } , 403 )
34
- }
39
+ const routeConfig = ROUTE_CONFIG . find ( ( route ) => route . path === path )
35
40
36
- // Allow OPTIONS, HEAD, and other non-restricted methods for all
37
- if ( ! restrictedMethods . includes ( method ) ) {
38
- return next ( )
41
+ if ( routeConfig ) {
42
+ if ( ! routeConfig . allowedEnvs . has ( currentEnv ) ) {
43
+ return c . json (
44
+ {
45
+ success : false ,
46
+ error : routeConfig . message
47
+ ? routeConfig . message
48
+ : `This route is not available in the ${ currentEnv } environment.`
49
+ } ,
50
+ 403
51
+ )
52
+ }
53
+ if ( routeConfig . skipAuth ) {
54
+ return next ( )
55
+ }
39
56
}
57
+
58
+ if ( ! RESTRICTED_METHODS . has ( method ) ) return next ( )
59
+
40
60
const authorization = c . req . header ( 'Authorization' )
41
61
42
62
if ( ! authorization ) {
@@ -49,22 +69,15 @@ export async function authMiddleware(c: Context, next: Next) {
49
69
}
50
70
51
71
try {
52
- const userPayload = await cryptoService . verifyAccessToken ( token )
53
-
54
- if ( ! isValidRole ( userPayload . role ) ) {
55
- return c . json ( { success : false , error : 'Forbidden Request' } , 403 )
56
- }
57
- const allowedMethods = ROLE_PERMISSIONS [ userPayload . role ]
58
-
59
- if ( ! allowedMethods . includes ( method ) ) {
72
+ const userPayload = cryptoService . verifyAccessToken ( token )
73
+ if ( ! VALID_ROLES . has ( userPayload . role ) || ! ROLE_PERMISSIONS [ userPayload . role as Role ] . has ( method ) ) {
60
74
return c . json ( { success : false , error : 'Forbidden' } , 403 )
61
75
}
62
76
63
77
c . set ( 'user' , userPayload )
64
-
65
78
await next ( )
66
79
} catch ( error ) {
67
- console . log ( error )
80
+ console . error ( error )
68
81
return c . json ( { success : false , error : 'Invalid token' } , 401 )
69
82
}
70
83
}
0 commit comments