@@ -9,6 +9,11 @@ import multer from 'multer';
99import axios from 'axios' ;
1010import swaggerUi from 'swagger-ui-express' ;
1111import { v4 as uuidv4 } from 'uuid' ;
12+ import dotenv from 'dotenv' ;
13+ import jwt from 'jsonwebtoken' ;
14+
15+ dotenv . config ( ) ;
16+
1217
1318/* Utility to get __dirname in ES modules */
1419const __filename = fileURLToPath ( import . meta. url ) ;
@@ -36,6 +41,33 @@ const openApiFilePath = path.join(__dirname, 'openapi.json');
3641const openApiDocument = JSON . parse ( fs . readFileSync ( openApiFilePath , 'utf8' ) ) ;
3742app . use ( '/api-docs' , swaggerUi . serve , swaggerUi . setup ( openApiDocument ) ) ;
3843
44+
45+ /* Security Middleware */
46+ const authenticateToken = ( req , res , next ) => {
47+ const authHeader = req . headers [ 'authorization' ] ;
48+ const token = authHeader && authHeader . split ( ' ' ) [ 1 ] ;
49+ if ( ! token ) return res . status ( 401 ) . json ( {
50+ "status" : "ERROR" ,
51+ "code" : 401 ,
52+ "message" : "Unauthorized access" ,
53+ "payload" : { }
54+ } ) ;
55+
56+ jwt . verify ( token , process . env . JWT_KEY , ( err , decoded ) => {
57+ if ( err || ( decoded . expire_at == undefined || decoded . issued_at == undefined || decoded . issuer == undefined || decoded . namespace == undefined ) ) {
58+ return res . status ( 401 ) . json ( {
59+ "status" : "ERROR" ,
60+ "code" : 401 ,
61+ "message" : "Unauthorized access" ,
62+ "payload" : { }
63+ } ) ;
64+ }
65+ req . decoded = decoded ;
66+ next ( ) ;
67+ } ) ;
68+ } ;
69+
70+
3971app . get ( '/server/health' , ( req , res ) => {
4072 res . status ( 200 ) . send ( 'OK' ) ;
4173} ) ;
@@ -44,29 +76,32 @@ app.head('/server/health', (req, res) => {
4476 res . status ( 200 ) . send ( ) ;
4577} ) ;
4678
47- app . get ( '/function/list' , ( req , res ) => {
48- fs . readdir ( ' functions' , ( err , files ) => {
79+ app . get ( '/function/list' , authenticateToken , ( req , res ) => {
80+ fs . readdir ( ` functions/ ${ req . decoded . namespace } ` , ( err , files ) => {
4981 if ( err ) {
5082 return res . status ( 500 ) . json ( {
5183 "status" : "ERROR" ,
5284 "code" : 500 ,
53- "message" : err . message ,
85+ "message" : "Namespace does not exist, create function before listing" ,
5486 "payload" : { }
5587 } ) ;
5688 }
5789
90+ // Remove extensions from filenames
91+ const fileNamesWithoutExtension = files . map ( file => path . basename ( file , path . extname ( file ) ) ) ;
92+
5893 res . status ( 200 ) . json ( {
5994 "status" : "OK" ,
6095 "code" : 200 ,
6196 "message" : "" ,
6297 "payload" : {
63- "functions " : files
98+ "function_ids " : fileNamesWithoutExtension
6499 }
65100 } ) ;
66101 } ) ;
67102} ) ;
68103
69- app . post ( '/function/create' , upload . single ( 'file' ) , ( req , res ) => {
104+ app . post ( '/function/create' , authenticateToken , upload . single ( 'file' ) , ( req , res ) => {
70105 if ( ! req . file ) {
71106 return res . status ( 400 ) . json ( {
72107 "status" : "ERROR" ,
@@ -79,7 +114,16 @@ app.post('/function/create', upload.single('file'), (req, res) => {
79114 const file = req . file ;
80115 const file_id = generateAlphanumericName ( 25 ) ;
81116 const file_name = `${ file_id } .mjs` ;
82- fs . renameSync ( file . path , `functions/${ file_name } ` ) ;
117+ const directory = `functions/${ req . decoded . namespace } ` ;
118+
119+ // Ensure the directory exists
120+ if ( ! fs . existsSync ( directory ) ) {
121+ fs . mkdirSync ( directory , { recursive : true } ) ;
122+ }
123+
124+ // Rename the uploaded file and move it to the correct directory
125+ fs . renameSync ( file . path , path . join ( directory , file_name ) ) ;
126+
83127 res . status ( 200 ) . json ( {
84128 "status" : "OK" ,
85129 "code" : 200 ,
@@ -90,16 +134,16 @@ app.post('/function/create', upload.single('file'), (req, res) => {
90134 } ) ;
91135} ) ;
92136
93- app . delete ( '/function/:function_id' , ( req , res ) => {
137+ app . delete ( '/function/:function_id' , authenticateToken , ( req , res ) => {
94138 const function_id = req . params . function_id ;
95139 const file_name = `${ function_id } .mjs` ;
96140
97- fs . unlink ( `functions/${ file_name } ` , ( err ) => {
141+ fs . unlink ( `functions/${ req . decoded . namespace } / ${ file_name } ` , ( err ) => {
98142 if ( err ) {
99143 return res . status ( 500 ) . json ( {
100144 "status" : "ERROR" ,
101145 "code" : 500 ,
102- "message" : err . message ,
146+ "message" : "Failed to delete function" ,
103147 "payload" : { }
104148 } ) ;
105149 }
@@ -113,16 +157,16 @@ app.delete('/function/:function_id', (req, res) => {
113157 } ) ;
114158} ) ;
115159
116- app . post ( '/function/execute/:function_id' , async ( req , res ) => {
160+ app . post ( '/function/execute/:function_id' , authenticateToken , async ( req , res ) => {
117161 await new Promise ( ( resolve , reject ) => {
118162 if ( ! req . body || Object . keys ( req . body ) . length === 0 ) {
119163 reject ( new Error ( "Request body is empty or not valid JSON" ) ) ;
120164 return ;
121165 }
122166 const function_id = req . params . function_id ;
123- fs . readFile ( `functions/${ function_id } .mjs` , 'utf8' , ( err , code ) => {
167+ fs . readFile ( `functions/${ req . decoded . namespace } / ${ function_id } .mjs` , 'utf8' , ( err , code ) => {
124168 if ( err ) {
125- reject ( new Error ( err . message ) ) ;
169+ reject ( new Error ( "Function does not exist" ) ) ;
126170 return ;
127171 }
128172 const { event_name, event_data } = req . body ;
0 commit comments