diff --git a/UC/backend/package-lock.json b/UC/backend/package-lock.json index 55f817d..78308fa 100644 --- a/UC/backend/package-lock.json +++ b/UC/backend/package-lock.json @@ -14,6 +14,7 @@ "cheerio": "^1.0.0-rc.12", "cors": "^2.8.5", "cron": "^3.1.6", + "crypto": "^1.0.1", "crypto-js": "^4.2.0", "express": "^4.19.1", "joi": "^17.12.2", @@ -492,6 +493,12 @@ "luxon": "~3.4.0" } }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." + }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", diff --git a/UC/backend/package.json b/UC/backend/package.json index 4b8ff38..45fb798 100644 --- a/UC/backend/package.json +++ b/UC/backend/package.json @@ -16,6 +16,7 @@ "cheerio": "^1.0.0-rc.12", "cors": "^2.8.5", "cron": "^3.1.6", + "crypto": "^1.0.1", "crypto-js": "^4.2.0", "express": "^4.19.1", "joi": "^17.12.2", diff --git a/UC/backend/src/app.js b/UC/backend/src/app.js index 8d53b3c..47f9b42 100644 --- a/UC/backend/src/app.js +++ b/UC/backend/src/app.js @@ -5,9 +5,25 @@ const cors = require('cors'); const app = express(); const port = process.env.PORT || 5000; -app.use(cors()); +app.use(cors({ + allowedHeaders: ['Authorization', 'Content-Type'] // Add 'Authorization' to the list of allowed headers +})); app.use(json()); +const { + usersDB, + departmentsDB, + backupSchemesDB, + ceoDB, + adminDB +} = require('./db/jsonDatabaseManager'); + +app.set('usersDB', usersDB); +app.set('departmentsDB', departmentsDB); +app.set('backupSchemesDB', backupSchemesDB); +app.set('ceoDB', ceoDB); +app.set('adminDB', adminDB); + const checkJson = require('./middlewares/checkJson'); const apiKeyValidation = require('./middlewares/apiKeyValidation'); diff --git a/UC/backend/src/db/backup_schemes.json b/UC/backend/src/db/backup_schemes.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/UC/backend/src/db/backup_schemes.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/UC/backend/src/db/ceo.json b/UC/backend/src/db/ceo.json new file mode 100644 index 0000000..2b10c9a --- /dev/null +++ b/UC/backend/src/db/ceo.json @@ -0,0 +1,5 @@ +{ + "name": "CEO", + "email": "ceo@yourfirm.com", + "password": "335ae110091d3bc5fbc90d5e3786890e" +} \ No newline at end of file diff --git a/UC/backend/src/db/departments.json b/UC/backend/src/db/departments.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/UC/backend/src/db/departments.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/UC/backend/src/db/jsonDatabaseManager.js b/UC/backend/src/db/jsonDatabaseManager.js new file mode 100644 index 0000000..ca524b1 --- /dev/null +++ b/UC/backend/src/db/jsonDatabaseManager.js @@ -0,0 +1,49 @@ +const fs = require('fs'); +const path = require('path'); + +class JSONDatabase { + constructor(filePath) { + this.filePath = filePath; + this.readFile = this.readFile.bind(this); // Bind readFile method to the instance + this.writeFile = this.writeFile.bind(this); // Bind writeFile method to the instance + + } + + readFile() { + if (!fs.existsSync(this.filePath)) { + console.log('File does not exist, returning null:', this.filePath); + return null; + } + try { + const data = fs.readFileSync(this.filePath, 'utf8'); + return JSON.parse(data); + } catch (error) { + console.error('Error reading file:', error); + return null; + } + } + + writeFile(data) { + try { + fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), { flag: 'w' }); + console.log('File written successfully.'); + } catch (error) { + console.error('Error writing file:', error); + } + } +} + +const usersDB = new JSONDatabase(path.join(__dirname, 'users.json')); +const departmentsDB = new JSONDatabase(path.join(__dirname, 'departments.json')); +const backupSchemesDB = new JSONDatabase(path.join(__dirname, 'backup_schemes.json')); +const ceoDB = new JSONDatabase(path.join(__dirname, 'ceo.json')); +const adminDB = new JSONDatabase(path.join(__dirname + '..', '..', '..', '..', 'frontend', 'config', 'credentials.json')); + +module.exports = { + usersDB, + departmentsDB, + backupSchemesDB, + ceoDB, + adminDB, + JSONDatabase +}; diff --git a/UC/backend/src/db/users.json b/UC/backend/src/db/users.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/UC/backend/src/db/users.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/UC/backend/src/routes/admin.js b/UC/backend/src/routes/admin.js index f38bd10..7c8055a 100644 --- a/UC/backend/src/routes/admin.js +++ b/UC/backend/src/routes/admin.js @@ -1,20 +1,47 @@ const express = require('express'); +const {httpStatus} = require("../helpers/httpResponses"); const router = express.Router(); +const crypto = require('crypto'); function validateBody(req, res, next) { + const apiKey = req.headers['authorization']; + const adminDB = req.app.get('adminDB'); + const {id} = adminDB.readFile(); + + if(apiKey !== id){ + return res.status(httpStatus.UNAUTHORIZED).json( + {message: "You are not authorized as an admin."}) + } + next(); } -router.post('/reset_server', validateBody, (req, res) => { - // Handle reset server logic here +router.get('/reset_server', validateBody, (req, res) => { + const usersDB = req.app.get('usersDB'); + const departmentsDB = req.app.get('departmentsDB'); + const backupSchemesDB = req.app.get('backupSchemesDB'); + const ceoDB = req.app.get('ceoDB'); + + usersDB.writeFile([]); + departmentsDB.writeFile([]); + backupSchemesDB.writeFile({}); + ceoDB.writeFile({ + name: "CEO", + email: "ceo@yourfirm.com", + password: crypto.randomBytes(16).toString('hex') + }); + + res.status(httpStatus.OK).json({ message: "Resetting the server..." }); }); router.get('/ceo', validateBody, (req, res) => { - // Retrieve CEO info + const ceoDB = req.app.get('ceoDB'); + res.status(httpStatus.OK).json({ message: "Retrieving CEO info...", data: ceoDB.readFile() }) // Corrected to readFile }); router.get('/users', validateBody, (req, res) => { - // Retrieve all users in the system + const usersDB = req.app.get('usersDB'); + res.status(httpStatus.OK).json({ message: "Retrieving users info...", data: usersDB.readFile() }) // Corrected to readFile }); module.exports = router; diff --git a/UC/frontend/README.md b/UC/frontend/README.md index 14e57f5..5b6df04 100644 --- a/UC/frontend/README.md +++ b/UC/frontend/README.md @@ -23,6 +23,7 @@ enable routing to the server; so also make sure to open those ports as well; - If the CEO wants to change the email address linked to the account, his password will be changed to a low-risk password, so make sure after any release to specify the account information; +- Make sure that all the ports configurations are respected to have all the applications work properly Closing thoughts - diff --git a/UC/frontend/config/credentials.json b/UC/frontend/config/credentials.json index 2faf214..5e615f0 100644 --- a/UC/frontend/config/credentials.json +++ b/UC/frontend/config/credentials.json @@ -1,4 +1,5 @@ { + "id": "deee8837-3549-44d5-af56-fb7532505574", "name": "Andrei", "email": "admin@yourfirm.com", "password": "password" diff --git a/UC/frontend/public/js/login.js b/UC/frontend/public/js/login.js index c50c718..7db51ed 100644 --- a/UC/frontend/public/js/login.js +++ b/UC/frontend/public/js/login.js @@ -22,7 +22,7 @@ document.addEventListener('DOMContentLoaded', function () { const result = await response.json(); if (response.ok && result.success) { - // Set cookie with email and name + document.cookie = `id=${result.user.id};`; document.cookie = `email=${result.user.email};`; document.cookie = `name=${result.user.name};`; diff --git a/UC/frontend/public/js/main_menu.js b/UC/frontend/public/js/main_menu.js index 88e734e..02f25ca 100644 --- a/UC/frontend/public/js/main_menu.js +++ b/UC/frontend/public/js/main_menu.js @@ -62,14 +62,122 @@ document.addEventListener('DOMContentLoaded', function() { ceoInfoButton.addEventListener('click', () => { console.log('Ceo Info Button pressed'); + + const domain = window.location.hostname; + const endpoint = 'http://' + domain + ':5000/admin/ceo'; + const id = getCookie('id'); + + fetch(endpoint, { + method: 'GET', + headers: { + 'Authorization': id + }, + }) + .then(async response => { + if (!response.ok) { + const responseData = await response.json(); + throw new Error(responseData.message); + } + + return await response.json() + }) + .then(data => { + alert(data.message); + + // Assuming 'data' is the property you want to download + const toDownload = data.data; + const jsonStr = JSON.stringify(toDownload, null, 2); + const blob = new Blob([jsonStr], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + + const a = document.createElement('a'); + a.href = url; + a.download = 'ceo.json'; + document.body.appendChild(a); + a.click(); + + // Cleanup: remove the link and revoke the URL + document.body.removeChild(a); + URL.revokeObjectURL(url); + }) + .catch(error => { + alert(error) + console.error('Error: '+ error) + }); }) usersInfoButton.addEventListener('click', () => { console.log('Users Info Button pressed'); + + const domain = window.location.hostname; + const endpoint = 'http://' + domain + ':5000/admin/users'; + const id = getCookie('id'); + + fetch(endpoint, { + method: 'GET', + headers: { + 'Authorization': id + }, + }) + .then(async response => { + if (!response.ok) { + const responseData = await response.json(); + throw new Error(responseData.message); + } + + return await response.json() + }) + .then(data => { + alert(data.message); + + const toDownload = data.data; + const jsonStr = JSON.stringify(toDownload, null, 2); + const blob = new Blob([jsonStr], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + + // Create a temporary link to trigger the download + const a = document.createElement('a'); + a.href = url; + a.download = 'users.json'; + document.body.appendChild(a); + a.click(); + + // Cleanup: remove the link and revoke the URL + document.body.removeChild(a); + URL.revokeObjectURL(url); + }) + .catch(error => { + alert(error) + console.error('Error: '+ error) + }); }) resetUcButton.addEventListener('click', () => { - console.log('Set Conf Button pressed'); + console.log('Reset UC Button pressed'); + + const domain = window.location.hostname; + const endpoint = 'http://' + domain + ':5000/admin/reset_server'; + const id = getCookie('id'); + + fetch(endpoint, { + method: 'GET', + headers: { + 'Authorization': id + }, + }) + .then(async response => { + if (!response.ok) { + const responseData = await response.json(); + throw new Error(responseData.message); + } + + return await response.json() + }) + .then(data => alert(data.message)) + .catch(error => { + alert(error) + console.error('Error: '+ error) + }); }) logoutButton.addEventListener('click', () => { @@ -81,6 +189,7 @@ document.addEventListener('DOMContentLoaded', function() { deleteCookie('email'); deleteCookie('name'); + deleteCookie('id'); fadeOut('/login'); }); diff --git a/UC/frontend/routers/login.js b/UC/frontend/routers/login.js index c3031c1..460db13 100644 --- a/UC/frontend/routers/login.js +++ b/UC/frontend/routers/login.js @@ -15,7 +15,7 @@ function validateLogin(req, res, next) { const {error, value} = schemas.loginModelSchema.validate(req.body); if (error) { - res.status(statusCodes.BAD_REQUEST).json({success: false, error: error.details}); + res.status(statusCodes.BAD_REQUEST).json({error: error.details}); } else { next(); } @@ -29,12 +29,13 @@ router.post('/', validateLogin, (req, res) => { success: true, message: 'Login successful', user: { + id: config.id, name: config.name, email: config.email } }); } else { - res.status(statusCodes.UNAUTHORIZED).json({ success: false, message: 'Invalid email or password' }); + res.status(statusCodes.UNAUTHORIZED).json({message: 'Invalid email or password' }); } }); module.exports = router; diff --git a/UC/frontend/routers/mainMenu.js b/UC/frontend/routers/mainMenu.js index c4a0737..4b86403 100644 --- a/UC/frontend/routers/mainMenu.js +++ b/UC/frontend/routers/mainMenu.js @@ -43,8 +43,4 @@ router.post('/server', async (req, res) => { } }); -router.post('ceo_credentials', (req, res) => { - -}); - module.exports = router;