diff --git a/.drone.yml b/.drone.yml index 80d000e..a33dd31 100644 --- a/.drone.yml +++ b/.drone.yml @@ -20,7 +20,7 @@ steps: repo: swiftlogiclabs/cdn-app-insider tags: - latest - - v1.0.0-beta.12 + - v1.0.0-beta.13 dockerfile: Dockerfile username: from_secret: docker_username diff --git a/Dockerfile b/Dockerfile index 86feb8c..d143103 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20 +FROM node:22 WORKDIR /srv/docker/cdn-app-insider diff --git a/models/swagger.js b/models/swagger.js index 0ccd002..22f7690 100644 --- a/models/swagger.js +++ b/models/swagger.js @@ -4,12 +4,11 @@ const swaggerUi = require('swagger-ui-express'); const swaggerOptions = { swaggerDefinition: { info: { - title: 'API - ManageMate', - version: '1.0-beta.1', - description: 'This documentation describes the ManageMate API.', + title: 'API - CDN-APP', + version: '1.0.0-beta.13', + description: 'This documentation describes the CDN-APP API.', }, - servers: [{ url: 'http://localhost:' + (process.env.PORT || 35665) }], - basePath: '/api/v1/', + basePath: '/api/dpanel/', }, apis: ['./routes/Dpanel/Api/*.js'], }; diff --git a/package.json b/package.json index c1c474b..f6418c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cdn-app/insider-swiftlogic-labs-dinawo", - "version": "1.0.0-beta.12", + "version": "1.0.0-beta.13", "description": "", "main": "server.js", "scripts": { diff --git a/public/css/styles.css b/public/css/styles.css index e0e3893..95246a7 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -117,6 +117,7 @@ background-color: #5b5b82; } + body.dark-theme .navbar-toggler-icon { filter: invert(1); } @@ -168,3 +169,32 @@ body.dark-theme .navbar-toggler-icon { padding: 0.5em; } +.custom-dropdown, +.animated-button { + position: relative; + background: #1d2429; + border: none; + cursor: pointer; + padding: 10px 20px; + font-size: 1em; + color: #17a2b8; + transition: all 0.3s ease; +} + +body.white-theme .custom-dropdown, +body.white-theme .animated-button { + color: #6c757d; + background: #e9ecef; +} + +.custom-dropdown:hover, +.animated-button:hover { + background: #343a40; + color: #fff; +} + +body.white-theme .custom-dropdown:hover, +body.white-theme .animated-button:hover { + background: #343a40; + color: #fff; +} \ No newline at end of file diff --git a/routes/Auth/ActiveDirectory.js b/routes/Auth/ActiveDirectory.js index f51eec6..5cf311b 100644 --- a/routes/Auth/ActiveDirectory.js +++ b/routes/Auth/ActiveDirectory.js @@ -14,10 +14,10 @@ const limiter = rateLimit({ router.post('/', limiter, (req, res, next) => { passport.authenticate('ActiveDirectory', (err, user) => { if (err) { - return res.render('AuthLogin', { isAuthenticated: false, errorMessage: err.message, setupData: {}, showActiveDirectoryForm: true, currentUrl: req.originalUrl }); + return res.json({ isAuthenticated: false, errorMessage: err.message, setupData: {}, showActiveDirectoryForm: true, currentUrl: req.originalUrl }); } if (!user) { - return res.render('AuthLogin', { isAuthenticated: false, errorMessage: 'L\'utilisateur n\'est pas autorisé.', setupData: {}, showActiveDirectoryForm: true, currentUrl: req.originalUrl }); + return res.json({ isAuthenticated: false, errorMessage: 'User is not authorized.', setupData: {}, showActiveDirectoryForm: true, currentUrl: req.originalUrl }); } req.user = { ...user._json, diff --git a/routes/Dpanel/API/BackgroundCustom.js b/routes/Dpanel/API/BackgroundCustom.js index d9e489e..99d1f77 100644 --- a/routes/Dpanel/API/BackgroundCustom.js +++ b/routes/Dpanel/API/BackgroundCustom.js @@ -1,16 +1,166 @@ const express = require('express'); +const fs = require('fs'); +const path = require('path'); const router = express.Router(); +const fileUpload = require('express-fileupload'); const authMiddleware = require('../../../Middlewares/authMiddleware'); +const { loggers } = require('winston'); +const ncp = require('ncp').ncp; +let configFile = fs.readFileSync(path.join(__dirname, '../../../data', 'setup.json'), 'utf-8') +let config = JSON.parse(configFile)[0]; +const bodyParser = require('body-parser'); +const crypto = require('crypto'); +const os = require('os'); +const { getUserData, getSetupData } = require('../../../Middlewares/watcherMiddleware'); -router.post('/', authMiddleware, (req, res) => { - const { backgroundUrl } = req.body; +let setupData = getSetupData(); +let userData = getUserData(); +router.use(bodyParser.json()); - if (!backgroundUrl) { - return res.status(400).json({ message: 'Background URL missing.' }); +/** + * @swagger + * /dashboard/getfilefolder/{folderName}?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - Folder + * summary: Get files and folders in a specific folder + * description: This route allows you to get the files and folders in a specific folder. It requires a valid JWT token in the Authorization header. + * parameters: + * - in: path + * name: folderName + * required: true + * schema: + * type: string + * description: The name of the folder + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * files: + * type: array + * items: + * type: object + * properties: + * name: + * type: string + * type: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 404: + * description: The specified folder does not exist + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 500: + * description: Internal server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + + +function authenticateToken(req, res, next) { + let token = null; + const authHeader = req.headers['authorization']; + + if (authHeader) { + token = authHeader.split(' ')[1]; + } else if (req.query.token) { + token = req.query.token; } + + if (token == null) { + if (req.user) { + return next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + } + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + console.error('Error reading user.json:', err); + return res.status(401).json({ message: 'Unauthorized' }); + } + + const users = JSON.parse(data); + + const user = users.find(u => u.token === token); + + if (user) { + req.user = user; + req.userData = user; + next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + }); + } - res.cookie('background', backgroundUrl, { httpOnly: true }); - res.status(200).json({ message: 'Background updated successfully.' }); +router.get('/wallpaper', authenticateToken, (req, res) => { + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + return res.status(500).send('Error reading the file'); + } + const users = JSON.parse(data); + const user = users.find(u => u.token === req.userData.token); + + res.json({ wallpaper: user.wallpaper || null }); + }); +}); + +router.post('/wallpaper', authenticateToken, (req, res) => { + const newWallpaper = req.body.wallpaper; + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + return res.status(500).send('Error reading the file'); + } + + let users = JSON.parse(data); + const userIndex = users.findIndex(u => u.token === req.userData.token); + + if (userIndex !== -1) { + users[userIndex].wallpaper = newWallpaper; + + fs.writeFile(path.join(__dirname, '../../../data', 'user.json'), JSON.stringify(users, null, 2), (err) => { + if (err) { + return res.status(500).send('Error writing to the file'); + } + res.send('Wallpaper updated'); + }); + } else { + res.status(401).send('Unauthorized'); + } + }); }); module.exports = router; \ No newline at end of file diff --git a/routes/Dpanel/API/DeleteFile.js b/routes/Dpanel/API/DeleteFile.js index e6340c0..9e4ea54 100644 --- a/routes/Dpanel/API/DeleteFile.js +++ b/routes/Dpanel/API/DeleteFile.js @@ -18,49 +18,129 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/deletefile?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Delete a specific file for a user + * description: This route allows you to delete a specific file for a user. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * filename: + * type: string + * description: The name of the file to delete + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 404: + * description: The specified file does not exist + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * message: + * type: string + * 500: + * description: Internal server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + + function authenticateToken(req, res, next) { let token = null; const authHeader = req.headers['authorization']; - + if (authHeader) { - token = authHeader.split(' ')[1]; + token = authHeader.split(' ')[1]; } else if (req.query.token) { - token = req.query.token; + token = req.query.token; } - - if (token == null) { - if (req.user) { - return next(); - } else { - return res.status(401).json({ message: 'Unauthorized' }); - } + + if (!token) { + return res.status(401).json({ message: 'Unauthorized: No token provided' }); } - + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { - if (err) { - console.error('Error reading user.json:', err); - return res.status(401).json({ message: 'Unauthorized' }); - } - - const users = JSON.parse(data); - - const user = users.find(u => u.token === token); - - if (user) { + if (err) { + console.error('Error reading user.json:', err); + return res.status(500).json({ message: 'Internal server error' }); + } + + const users = JSON.parse(data); + const user = users.find(u => u.token === token); + + if (!user) { + return res.status(401).json({ message: 'Unauthorized: Invalid token' }); + } + req.user = user; req.userData = user; next(); - } else { - return res.status(401).json({ message: 'Unauthorized' }); - } }); - } +} + router.get('/', (req, res) => { res.status(400).json({ error: 'Bad Request. The request cannot be fulfilled due to bad syntax or missing parameters.' }); }); router.post('/', authenticateToken, (req, res) => { + if (!req.userData) { + return res.status(401).json({ message: 'Authentication failed.' }); + } + const userId = req.userData.name; const { filename } = req.body; @@ -90,6 +170,7 @@ router.post('/', authenticateToken, (req, res) => { fs.unlinkSync(filePath); return true; } catch (error) { + console.error('Error deleting file:', error); return false; } } @@ -107,9 +188,9 @@ router.post('/', authenticateToken, (req, res) => { } }); + const ncpAsync = (source, destination) => { - const userFolderPath = path.join('cdn-files', userId); - if (!source.startsWith(userFolderPath) || !destination.startsWith(userFolderPath)) { + if (!source.startsWith('cdn-files') || !destination.startsWith('cdn-files')) { throw new Error('Unauthorized directory access attempt'); } diff --git a/routes/Dpanel/API/DeleteFolfder.js b/routes/Dpanel/API/DeleteFolfder.js index 9dcfcd2..4f04592 100644 --- a/routes/Dpanel/API/DeleteFolfder.js +++ b/routes/Dpanel/API/DeleteFolfder.js @@ -18,31 +18,166 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/deletefolder/{folderName}?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - Folder + * summary: Delete a specific file in folder for a user + * description: This route allows you to delete a specific file for a user. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * filename: + * type: string + * description: The name of the file to delete + * parameters: + * - in: path + * name: folderName + * required: true + * schema: + * type: string + * description: The name of the folder + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Folder successfully deleted. + * content: + * application/json: + * schema: + * type: object + * properties: + * deleted: + * type: boolean + * success: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 403: + * description: You do not have permission to delete this folder. + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 404: + * description: The specified folder does not exist. + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 500: + * description: Error deleting the folder. + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + +function authenticateToken(req, res, next) { + authMiddleware(req, res, function(err) { + if (!err) { + return next(); + } + + let token = null; + const authHeader = req.headers['authorization']; + + if (authHeader) { + token = authHeader.split(' ')[1]; + } else if (req.query.token) { + token = req.query.token; + } + + if (token == null) { + return res.status(401).json({ message: 'Unauthorized' }); + } + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + console.error('Error reading user.json:', err); + return res.status(401).json({ message: 'Unauthorized' }); + } + + const users = JSON.parse(data); + + const user = users.find(u => u.token === token); + + if (user) { + req.user = user; + req.userData = user; + next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + }); + }); +} + router.get('/', (req, res) => { - res.status(400).json({ error: 'Bad Request. The request cannot be fulfilled due to bad syntax or missing parameters.' }); + res.status(400).json({ error: 'Bad Request. The request cannot be fulfilled due to bad syntax or missing parameters.' }); }); -router.delete('/:folderName', authMiddleware, (req, res) => { - const userId = req.userData.name; - const folderName = req.params.folderName; - const userFolderPath = path.join('cdn-files', userId); - const folderPath = path.join(userFolderPath, folderName); +router.delete('/:folderName', authenticateToken, (req, res) => { - if (!fs.existsSync(folderPath)) { - return res.status(404).json({ error: 'Le dossier spécifié n\'existe pas.' }); - } + const userId = req.userData ? req.userData.name : null; + if (!userId) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const folderName = req.params.folderName; + const userFolderPath = path.join('cdn-files', userId); + const folderPath = path.join(userFolderPath, folderName); - if (!folderPath.startsWith(userFolderPath)) { - return res.status(403).json({ error: 'Vous n\'avez pas la permission de supprimer ce dossier.' }); - } + if (!fs.existsSync(folderPath)) { + return res.status(404).json({ error: 'The specified folder does not exist.' }); + } - fs.rmdir(folderPath, { recursive: true }, (err) => { - if (err) { - console.error(err); - return res.status(500).json({ error: 'Erreur lors de la suppression du dossier.' }); - } - res.json({ deleted: true, success: 'Dossier supprimé avec succès.' }); - }); + if (!folderPath.startsWith(userFolderPath)) { + return res.status(403).json({ error: 'You do not have permission to delete this folder.' }); + } + + fs.rmdir(folderPath, { recursive: true }, (err) => { + if (err) { + return res.status(500).json({ error: 'Error deleting the folder.' }); + } + res.json({ deleted: true, success: 'Folder successfully deleted.' }); + }); }); module.exports = router; \ No newline at end of file diff --git a/routes/Dpanel/API/GetMetaDataFile.js b/routes/Dpanel/API/GetMetaDataFile.js index 376b4a6..f86a9ec 100644 --- a/routes/Dpanel/API/GetMetaDataFile.js +++ b/routes/Dpanel/API/GetMetaDataFile.js @@ -18,6 +18,83 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/getfile?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Get file information + * description: This route allows you to get information about a specific file. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * fileLink: + * type: string + * description: The link of the file to get information about + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * Id: + * type: string + * fileName: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 404: + * description: The specified file does not exist or no information found for the file + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 500: + * description: Error reading the file + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + router.get('/', (req, res) => { res.status(400).json({ error: 'Bad Request. The request cannot be fulfilled due to bad syntax or missing parameters.' }); }); diff --git a/routes/Dpanel/API/MoveFile.js b/routes/Dpanel/API/MoveFile.js index b6a328b..a16bf46 100644 --- a/routes/Dpanel/API/MoveFile.js +++ b/routes/Dpanel/API/MoveFile.js @@ -20,6 +20,84 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/movefile?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Move file to a different folder + * description: This route allows you to move a file to a different folder. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * fileName: + * type: string + * description: The name of the file to be moved + * folderName: + * type: string + * description: The name of the destination folder + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 403: + * description: Unauthorized directory access attempt + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 500: + * description: Error moving the file + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + function authenticateToken(req, res, next) { let token = null; const authHeader = req.headers['authorization']; @@ -120,16 +198,25 @@ router.post('/', authenticateToken, async (req, res) => { router.post('/:folderName', authenticateToken, async (req, res) => { const fileName = req.body.fileName; - const newFolderName = req.body.folderName; + let newFolderName = req.body.newFolderName; const oldFolderName = req.params.folderName; - const userId = req.user && req.user._json ? req.userData.name : undefined; + const userName = req.body.userName; + + console.log('fileName:', fileName); + console.log('newFolderName:', newFolderName); + console.log('oldFolderName:', oldFolderName); + console.log('userName:', userName); - if (!fileName || !userId || !oldFolderName || !newFolderName) { - console.error('fileName, userId, oldFolderName, or newFolderName is undefined'); + if (newFolderName === 'root') { + newFolderName = ''; + } + + if (fileName === undefined || userName === undefined || oldFolderName === undefined || newFolderName === undefined) { + console.error('fileName, userName, oldFolderName, or newFolderName is undefined'); return res.status(500).send('Error moving the file.'); } - const userDir = path.join(process.cwd(), 'cdn-files', userId); + const userDir = path.join(process.cwd(), 'cdn-files', userName); const sourcePath = path.join(userDir, oldFolderName, fileName); const destinationDir = path.join(userDir, newFolderName); const destinationPath = path.join(destinationDir, fileName); diff --git a/routes/Dpanel/API/NewFolder.js b/routes/Dpanel/API/NewFolder.js index 64b594e..a823cca 100644 --- a/routes/Dpanel/API/NewFolder.js +++ b/routes/Dpanel/API/NewFolder.js @@ -18,42 +18,112 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/newfolder?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - Folder + * summary: Create a new folder + * description: This route allows you to create a new folder. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * folderName: + * type: string + * description: The name of the new folder + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 500: + * description: Error creating the folder + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * error: + * type: string + */ + function authenticateToken(req, res, next) { - let token = null; - const authHeader = req.headers['authorization']; - - if (authHeader) { - token = authHeader.split(' ')[1]; - } else if (req.query.token) { - token = req.query.token; - } - - if (token == null) { - if (req.user) { - return next(); - } else { - return res.status(401).json({ message: 'Unauthorized' }); + authMiddleware(req, res, function(err) { + if (!err) { + return next(); } - } - - fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { - if (err) { - console.error('Error reading user.json:', err); - return res.status(401).json({ message: 'Unauthorized' }); + + let token = null; + const authHeader = req.headers['authorization']; + + if (authHeader) { + token = authHeader.split(' ')[1]; + } else if (req.query.token) { + token = req.query.token; } - - const users = JSON.parse(data); - - const user = users.find(u => u.token === token); - - if (user) { - req.user = user; - req.userData = user; - next(); - } else { - return res.status(401).json({ message: 'Unauthorized' }); + + if (token == null) { + return res.status(401).json({ message: 'Unauthorized' }); } - }); + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + console.error('Error reading user.json:', err); + return res.status(401).json({ message: 'Unauthorized' }); + } + + const users = JSON.parse(data); + + const user = users.find(u => u.token === token); + + if (user) { + req.user = user; + req.userData = user; + next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + }); + }); } router.get('/', (req, res) => { @@ -62,12 +132,10 @@ router.get('/', (req, res) => { router.post('/', authenticateToken, (req, res) => { try { - logger.info('Received POST request to create a new folder.'); - const userId = req.userData.name; + const userId = req.user.name; let { folderName } = req.body; - logger.info('Received folderName:', folderName); if (!folderName || typeof folderName !== 'string') { ErrorLogger.error('Invalid folderName:', folderName); @@ -83,7 +151,6 @@ router.post('/', authenticateToken, (req, res) => { const folderPath = path.join('cdn-files', userId, folderName); if (fs.existsSync(folderPath)) { - logger.info('Folder already exists:', folderPath); return res.status(400).json({ message: 'Folder already exists.' }); } @@ -92,7 +159,6 @@ router.post('/', authenticateToken, (req, res) => { ErrorLogger.error(err); return res.status(500).json({ message: 'Error creating folder.', error: err }); } - logger.info('Folder created successfully:', folderPath); res.status(200).json({ message: 'Folder created successfully.' }); }); } catch (error) { diff --git a/routes/Dpanel/API/RenameFile.js b/routes/Dpanel/API/RenameFile.js index 04bb4fd..67df6c5 100644 --- a/routes/Dpanel/API/RenameFile.js +++ b/routes/Dpanel/API/RenameFile.js @@ -18,45 +18,163 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/rename?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Rename a file + * description: This route allows you to rename a file. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * currentName: + * type: string + * description: The current name of the file + * newName: + * type: string + * description: The new name for the file + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 500: + * description: Error renaming the file + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * error: + * type: string + */ + +function authenticateToken(req, res, next) { + let token = null; + const authHeader = req.headers['authorization']; + + if (authHeader) { + token = authHeader.split(' ')[1]; + } else if (req.query.token) { + token = req.query.token; + } + + if (token == null) { + if (req.user) { + return next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + } + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + console.error('Error reading user.json:', err); + return res.status(401).json({ message: 'Unauthorized' }); + } + + const users = JSON.parse(data); + + const user = users.find(u => u.token === token); + + if (user) { + console.log('User found:', user); + req.user = user; + req.userData = user; + next(); + } else { + console.log('No user found for token:', token); + return res.status(401).json({ message: 'Unauthorized' }); + } + }); +} + router.get('/', (req, res) => { res.status(400).json({ error: 'Bad Request. The request cannot be fulfilled due to bad syntax or missing parameters.' }); }); router.post('/', authMiddleware, async (req, res) => { - const userId = req.userData.name; - const { currentName, newName } = req.body; + const userId = req.userData.name; + const { currentName, newName } = req.body; + const filePath = path.join(req.params.filePath || '', req.params[0] || ''); - if (!currentName || !newName) { - return res.status(400).send('Both currentName and newName must be provided.'); - } + if (!currentName || !newName) { + return res.status(400).json('Both currentName and newName must be provided.'); + } - const currentPath = path.join('cdn-files', userId || '', currentName); - const newPath = path.join('cdn-files', userId, newName); + const userDir = path.join('cdn-files', userId); + const currentPath = path.join(userDir, filePath, currentName); + const newPath = path.join(userDir, filePath, newName); - try { - await fs.promises.rename(currentPath, newPath); + if (!currentPath.startsWith(userDir) || !newPath.startsWith(userDir)) { + ErrorLogger.error('Unauthorized directory access attempt'); + return res.status(403).json('Unauthorized directory access attempt'); + } - const data = await fs.promises.readFile(path.join(__dirname, '../../../data', 'file_info.json'), 'utf-8') - let fileInfo = JSON.parse(data); + try { + await fs.promises.rename(currentPath, newPath); - let found = false; - for (let i = 0; i < fileInfo.length; i++) { - if (fileInfo[i].fileName === currentName) { - fileInfo[i].fileName = newName; - found = true; - break; - } - } + const data = await fs.promises.readFile(path.join(__dirname, '../../../data', 'file_info.json'), 'utf8'); + let fileInfo = JSON.parse(data); - if (found) { - await fs.promises.writeFile(path.join(__dirname, '../../../data', 'file_info.json'), JSON.stringify(fileInfo, null, 2), 'utf8'); - } + let found = false; + for (let i = 0; i < fileInfo.length; i++) { + if (fileInfo[i].fileName === currentName) { + fileInfo[i].fileName = newName; + found = true; + break; + } + } - res.status(200).send('L\'opération a été effectuée avec succès.'); - } catch (err) { - console.error(err); - return res.status(500).send('Erreur lors du changement de nom du fichier.'); - } + if (found) { + await fs.promises.writeFile(path.join(__dirname, '../../../data', 'file_info.json'), JSON.stringify(fileInfo, null, 2), 'utf8'); + } + + res.status(200).json('Operation was successful.'); + } catch (err) { + console.error(err); + return res.status(500).json('Error renaming the file.'); + } }); router.post('/:filePath*', authMiddleware, async (req, res) => { @@ -65,7 +183,7 @@ router.post('/:filePath*', authMiddleware, async (req, res) => { const filePath = path.join(req.params.filePath, req.params[0] || ''); if (!currentName || !newName) { - return res.status(400).send('Both currentName and newName must be provided.'); + return res.status(400).json('Both currentName and newName must be provided.'); } const userDir = path.join('cdn-files', userId); @@ -74,7 +192,7 @@ router.post('/:filePath*', authMiddleware, async (req, res) => { if (!currentPath.startsWith(userDir) || !newPath.startsWith(userDir)) { ErrorLogger.error('Unauthorized directory access attempt'); - return res.status(403).send('Unauthorized directory access attempt'); + return res.status(403).json('Unauthorized directory access attempt'); } try { @@ -96,10 +214,10 @@ router.post('/:filePath*', authMiddleware, async (req, res) => { await fs.promises.writeFile(path.join(__dirname, '../../../data', 'file_info.json'), JSON.stringify(fileInfo, null, 2), 'utf8'); } - res.status(200).send('L\'opération a été effectuée avec succès.'); + res.status(200).json('Operation was successful.'); } catch (err) { console.error(err); - return res.status(500).send('Erreur lors du changement de nom du fichier.'); + return res.status(500).json('Error renaming the file.'); } }); diff --git a/routes/Dpanel/API/Upload.js b/routes/Dpanel/API/Upload.js index 15a0484..54093f8 100644 --- a/routes/Dpanel/API/Upload.js +++ b/routes/Dpanel/API/Upload.js @@ -18,6 +18,82 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dpanel/upload?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Upload a file + * description: This route allows you to upload a file. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * multipart/form-data: + * schema: + * type: object + * properties: + * file: + * type: string + * format: binary + * description: The file to upload + * expiryDate: + * type: string + * format: date-time + * description: The expiry date of the file + * password: + * type: string + * description: The password to protect the file + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 500: + * description: Error uploading the file + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * error: + * type: string + */ + function authenticateToken(req, res, next) { let token = null; const authHeader = req.headers['authorization']; diff --git a/routes/Dpanel/API/getFile.js b/routes/Dpanel/API/getFile.js index 46d8f25..f20908c 100644 --- a/routes/Dpanel/API/getFile.js +++ b/routes/Dpanel/API/getFile.js @@ -17,6 +17,85 @@ let setupData = getSetupData(); let userData = getUserData(); router.use(bodyParser.json()); +/** + * @swagger + * /dashboard/getfile?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - File + * summary: Get files and folders in a specific folder + * description: This route allows you to delete a specific file for a user. It requires a valid JWT token in the Authorization header. + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * filename: + * type: string + * description: The name of the file to delete + * parameters: + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * message: + * type: string + * 400: + * description: Bad Request + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 404: + * description: The specified file does not exist + * content: + * application/json: + * schema: + * type: object + * properties: + * status: + * type: string + * message: + * type: string + * 500: + * description: Internal server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + function authenticateToken(req, res, next) { let token = null; const authHeader = req.headers['authorization']; diff --git a/routes/Dpanel/API/getFileFolder.js b/routes/Dpanel/API/getFileFolder.js new file mode 100644 index 0000000..9f2a1a3 --- /dev/null +++ b/routes/Dpanel/API/getFileFolder.js @@ -0,0 +1,158 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const router = express.Router(); +const fileUpload = require('express-fileupload'); +const authMiddleware = require('../../../Middlewares/authMiddleware'); +const { loggers } = require('winston'); +const ncp = require('ncp').ncp; +let configFile = fs.readFileSync(path.join(__dirname, '../../../data', 'setup.json'), 'utf-8') +let config = JSON.parse(configFile)[0]; +const bodyParser = require('body-parser'); +const crypto = require('crypto'); +const os = require('os'); +const { getUserData, getSetupData } = require('../../../Middlewares/watcherMiddleware'); + +let setupData = getSetupData(); +let userData = getUserData(); +router.use(bodyParser.json()); + +/** + * @swagger + * /dashboard/getfilefolder/{folderName}?token={token}: + * post: + * security: + * - bearerAuth: [] + * tags: + * - Folder + * summary: Get files and folders in a specific folder + * description: This route allows you to get the files and folders in a specific folder. It requires a valid JWT token in the Authorization header. + * parameters: + * - in: path + * name: folderName + * required: true + * schema: + * type: string + * description: The name of the folder + * - in: header + * name: Authorization + * required: true + * schema: + * type: string + * description: The JWT token of your account to have access + * responses: + * 200: + * description: Success + * content: + * application/json: + * schema: + * type: object + * properties: + * files: + * type: array + * items: + * type: object + * properties: + * name: + * type: string + * type: + * type: string + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * type: object + * properties: + * message: + * type: string + * 404: + * description: The specified folder does not exist + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + * 500: + * description: Internal server error + * content: + * application/json: + * schema: + * type: object + * properties: + * error: + * type: string + */ + + +function authenticateToken(req, res, next) { + let token = null; + const authHeader = req.headers['authorization']; + + if (authHeader) { + token = authHeader.split(' ')[1]; + } else if (req.query.token) { + token = req.query.token; + } + + if (token == null) { + if (req.user) { + return next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + } + + fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { + if (err) { + console.error('Error reading user.json:', err); + return res.status(401).json({ message: 'Unauthorized' }); + } + + const users = JSON.parse(data); + + const user = users.find(u => u.token === token); + + if (user) { + req.user = user; + req.userData = user; + next(); + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + }); + } + +router.post('/:folderName', authenticateToken, async (req, res) => { + const userName = req.userData.name; + const folderName = req.params.folderName; + const downloadDir = path.join('cdn-files', userName, folderName); + + if (!fs.existsSync(downloadDir)) { + return res.status(404).json({ error: 'The specified folder does not exist.' }); + } + + try { + const files = await fs.promises.readdir(downloadDir); + + const fileDetails = files.map(file => { + const filePath = path.join(downloadDir, file); + const stats = fs.statSync(filePath); + const fileType = stats.isDirectory() ? 'folder' : 'file'; + + return { + name: file, + type: fileType + }; + }); + + res.json({ files: fileDetails }); + } catch (err) { + console.error('Error reading directory:', err); + res.status(500).json({ error: err.message }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/Dpanel/Folder/index.js b/routes/Dpanel/Folder/index.js index b74ce92..62a45fd 100644 --- a/routes/Dpanel/Folder/index.js +++ b/routes/Dpanel/Folder/index.js @@ -19,6 +19,7 @@ router.use(bodyParser.json()); router.get('/:folderName', authMiddleware, async (req, res) => { const userId = req.userData.name; + const userName = req.userData.name; const folderName = req.params.folderName || ''; const folderPath = path.join('cdn-files', userId, folderName); const userFolderPath = path.join('cdn-files', userId); @@ -114,7 +115,7 @@ router.get('/:folderName', authMiddleware, async (req, res) => { .then(fileDetails => { const availableExtensions = Array.from(new Set(fileDetails.map(file => file.extension))); - res.render('folder', { files: fileDetails, folders, allFolders, extensions: availableExtensions, currentFolder: currentFolderName, folderName: folderName, fileInfoNames }); + res.render('folder', { files: fileDetails, folders, allFolders, extensions: availableExtensions, currentFolder: currentFolderName, folderName: folderName, fileInfoNames, userName }); }) .catch(error => { console.error('Error processing file details:', error); diff --git a/routes/routes.js b/routes/routes.js index ac88c59..9fe6e05 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -12,7 +12,8 @@ const AttachmentsRoute = require('./attachments.js'); const buildMetadataRoute = require('./BuildMetaData.js'); const DpanelBackgroundCustomRoute = require('./Dpanel/API/BackgroundCustom.js'); const getFileDashboardRoute = require('./Dpanel/API/getFile.js'); - +const getFileFolderRoute = require('./Dpanel/API/getFileFolder.js'); +const swagger = require('../models/swagger.js'); const NewFolderRoute = require('./Dpanel/API/NewFolder.js'); const RenameFileRoute = require('./Dpanel/API/RenameFile.js'); const DeleteFileRoute = require('./Dpanel/API/DeleteFile.js'); @@ -39,6 +40,7 @@ const GenerateTokenRoute = require('./Dpanel/API/GenerateToken.js'); router.use('/', indexRoute); router.use('/attachments', AttachmentsRoute); router.use('/build-metadata', buildMetadataRoute); +router.use('/api/docs', swagger.serve, swagger.setup); router.use('/dpanel/dashboard', DpanelDashboardRoute); router.use('/dpanel/upload', DpanelUploadRoute); @@ -61,7 +63,8 @@ router.use('/api/dpanel/dashboard/deletefile/', discordWebhookSuspisiousAlertMid router.use('/api/dpanel/dashboard/getmetadatafile',discordWebhookSuspisiousAlertMiddleware, logApiRequest, GetMetaDataFileRoute); router.use('/api/dpanel/dashboard/backgroundcustom',discordWebhookSuspisiousAlertMiddleware, logApiRequest, DpanelBackgroundCustomRoute); router.use('/api/dpanel/generate-token',discordWebhookSuspisiousAlertMiddleware, logApiRequest, GenerateTokenRoute); -router.use('/api/dpanel/dashboard/getfile', getFileDashboardRoute); +router.use('/api/dpanel/dashboard/getfile', getFileDashboardRoute, logApiRequest); +router.use('/api/dpanel/dashboard/getfilefolder', getFileFolderRoute, logApiRequest); router.use('/auth/login', loginRoute); router.use('/auth/logout', logoutRoute); diff --git a/views/dashboard.ejs b/views/dashboard.ejs index e1b1644..2e94c44 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -35,20 +35,20 @@