diff --git a/UC/backend/src/app.js b/UC/backend/src/app.js index 0b7849a..c33ac73 100644 --- a/UC/backend/src/app.js +++ b/UC/backend/src/app.js @@ -27,6 +27,10 @@ app.set('backupSchemesDB', backupSchemesDB); app.set('ceoDB', ceoDB); app.set('adminDB', adminDB); +app.use('/heartbeat', (req, res) => { + return res.status(200).json({message: 'Server ap and running.'}); +}) + const checkJson = require('./middlewares/checkJson'); const apiKeyValidation = require('./middlewares/apiKeyValidation'); diff --git a/UC/backend/src/db/users.json b/UC/backend/src/db/users.json index 0637a08..276727e 100644 --- a/UC/backend/src/db/users.json +++ b/UC/backend/src/db/users.json @@ -1 +1,9 @@ -[] \ No newline at end of file +[ + { + "id": "4659e71f-9bb4-4902-97d8-097efa138333", + "name": "Andrei Cerbu", + "email": "a@c.com", + "password": "5447045dc3cfaafdb49b365e31dad41eb88616b0b1449930e55fd3a70bd8cee4", + "department": "Contabili" + } +] \ No newline at end of file diff --git a/UC/backend/src/helpers/httpResponses.js b/UC/backend/src/helpers/httpResponses.js index 176fca9..1519d88 100644 --- a/UC/backend/src/helpers/httpResponses.js +++ b/UC/backend/src/helpers/httpResponses.js @@ -33,43 +33,6 @@ const httpStatus = { SERVICE_UNAVAILABLE: 503 }; -const httpStatusMessages = { - // Informational - [httpStatus.CONTINUE]: "Continue", - [httpStatus.SWITCHING_PROTOCOLS]: "Switching Protocols", - [httpStatus.PROCESSING]: "Processing", - // Success - [httpStatus.OK]: "OK", - [httpStatus.CREATED]: "Created", - [httpStatus.ACCEPTED]: "Accepted", - [httpStatus.NO_CONTENT]: "No Content", - // Redirection - [httpStatus.MOVED_PERMANENTLY]: "Moved Permanently", - [httpStatus.FOUND]: "Found", - [httpStatus.SEE_OTHER]: "See Other", - [httpStatus.NOT_MODIFIED]: "Not Modified", - [httpStatus.TEMPORARY_REDIRECT]: "Temporary Redirect", - - // Client Error - [httpStatus.BAD_REQUEST]: "Bad Request", - [httpStatus.UNAUTHORIZED]: "Unauthorized", - [httpStatus.FORBIDDEN]: "Forbidden", - [httpStatus.NOT_FOUND]: "Not Found", - [httpStatus.METHOD_NOT_ALLOWED]: "Method Not Allowed", - [httpStatus.CONFLICT]: "Conflict", - [httpStatus.GONE]: "Gone", - [httpStatus.UNSUPPORTED_MEDIA_TYPE]: "Unsupported Media Type", - - // Server Error - [httpStatus.INTERNAL_SERVER_ERROR]: "Internal Server Error", - [httpStatus.NOT_IMPLEMENTED]: "Not Implemented", - [httpStatus.SERVICE_UNAVAILABLE]: "Service Unavailable" -}; - -const httpHeaders = { - JSON: { 'name': 'Content-Type', 'value': 'application/json' } -}; - -module.exports = {httpStatus, httpStatusMessages, httpHeaders}; \ No newline at end of file +module.exports = {httpStatus}; \ No newline at end of file diff --git a/UC/backend/src/helpers/responseHelper.js b/UC/backend/src/helpers/responseHelper.js deleted file mode 100644 index 42a3bde..0000000 --- a/UC/backend/src/helpers/responseHelper.js +++ /dev/null @@ -1,21 +0,0 @@ -const {httpHeaders} = require("./httpResponses"); - -const headers = { - [httpHeaders.JSON.name]: httpHeaders.JSON.value -} - -function sendResponse(res, statusCode, message, data = null, headers_parsed = {}) { - Object.entries(headers).forEach(([key, value]) => { - res.setHeader(key, value); - }); - - // Set headers if provided - Object.entries(headers_parsed).forEach(([key, value]) => { - res.setHeader(key, value); - }); - - // Send the response with status code, message, and optional data - res.status(statusCode).json({ message, data }); -} - -module.exports = { sendResponse }; \ No newline at end of file diff --git a/UC/backend/src/middlewares/apiKeyValidation.js b/UC/backend/src/middlewares/apiKeyValidation.js index c156021..cfa3748 100644 --- a/UC/backend/src/middlewares/apiKeyValidation.js +++ b/UC/backend/src/middlewares/apiKeyValidation.js @@ -1,10 +1,9 @@ -const { sendResponse } = require('../helpers/responseHelper'); const {httpStatus, httpStatusMessages} = require('../helpers/httpResponses') function apiKeyValidation(req, res, next) { const apiKey = req.headers['x-api-key']; if (apiKey !== req.app.locals.apiKey) { - return sendResponse(res, httpStatus.UNAUTHORIZED, httpStatusMessages[httpStatus.UNAUTHORIZED]); + return res.status(httpStatus.UNAUTHORIZED).json({message: 'Invalid API key'}); } next(); } diff --git a/UC/backend/src/middlewares/checkJson.js b/UC/backend/src/middlewares/checkJson.js index 32f432f..1446c5f 100644 --- a/UC/backend/src/middlewares/checkJson.js +++ b/UC/backend/src/middlewares/checkJson.js @@ -1,5 +1,5 @@ -const { sendResponse } = require('../helpers/responseHelper'); -const {httpStatus, httpStatusMessages} = require("../helpers/httpResponses"); + +const {httpStatus} = require("../helpers/httpResponses"); function checkJson(req, res, next) { if(req.method === 'GET'){ @@ -7,7 +7,7 @@ function checkJson(req, res, next) { } if (['POST', 'PUT', 'PATCH'].includes(req.method) && req.headers['content-type'] !== 'application/json') { - return sendResponse(res, httpStatus.BAD_REQUEST, httpStatusMessages[httpStatus.BAD_REQUEST]); + return res.status(httpStatus.BAD_REQUEST).json({message: "Body missing in action."}); } next(); diff --git a/UC/backend/src/models/dirStructureModel.js b/UC/backend/src/models/dirStructureModel.js index f269bee..2c2d686 100644 --- a/UC/backend/src/models/dirStructureModel.js +++ b/UC/backend/src/models/dirStructureModel.js @@ -6,6 +6,10 @@ const dirStructureModel = Joi.object({ 'string.empty': 'ID must not be empty', 'string.guid': 'ID must be a valid GUID' }), + ip: Joi.string().ip().required().messages({ + 'string.ip': 'The IP address "{{#value}}" is not valid.', + 'any.required': 'IP address is required.' + }), dir_config: Joi.string().required().messages({ 'any.required': 'Directory configuration is required', 'string.empty': 'Directory configuration must not be empty' diff --git a/UC/backend/src/models/userDepartmentPatchModel.js b/UC/backend/src/models/userDepartmentPatchModel.js index 5dd2c00..077b078 100644 --- a/UC/backend/src/models/userDepartmentPatchModel.js +++ b/UC/backend/src/models/userDepartmentPatchModel.js @@ -5,6 +5,10 @@ const UserDepartmentPatchModel = Joi.object({ 'any.required': 'User ID is required', 'string.empty': 'User ID must not be empty', 'string.uuid': 'User ID must be a valid UUID' + }), + department: Joi.string().required().messages({ + 'any.required': 'User ID is required', + 'string.empty': 'User ID must not be empty', }) }); diff --git a/UC/backend/src/models/usersRegisterModel.js b/UC/backend/src/models/usersRegisterModel.js index cef077a..0b49551 100644 --- a/UC/backend/src/models/usersRegisterModel.js +++ b/UC/backend/src/models/usersRegisterModel.js @@ -16,10 +16,9 @@ const usersRegisterModel = Joi.object({ 'string.min': 'Password must be at least {#limit} characters long', 'string.max': 'Password must be at most {#limit} characters long' }), - department: Joi.string().uuid().required().messages({ + department: Joi.string().required().messages({ 'any.required': 'Department ID is required', - 'string.empty': 'Department ID must not be empty', - 'string.uuid': 'Department ID must be a valid UUID' + 'string.empty': 'Department ID must not be empty' }) }); diff --git a/UC/backend/src/routes/admin.js b/UC/backend/src/routes/admin.js index ff93068..8180b3b 100644 --- a/UC/backend/src/routes/admin.js +++ b/UC/backend/src/routes/admin.js @@ -48,4 +48,8 @@ router.get('/users', validateBody, (req, res) => { res.status(httpStatus.OK).json({ message: "Retrieving users info...", data: usersDB.readFile() }) // Corrected to readFile }); +router.use((req, res) => { + return res.status(httpStatus.NOT_FOUND).json({message: "Endpoint not found"}); +}) + module.exports = router; diff --git a/UC/backend/src/routes/backup_schemes.js b/UC/backend/src/routes/backup_schemes.js index aa2d366..526314e 100644 --- a/UC/backend/src/routes/backup_schemes.js +++ b/UC/backend/src/routes/backup_schemes.js @@ -1,15 +1,49 @@ const express = require('express'); +const {httpStatus} = require("../helpers/httpResponses"); +const {schemas} = require("../models/schemaMapper"); const router = express.Router(); function validateBody(req, res, next) { + let validationSchema = undefined; + + if(req.path === '/' && req.method === 'PATCH'){ + validationSchema = schemas.dirStructureModelSchema + } + + if(validationSchema !== undefined){ + const {error} = validationSchema.validate(req.body); + if(error){ + const errorMessage = error.details.map(detail => detail.message).join(', '); + return res.status(httpStatus.BAD_REQUEST).json({ message: errorMessage }); + } + } next(); } router.patch('/', validateBody, (req, res) => { + const backupSchemesDB = req.app.get('backupSchemesDB'); const { id, ip, backup_schema, size } = req.body; + + let backupSchemesJson = backupSchemesDB.readFile(); + backupSchemesJson[id] = { + ip: ip, + backup_schema: backup_schema, + size: size + } + + return res.status(httpStatus.OK).json({message: 'Backup schema updated'}); }); router.get('/', validateBody, (req, res) => { + const backupSchemesDB = req.app.get('backupSchemesDB'); + return res.status(httpStatus.OK).json({ + message: 'Backup Schemes fetched.', + data: backupSchemesDB.readFile() + }); }); +router.use((req, res) => { + return res.status(httpStatus.NOT_FOUND).json({message: "Endpoint not found"}); +}) + module.exports = router; diff --git a/UC/backend/src/routes/ceo.js b/UC/backend/src/routes/ceo.js index 84ba1cd..32301f6 100644 --- a/UC/backend/src/routes/ceo.js +++ b/UC/backend/src/routes/ceo.js @@ -184,4 +184,8 @@ router.get('/get_decrypt_keys', (req, res) => { }); }); +router.use((req, res) => { + return res.status(httpStatus.NOT_FOUND).json({message: "Endpoint not found"}); +}) + module.exports = router; diff --git a/UC/backend/src/routes/users.js b/UC/backend/src/routes/users.js index e1651c0..9e7e617 100644 --- a/UC/backend/src/routes/users.js +++ b/UC/backend/src/routes/users.js @@ -1,9 +1,11 @@ const express = require('express'); const { v4: uuidv4 } = require('uuid'); +const crypto = require('crypto'); const {schemas} = require('../models/schemaMapper'); const {httpStatus} = require("../helpers/httpResponses"); + const router = express.Router(); function validateBody(req, res, next) { @@ -16,6 +18,9 @@ function validateBody(req, res, next) { case '/login': validationSchema = schemas.usersLoginModelSchema; break; + case '/validate_ceo_password': + validationSchema = schemas.ceoPasswordModelSchema; + break; case '/validate_email': validationSchema = schemas.emailVerificationSchema; break; @@ -24,16 +29,15 @@ function validateBody(req, res, next) { validationSchema = schemas.usersModifyModelSchema; } break; - case 'change_department': + case '/change_department': validationSchema = schemas.userDepartmentPatchSchema; break; default: validationSchema = undefined; } - console.log(validationSchema); - if(validationSchema !== undefined){ + console.log(req.body); const {error} = validationSchema.validate(req.body); if(error){ const errorMessage = error.details.map(detail => detail.message).join(', '); @@ -69,14 +73,35 @@ router.post('/login', validateBody, (req, res) => { const { email, password } = req.body; const hashedPassword = crypto.createHash('sha256').update(password).digest('hex'); + if(usersDB.readFile().length === 0){ + return res.status(httpStatus.NOT_FOUND).json({message: 'Invalid credentials.'}); + } + if(usersDB.findIndexByKeyValueInArray('email', email) !== usersDB.findIndexByKeyValueInArray('password', hashedPassword)){ return res.status(httpStatus.NOT_FOUND).json({message: 'Invalid credentials.'}); } - return res.status(httpStatus.Ok).json({message: 'Logged in.'}); + const userIndex = usersDB.findIndexByKeyValueInArray('email', email); + + return res.status(httpStatus.OK).json({ + message: 'Logged in.', + data: usersDB.readFile()[userIndex] + }); }); +router.post('/validate_ceo_password', validateBody, (req, res) => { + const ceoDB = req.app.get('ceoDB'); + const { password } = req.body; + + const ceoJson = ceoDB.readFile(); + if(ceoJson.password !== password){ + return res.status(httpStatus.UNAUTHORIZED).json({message: 'Incorrect CEO password'}); + } + + return res.status(httpStatus.OK).json({message: 'Password verified.'}) +}) + router.post('/validate_email', validateBody, (req, res) => { const usersDB = req.app.get('usersDB'); const { email } = req.body; @@ -159,7 +184,7 @@ router.patch('/change_department', validateBody, (req, res) => { usersJson[userIndex] = userInfo usersDB.writeFile(usersJson); - return res.status(httpStatus.Ok).json({message: "Department modified."}); + return res.status(httpStatus.OK).json({message: "Department modified."}); }); router.get('/get_decrypt_keys', (req, res) => { diff --git a/UC/backend/task_uri.md b/UC/backend/task_uri.md new file mode 100644 index 0000000..475f640 --- /dev/null +++ b/UC/backend/task_uri.md @@ -0,0 +1,21 @@ +Taskuri +- +- create form which upon submission set's the ip location (also create a button which can change this one and have to +create a IPC for retrieving the ip when making the requests). +- create the encryption process when writing a file on disk / decryption process when reading a file form disk +- configure endpoint for 'backup_schemes' completely +- refactor the JS code from all the html to make it with .then statements and show the messages +from the UC +- finish the CEO interface +- create process which will update the backup scheme with: + + - IP + - user_id + - dir_schema + - size + +- create process which will fetch the large schema and encryption keys and compare it with the one on local; +if is the same, hibernate; else, make requests for the files +- create process which will get the user database and combine it with the ip and at the request will share a +specific file +- create process which will decrypt all the files from the backup scheme locally \ No newline at end of file diff --git a/User/.idea/encodings.xml b/User/.idea/encodings.xml new file mode 100644 index 0000000..31b5dc7 --- /dev/null +++ b/User/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/User/ipConfig.json b/User/ipConfig.json new file mode 100644 index 0000000..81d3eb7 --- /dev/null +++ b/User/ipConfig.json @@ -0,0 +1 @@ +êÔ—‘Û°ës_žì¢(Ëk´¾K–ô:Ô‚Fn]C‹$ \ No newline at end of file diff --git a/User/iv.key b/User/iv.key new file mode 100644 index 0000000..dbf14ed --- /dev/null +++ b/User/iv.key @@ -0,0 +1 @@ +äï§¡’a%l:ðIÇ÷ÑÝ \ No newline at end of file diff --git a/User/jobs/backup.js b/User/jobs/backup.js new file mode 100644 index 0000000..e69de29 diff --git a/User/jobs/decrypt_files.js b/User/jobs/decrypt_files.js new file mode 100644 index 0000000..e69de29 diff --git a/User/jobs/fetcher.js b/User/jobs/fetcher.js new file mode 100644 index 0000000..e69de29 diff --git a/User/jobs/receiver.js b/User/jobs/receiver.js new file mode 100644 index 0000000..e69de29 diff --git a/User/jobs/send_files.js b/User/jobs/send_files.js new file mode 100644 index 0000000..e69de29 diff --git a/User/loginData.json b/User/loginData.json new file mode 100644 index 0000000..4b94fa6 Binary files /dev/null and b/User/loginData.json differ diff --git a/User/secret.key b/User/secret.key new file mode 100644 index 0000000..c209bc5 --- /dev/null +++ b/User/secret.key @@ -0,0 +1 @@ +ª ƒ4¥•ÿØ~n`¤ìƒ'TníoCÀ:­%:xØë \ No newline at end of file diff --git a/User/src/main/aes_encrypt.js b/User/src/main/aes_encrypt.js new file mode 100644 index 0000000..aa33b9e --- /dev/null +++ b/User/src/main/aes_encrypt.js @@ -0,0 +1,76 @@ +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); + +async function readKeyFromFile(filePath) { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + return fs.promises.readFile(filePath); // Use asynchronous readFile + } catch(error) { + console.error('Error reading key file:', error); + return null; + } +} + +// Paths to the key files remain the same +const IV_FILE_PATH = path.join(__dirname, '..', '..', 'iv.key'); +const SECRET_KEY_FILE_PATH = path.join(__dirname, '..', '..', 'secret.key'); + +async function encryptFileInPlace(filePath) { + // Await the resolution of these promises + const IV = await readKeyFromFile(IV_FILE_PATH); + const SECRET_KEY = await readKeyFromFile(SECRET_KEY_FILE_PATH); + + if (!IV || !SECRET_KEY) { + throw new Error('Failed to load IV or Secret Key'); + } + + const tempEncryptedFilePath = filePath + '.enc'; // Temporary encrypted file + return new Promise((resolve, reject) => { + const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), IV); + const input = fs.createReadStream(filePath); + const output = fs.createWriteStream(tempEncryptedFilePath); + + input.pipe(cipher).pipe(output); + + output.on('finish', () => { + fs.rename(tempEncryptedFilePath, filePath, (err) => { + if (err) reject(err); + else resolve('File encrypted successfully and replaced original.'); + }); + }); + output.on('error', reject); + }); +} + +async function decryptFileInPlace(filePath) { + // Await the resolution of these promises + const IV = await readKeyFromFile(IV_FILE_PATH); + const SECRET_KEY = await readKeyFromFile(SECRET_KEY_FILE_PATH); + + if (!IV || !SECRET_KEY) { + throw new Error('Failed to load IV or Secret Key'); + } + + const tempDecryptedFilePath = filePath + '.dec'; // Temporary decrypted file + return new Promise((resolve, reject) => { + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(SECRET_KEY), IV); + const input = fs.createReadStream(filePath); + const output = fs.createWriteStream(tempDecryptedFilePath); + + input.pipe(decipher).pipe(output); + + output.on('finish', () => { + fs.rename(tempDecryptedFilePath, filePath, (err) => { + if (err) reject(err); + else resolve('File decrypted successfully and replaced original.'); + }); + }); + output.on('error', reject); + }); +} + +module.exports = { + encryptFileInPlace, + decryptFileInPlace +} diff --git a/User/src/main/main.js b/User/src/main/main.js index 9b9cfb0..c77857f 100644 --- a/User/src/main/main.js +++ b/User/src/main/main.js @@ -1,13 +1,57 @@ const { app, BrowserWindow, screen, ipcMain, dialog } = require('electron'); const fs = require('fs'); const path = require('path'); +const crypto = require('crypto'); +const { fork } = require('child_process'); + +const {encryptFileInPlace, decryptFileInPlace} = require('./aes_encrypt'); const isMac = process.platform === 'darwin'; let html_page = undefined; let mainWindow = undefined; let alertWindow = undefined; -const createMainWindow = ((title, width, height) => { +let backupProcess = null; +let receiverProcess = null; +let fetcherProcess = null; + +const create_initial_keys = () => { + const SECRET_KEY = crypto.randomBytes(32); + const IV = crypto.randomBytes(16); + + const secretKeyPath = path.join(__dirname, '..', '..', 'secret.key'); + const ivPath = path.join(__dirname, '..', '..', 'iv.key'); + + fs.writeFileSync(secretKeyPath, SECRET_KEY); + console.log(`Secret Key saved to ${secretKeyPath}`); + + fs.writeFileSync(ivPath, IV); + console.log(`IV saved to ${ivPath}`); +} + +const delete_external_files = () => { + const ipConfigPath = path.join(__dirname, '..', '..', 'ipConfig.json'); + const loginDataPath = path.join(__dirname, '..', '..', 'loginData.json'); + + fs.unlink(ipConfigPath, (err) => { + if (err) { + console.error('Error deleting file:', err); + return; + } + console.log('File deleted successfully: ' + 'ipConfig.json'); + }); + + fs.unlink(loginDataPath, (err) => { + if (err) { + console.error('Error deleting file:', err); + return; + } + console.log('File deleted successfully: ' + 'loginData.json'); + }); + +} + +const createMainWindow = (async (title, width, height) => { mainWindow = new BrowserWindow({ title: title, width: width, @@ -19,9 +63,25 @@ const createMainWindow = ((title, width, height) => { } }); - html_page = 'login.html'; + try { + await fs.promises.access(path.join(__dirname, '..', '..', 'secret.key'), fs.constants.F_OK); + await fs.promises.access(path.join(__dirname, '..', '..', 'iv.key'), fs.constants.F_OK); + } catch (err) { + create_initial_keys(); + delete_external_files(); + } + + html_page = 'ip_config.html'; + + try { + await fs.promises.access(path.join(__dirname, '..', '..', 'ipConfig.json')); + html_page = 'login.html'; + } catch (err) { + html_page = 'ip_submit.html'; + } + //mainWindow.setMenu(null); - mainWindow.loadFile(path.join(__dirname, '..', 'renderer', 'html', 'login.html')) + mainWindow.loadFile(path.join(__dirname, '..', 'renderer', 'html', html_page)) .then(() => { console.log('Main window loaded!') }) @@ -79,6 +139,18 @@ app.whenReady().then(() => { }); }); +app.on('before-quit', () => { + if (backupProcess !== null) { + backupProcess.kill(); + } + if (receiverProcess !== null) { + receiverProcess.kill(); + } + if (fetcherProcess !== null) { + fetcherProcess.kill(); + } +}); + app.on('window-all-closed', () => { if(!isMac){ app.quit(); @@ -89,6 +161,7 @@ ipcMain.handle('write-file', async (event, fileName, content) => { try { let filePath = path.join(__dirname, '..', '..', fileName); await fs.promises.writeFile(filePath, content); + await encryptFileInPlace(filePath); console.log(`File successfully written to ${filePath}`); return { success: true }; } catch (error) { @@ -113,8 +186,10 @@ ipcMain.handle('delete-file', async (event, fileName) => { ipcMain.handle('read-file', async (event, fileName) => { try { let filePath = path.join(__dirname, '..', '..', fileName); - + await decryptFileInPlace(filePath); const content = await fs.promises.readFile(filePath, 'utf-8'); + + await encryptFileInPlace(filePath); return { success: true, content }; } catch (error) { console.error('Error reading file:', error); @@ -125,16 +200,7 @@ ipcMain.handle('read-file', async (event, fileName) => { ipcMain.handle('change-content', async (event, nextPage) => { try { html_page = nextPage; - mainWindow.webContents.executeJavaScript(` - document.body.classList.add('fade-out'); - `); - - await new Promise(resolve => setTimeout(resolve, 1000)); await mainWindow.loadFile(path.join(__dirname, '..', 'renderer', 'html', nextPage)); - - mainWindow.webContents.executeJavaScript(` - document.body.classList.add('fade-in'); - `); return true; } catch (error) { console.error('Error changing content:', error); @@ -197,3 +263,59 @@ ipcMain.on('close-alert-window', () => { alertWindow = undefined; } }); + +//External processes + +ipcMain.handle('start-fetcher', async (event, args) => { + if (fetcherProcess === null) { + fetcherProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'fetcher.js'), args, { silent: false }); + fetcherProcess.on('exit', () => { + fetcherProcess = null; + // Optionally, notify the renderer process that the fetcher has finished + }); + } + return true; // Indicate that the operation has started +}); + +// Handler to start the backup process +ipcMain.handle('start-backup', async (event, args) => { + if (backupProcess === null) { // Should this be a unique variable for backupProcess instead? + backupProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'backup.js'), args, { silent: false }); + backupProcess.on('exit', () => { + backupProcess = null; + // Optionally, notify the renderer process that the backup has finished + }); + } + return true; // Indicate that the operation has started +}); + +// Handler to start the decrypt-files process +ipcMain.handle('start-decrypt-files', async (event, args) => { + const decryptFilesProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'decrypt_files.js'), args, { silent: false }); + decryptFilesProcess.on('exit', () => { + event.sender.send('decrypt-files-finished', true); // Notify renderer process + }); + return true; // Indicate that the operation has started +}); + +// Handler to start the send_files process +ipcMain.handle('start-send_files', async (event, args) => { + // This seems to duplicate the 'start-decrypt-files' process; assuming a different script is intended + const sendFilesProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'send_files.js'), args, { silent: false }); + sendFilesProcess.on('exit', () => { + event.sender.send('send-files-finished', true); // Notify renderer process + }); + return true; // Indicate that the operation has started +}); + +// Handler to start the receiver process +ipcMain.handle('start-receiver', async (event, args) => { + if (receiverProcess === null) { + receiverProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'receiver.js'), args, { silent: false }); + receiverProcess.on('exit', () => { + receiverProcess = null; + // Optionally, notify the renderer process that the receiver has finished + }); + } + return true; // Indicate that the operation has started +}); diff --git a/User/src/main/preload.js b/User/src/main/preload.js index 6a718c7..d259984 100644 --- a/User/src/main/preload.js +++ b/User/src/main/preload.js @@ -9,5 +9,11 @@ contextBridge.exposeInMainWorld('electronAPI', { closeAlertWindow: () => ipcRenderer.send('close-alert-window'), openBackupDirDialog: () => ipcRenderer.invoke('open-backup-dir-dialog'), openFileDialog: () => ipcRenderer.invoke('open-file-dialog'), - checkFileExists: (fileName) => ipcRenderer.invoke('check-file-exists', fileName) + checkFileExists: (fileName) => ipcRenderer.invoke('check-file-exists', fileName), + + startFetcher: async (args) => ipcRenderer.invoke('start-fetcher', args), + startBackup: async (args) => ipcRenderer.invoke('start-backup', args), + startDecryptFiles: async (args) => ipcRenderer.invoke('start-decrypt-files', args), + startSendFiles: async (args) => ipcRenderer.invoke('start-send_files', args), + startReceiver: async (args) => ipcRenderer.invoke('start-receiver', args) }); \ No newline at end of file diff --git a/User/src/renderer/css/change_department.css b/User/src/renderer/css/change_department.css index 2549504..d34a81d 100644 --- a/User/src/renderer/css/change_department.css +++ b/User/src/renderer/css/change_department.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/ip_submit.css b/User/src/renderer/css/ip_submit.css new file mode 100644 index 0000000..1b40e46 --- /dev/null +++ b/User/src/renderer/css/ip_submit.css @@ -0,0 +1,98 @@ +body, html { + height: 100%; + width: 100%; + margin: 0; + padding: 0; + + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; + + background-image: url('../assets/background.png'); + background-size: cover; + background-repeat: no-repeat; + +} + +.container { + opacity: 0; + + display: flex; + flex-direction: row; + justify-content: space-evenly; + align-items: center; + min-height: 100vh; +} + + +.ip-form { + background-color: #535C91; + opacity: 71; + padding: 9vh 3vh 5vh; + border-radius: 1rem; + box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.9); + width: 25%; +} + +.ip-form-title{ + margin: 0 0 5vh 0; + text-align: center; +} + +.ip-form-title h2{ + color: #FFFFFF; + font-size: 5vh; + margin: 0; + padding: 0; +} + +.ip-form hr{ + width: 40%; +} + +.ip-form-content{ + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +input { + text-align: center; + color: white; + font-weight: bold; + font-size: 1.2rem; + width: 70%; + padding: 1rem; + margin: 0.7rem; + background-color: #1B1A55; + border-radius: 10px; +} + +button { + font-weight: bold; + width: 35%; + font-size: 1rem; + padding: 10px; + border: none; + border-radius: 5px; + margin-top: 1rem; + cursor: pointer; +} + +button:hover{ + filter: brightness(85%); +} + +.ip-form-footer{ + margin-top: 3vh; + display: flex; + flex-wrap: wrap; + align-content: center; + align-items: center; + justify-content: space-evenly; +} + +button[name="submit"] { + background-color: #F44336; + color: white; +} \ No newline at end of file diff --git a/User/src/renderer/css/login.css b/User/src/renderer/css/login.css index 3e04a36..00530ae 100644 --- a/User/src/renderer/css/login.css +++ b/User/src/renderer/css/login.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; @@ -102,7 +104,7 @@ button[name="submit"] { color: white; } -button[name="signin"] { +button[name="signup"] { background-color: #2196F3; color: white; } \ No newline at end of file diff --git a/User/src/renderer/css/main_menu.css b/User/src/renderer/css/main_menu.css index 259ac29..54b52d9 100644 --- a/User/src/renderer/css/main_menu.css +++ b/User/src/renderer/css/main_menu.css @@ -85,6 +85,8 @@ input { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/profile.css b/User/src/renderer/css/profile.css index f030018..3197e2e 100644 --- a/User/src/renderer/css/profile.css +++ b/User/src/renderer/css/profile.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/sending_file_confirmation.css b/User/src/renderer/css/sending_file_confirmation.css index 0c2ff31..ea7177f 100644 --- a/User/src/renderer/css/sending_file_confirmation.css +++ b/User/src/renderer/css/sending_file_confirmation.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/share_file.css b/User/src/renderer/css/share_file.css index a4a77ae..128b495 100644 --- a/User/src/renderer/css/share_file.css +++ b/User/src/renderer/css/share_file.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/sign_up_confirmation.css b/User/src/renderer/css/sign_up_confirmation.css index 2dbc893..183c9f9 100644 --- a/User/src/renderer/css/sign_up_confirmation.css +++ b/User/src/renderer/css/sign_up_confirmation.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/sign_up_department.css b/User/src/renderer/css/sign_up_department.css index f15f98a..009caab 100644 --- a/User/src/renderer/css/sign_up_department.css +++ b/User/src/renderer/css/sign_up_department.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/css/sing_up_profile.css b/User/src/renderer/css/sing_up_profile.css index 43fdc42..9fda52d 100644 --- a/User/src/renderer/css/sing_up_profile.css +++ b/User/src/renderer/css/sing_up_profile.css @@ -15,6 +15,8 @@ body, html { } .container { + opacity: 0; + display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/User/src/renderer/html/change_department.html b/User/src/renderer/html/change_department.html index 61c1445..d8e0564 100644 --- a/User/src/renderer/html/change_department.html +++ b/User/src/renderer/html/change_department.html @@ -9,10 +9,11 @@ + Department Selection - +
diff --git a/User/src/renderer/html/decrypting_files.html b/User/src/renderer/html/decrypting_files.html new file mode 100644 index 0000000..5f80209 --- /dev/null +++ b/User/src/renderer/html/decrypting_files.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + Setup Completion + + +
+
+

SENDING THE FILE!

+

PlEASE WAIT

+ Description of GIF + +
+
+ + diff --git a/User/src/renderer/html/ip_submit.html b/User/src/renderer/html/ip_submit.html new file mode 100644 index 0000000..007ccfd --- /dev/null +++ b/User/src/renderer/html/ip_submit.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + IP Submit + + +
+ +
+

IP Config

+
+
+
+ +
+ + +
+ + diff --git a/User/src/renderer/html/login.html b/User/src/renderer/html/login.html index 13753ba..5a8f5c4 100644 --- a/User/src/renderer/html/login.html +++ b/User/src/renderer/html/login.html @@ -4,12 +4,16 @@ + + + + Login - +

DO WE KNOW

@@ -25,7 +29,7 @@
diff --git a/User/src/renderer/html/main_menu.html b/User/src/renderer/html/main_menu.html index 24e7c37..d230d08 100644 --- a/User/src/renderer/html/main_menu.html +++ b/User/src/renderer/html/main_menu.html @@ -4,15 +4,17 @@ + + Main Page - +

CEO Authentication

diff --git a/User/src/renderer/html/profile.html b/User/src/renderer/html/profile.html index 0684a8e..3840aaf 100644 --- a/User/src/renderer/html/profile.html +++ b/User/src/renderer/html/profile.html @@ -9,10 +9,11 @@ + Profile - +
diff --git a/User/src/renderer/html/sending_file_confirmation.html b/User/src/renderer/html/sending_file_confirmation.html index 762093c..5f80209 100644 --- a/User/src/renderer/html/sending_file_confirmation.html +++ b/User/src/renderer/html/sending_file_confirmation.html @@ -4,10 +4,15 @@ - Setup Completion + + + + + + Setup Completion - +

SENDING THE FILE!

diff --git a/User/src/renderer/html/share_file.html b/User/src/renderer/html/share_file.html index fabf9a9..4f7fc47 100644 --- a/User/src/renderer/html/share_file.html +++ b/User/src/renderer/html/share_file.html @@ -9,9 +9,11 @@ + + Share File - +
diff --git a/User/src/renderer/html/sign_up_confirmation.html b/User/src/renderer/html/sign_up_confirmation.html index 0b34001..089c38b 100644 --- a/User/src/renderer/html/sign_up_confirmation.html +++ b/User/src/renderer/html/sign_up_confirmation.html @@ -4,12 +4,16 @@ + + + + Setup Completion - +

ALL THE SETUP IS DONE!

diff --git a/User/src/renderer/html/sign_up_departments.html b/User/src/renderer/html/sign_up_departments.html index 4d2f37b..86bf10c 100644 --- a/User/src/renderer/html/sign_up_departments.html +++ b/User/src/renderer/html/sign_up_departments.html @@ -9,10 +9,11 @@ + Department Selection - +

TELL ME MORE

diff --git a/User/src/renderer/html/sign_up_profile.html b/User/src/renderer/html/sign_up_profile.html index 6d23359..01b3448 100644 --- a/User/src/renderer/html/sign_up_profile.html +++ b/User/src/renderer/html/sign_up_profile.html @@ -4,12 +4,16 @@ + + + + Signup - +

LET US MEET

diff --git a/User/src/renderer/js/change_department.js b/User/src/renderer/js/change_department.js index 9a9a035..d1b5dec 100644 --- a/User/src/renderer/js/change_department.js +++ b/User/src/renderer/js/change_department.js @@ -1,82 +1,78 @@ -document.addEventListener('DOMContentLoaded', async function() { - try { - // Make API call to fetch department data - const response = await fetch('http://localhost:5000/departments', { - method: 'GET', - headers: { - 'x-api-key': 'uc_api' - } - }); - const res = await response.json(); +document.addEventListener('DOMContentLoaded', async function () { + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) + + await fetch(`http://${ip}/users/departments`, { + method: 'GET', + headers: { + 'x-api-key': 'uc_api' + } + }).then(async result => { + const res = await result.json(); const data = res['data']; const formContent = document.querySelector('.department-form-content'); - data.forEach(department => { + Object.entries(data).forEach(([key, department]) => { const label = document.createElement('label'); - label.innerHTML = `${department.name}`; + label.innerHTML = `${department.name}`; formContent.appendChild(label); }); - } catch (error) { + }).catch(async error => { await window.electronAPI.showAlert(error.message) .then(() => console.log('Alert window opened')) .catch(error => console.error('Error changing content:', error)); - } + }); document.getElementById('back').addEventListener('click', async function () { try { - await window.electronAPI.changeContent('main_menu.html'); + await fadeOut('main_menu.html'); console.log('Content changed successfully'); } catch (error) { console.error('Error changing content:', error); } }); - document.getElementById('submit').addEventListener('click', async function(e) { + document.getElementById('submit').addEventListener('click', async function (e) { e.preventDefault(); const selectedDept = document.querySelector('input[name="dept"]:checked').value; + if (!selectedDept) { + throw new Error('No department had been selected!.'); + } - try { - if (!selectedDept) { - throw new Error('No department had been selected!.'); + let result = await window.electronAPI.readFile('loginData.json'); + if (!result.success) { + throw new Error('Error reading the file. Please try again later.'); + } + + const data = JSON.parse(await result.content); + const id = data.id; + + await fetch(`http://${ip}/users/change_department`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify({ + id: id, + department: selectedDept, + }) + }).then(async response => { + if (!response.ok) { + return; } - let result = await window.electronAPI.readFile('loginData.json'); - if (!result.success) { - throw new Error('Error reading the file. Please try again later.'); - } - - const data = JSON.parse(result.content); - const id = data.id; - - await fetch(`http://localhost:5000/users/${id}`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ - department: selectedDept, - }) - }).then(async response => { - if(!response.ok){ - await window.electronAPI.showAlert("Internal server error. Try again later!") - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error changing content:', error)); - return; - } - - window.electronAPI.changeContent('main_menu.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); - }).catch(error => { - console.error(error); - }); - - } catch (error) { + fadeOut('main_menu.html') + }).catch(async error => { + console.error(error); await window.electronAPI.showAlert(error.message) .then(() => console.log('Alert window opened')) .catch(error => console.error('Error changing content:', error)); - } + }); }); -}); \ No newline at end of file +}) diff --git a/User/src/renderer/js/ip_submit.js b/User/src/renderer/js/ip_submit.js new file mode 100644 index 0000000..7c78d06 --- /dev/null +++ b/User/src/renderer/js/ip_submit.js @@ -0,0 +1,33 @@ +document.addEventListener('DOMContentLoaded', async function () { + const submitButton = document.getElementById('submit'); + const ipInput = document.getElementById('ipInput'); + + submitButton.addEventListener('click', async function (e) { + e.preventDefault(); + try { + const ipAddress = ipInput.value.trim(); + if (!ipAddress) { + throw new Error('Please enter an IP address.'); + } + + fetch(`http://${ipAddress}/heartbeat`) + .then(async response => { + if (!response.ok) { + throw new Error('Test failed. Check ip and server.'); + } + + await window.electronAPI.writeFile('ipConfig.json', JSON.stringify({ip: ipAddress})); + fadeOut('login.html'); + }) + .catch(error => { + console.error('Error:', error.message); + throw new Error(error.message); + }); + } catch (error) { + console.error('Error:', error.message); + await window.electronAPI.showAlert(error.message) + .then(() => console.log('Alert window opened')) + .catch(error => console.error('Error showing alert:', error)); + } + }); +}); diff --git a/User/src/renderer/js/login.js b/User/src/renderer/js/login.js index a199849..3f1b4bd 100644 --- a/User/src/renderer/js/login.js +++ b/User/src/renderer/js/login.js @@ -1,89 +1,93 @@ document.addEventListener('DOMContentLoaded', async function () { - const signinButton = document.getElementById('signin'); + const signupButton = document.getElementById('signup'); const submitButton = document.getElementById('submit'); - await window.electronAPI.readFile('loginData.json') - .then(async result => { - const loginData = JSON.parse(result.content); - const { email, password } = loginData; + const signupDataExists = await window.electronAPI.checkFileExists('signupData.json'); + if(signupDataExists){ + await window.electronAPI.deleteFile('signupData.json'); + } - const response = await fetch('http://localhost:5000/users/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ - email: email, - password: password - }) + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) + + const fileExists = await window.electronAPI.checkFileExists('loginData.json'); + if (fileExists) { + await window.electronAPI.readFile('loginData.json') + .then(async result => { + const loginData = JSON.parse(result.content); + console.log(loginData); + const {email, password} = loginData; + + await fetch(`http://${ip}/users/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify({ + email: email, + password: password + }) + }).then(response => { + if (response.ok) { + fadeOut('main_menu.html'); + } + }).catch(error => { + console.error(error); + }); + }) + .catch(async error => { + console.error('Can\'t read loginData'); + await window.electronAPI.deleteFile('loginData.json'); }); + } - if(response.ok) { - window.electronAPI.changeContent('main_menu.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); - } - }).catch(async error => { - console.error('Can\'t read loginData'); - await window.electronAPI.deleteFile('loginData.json') - }); - - signinButton.addEventListener('click', function (e) { - window.electronAPI.changeContent('sign_up_profile.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); + signupButton.addEventListener('click', function (e) { + e.preventDefault(); + console.log('Sign up button clicked.') + fadeOut('sign_up_profile.html'); }); submitButton.addEventListener('click', async function (e) { - try { - e.preventDefault(); - console.log('Submit button clicked'); + e.preventDefault(); + console.log('Submit button clicked'); - const form = document.getElementById('loginForm'); - const formData = new FormData(form); + const form = document.getElementById('loginForm'); + const formData = new FormData(form); - const email = formData.get('email'); - const password = formData.get('password'); + const email = formData.get('email'); + const password = formData.get('password'); - if (!email || !password) { - throw new Error('Both email and password are required.'); + await fetch(`http://${ip}/users/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify({ + email: email, + password: password + }) + }).then(async response => { + if (!response.ok) { + const data = await response.json(); + throw new Error(data.message); } - const response = await fetch('http://localhost:5000/users/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ - email: email, - password: password - }) - }); - - switch (response.status) { - case 401: - throw new Error('Invalid credentials!'); - case 500: - throw new Error('Internal server error. Try again later!'); - } - - const responseBody = await response.json(); - - const result = await window.electronAPI.writeFile('loginData.json', JSON.stringify(responseBody.message, null, 2)); - if (!result.success) { - throw new Error('Error writing to file. Please try again later.'); - } - - window.electronAPI.changeContent('main_menu.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); - - } catch (error) { - await window.electronAPI.showAlert(error.message) - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error)); - } + return response.json(); + }).then(async data => { + console.log(data) + await window.electronAPI.writeFile('loginData.json', JSON.stringify(responseBody.message, null, 2)); + fadeOut('main_menu.html'); + }) + .catch(async error => { + await window.electronAPI.showAlert(error.message) + .then(() => console.log('Alert window opened')) + .catch(error => console.error('Error showing alert:', error)); + }) }); }); diff --git a/User/src/renderer/js/main_menu.js b/User/src/renderer/js/main_menu.js index b5c3c47..6f9f80d 100644 --- a/User/src/renderer/js/main_menu.js +++ b/User/src/renderer/js/main_menu.js @@ -10,8 +10,16 @@ document.addEventListener('DOMContentLoaded', async function () { const ceoBackButton = document.getElementById('back_button'); const ceoSubmitButton = document.getElementById('submit_button'); + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) + let triggerSource = ''; + function handleOverlayOpen(buttonId) { overlay.style.display = 'block'; triggerSource = buttonId; // Remember the button that triggered the overlay @@ -26,70 +34,35 @@ document.addEventListener('DOMContentLoaded', async function () { handleOverlayOpen('decrypt'); }); - // Hide the form when the "Back" button is clicked ceoBackButton.addEventListener('click', function() { overlay.style.display = 'none'; }); - // Validate and process the form when submitted ceoSubmitButton.addEventListener('click', async function(event) { event.preventDefault(); const password = document.getElementById('ceo_password').value; - if (password === '') { - await window.electronAPI.showAlert('Please enter password') - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error)); - return; - } - - let fetchResult; - let fetchJson = undefined; - - fetchResult = await fetch('http://localhost:5000/admin/reset_key', { - method: 'GET', - headers: { - 'x-api-key': 'uc_api' - } - }) - - if(!fetchResult.ok){ - await window.electronAPI.showAlert('Internal server error. Please try again later!') - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error)); - return; - } - - fetchJson = await fetchResult.json(); - const adminKey = fetchJson['data']; - - fetchResult = await fetch('http://localhost:5000/admin/validate_admin_password', { + await fetch(`http://${ip}/users/validate_ceo_password`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'uc_api', - 'admin-key': adminKey }, body: JSON.stringify({ password: password }) + }).then(async result => { + const data = await result.json(); + if(!result.ok){ + throw new Error(data.message); + } + if (triggerSource === 'change_department') { + fadeOut('change_department.html'); + }else if (triggerSource === 'decrypt'){ + fadeOut('decrypting_files.html'); + } }) - if(!fetchResult.ok){ - await window.electronAPI.showAlert('The password is incorrect') - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error)); - return; - } - - if (triggerSource === 'change_department') { - window.electronAPI.changeContent('change_department.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); - } else if (triggerSource === 'decrypt') { - await decryptFiles() - } - overlay.style.display = 'none'; triggerSource = ''; }); @@ -110,29 +83,19 @@ document.addEventListener('DOMContentLoaded', async function () { changeInfoButton.addEventListener('click', function () { console.log('Change your info button clicked!'); - - window.electronAPI.changeContent('profile.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); + fadeOut('profile.html'); }); shareFileButton.addEventListener('click', function () { console.log('Share a file button clicked!'); - - window.electronAPI.changeContent('share_file.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); + fadeOut('share_file.html'); }); - - logoutButton.addEventListener('click', async function () { console.log('Logout button clicked!'); await window.electronAPI.deleteFile('loginData.json'); - window.electronAPI.changeContent('login.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); + fadeOut('login.html'); }); async function checkDirBackupFileExists() { @@ -184,8 +147,4 @@ document.addEventListener('DOMContentLoaded', async function () { usernameField.textContent = 'User!'; } } - - async function decryptFiles(){ - - } }); diff --git a/User/src/renderer/js/profile.js b/User/src/renderer/js/profile.js index a3d0f41..e4972d2 100644 --- a/User/src/renderer/js/profile.js +++ b/User/src/renderer/js/profile.js @@ -1,25 +1,26 @@ document.addEventListener('DOMContentLoaded', async function () { - try { - const result = await window.electronAPI.readFile('loginData.json'); - const loginData = JSON.parse(result.content); - // Set values for the inputs - const emailInput = document.querySelector('input[name="email"]'); - const usernameInput = document.querySelector('input[name="username"]'); - const passwordInput = document.querySelector('input[name="password"]'); + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) - emailInput.value = loginData.email; - usernameInput.value = loginData.name; - passwordInput.value = loginData.password; + const result = await window.electronAPI.readFile('loginData.json'); + const loginData = JSON.parse(result.content); - } catch (error) { - console.error('Error reading login data:', error); - } + const emailInput = document.querySelector('input[name="email"]'); + const usernameInput = document.querySelector('input[name="username"]'); + const passwordInput = document.querySelector('input[name="password"]'); + + emailInput.value = loginData.email; + usernameInput.value = loginData.name; + passwordInput.value = loginData.password; const backButton = document.querySelector('button[name="login"]'); const submitButton = document.querySelector('button[name="submit"]'); - // Add event listeners for the back and submit buttons backButton.addEventListener('click', function () { console.log('Back button clicked!'); @@ -29,42 +30,36 @@ document.addEventListener('DOMContentLoaded', async function () { }); submitButton.addEventListener('click', async function (e) { - try { - e.preventDefault(); - console.log('Submit button clicked!'); + e.preventDefault(); + console.log('Submit button clicked!'); - const emailInput = document.querySelector('input[name="email"]'); - const usernameInput = document.querySelector('input[name="username"]'); - const passwordInput = document.querySelector('input[name="password"]'); + const emailInput = document.querySelector('input[name="email"]'); + const usernameInput = document.querySelector('input[name="username"]'); + const passwordInput = document.querySelector('input[name="password"]'); - const result = await window.electronAPI.readFile('loginData.json'); - const loginData = JSON.parse(result.content); + const result = await window.electronAPI.readFile('loginData.json'); + const loginData = JSON.parse(result.content); - const {id, department} = loginData; - const email = emailInput.value; - const name = usernameInput.value; - const password = passwordInput.value; + const {id, department} = loginData; + const email = emailInput.value; + const name = usernameInput.value; + const password = passwordInput.value; - const response = await fetch(`http://localhost:5000/users/${id}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ - name: name, - email: email, - password: password - }) - }); - - switch (response.status) { - case 400: - throw new Error('Email format invalid!') - case 409: - throw new Error('Email already in system!') - case 500: - throw new Error('Internal server error. Try again later!') + await fetch(`http://${ip}/users`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify({ + name: name, + email: email, + password: password + }) + }).then(async result => { + const data = await result.json(); + if (!result.ok) { + throw new Error(data.message); } await window.electronAPI.writeFile('loginData.json', JSON.stringify({ @@ -75,13 +70,11 @@ document.addEventListener('DOMContentLoaded', async function () { department: department })); - window.electronAPI.changeContent('main_menu.html') - .then(() => console.log('Navigated to dashboard')) - .catch(error => console.error('Error navigating:', error)); - }catch(error) { + fadeOut('main_menu.html'); + }).catch(async error => { await window.electronAPI.showAlert(error.message) .then(() => console.log('Alert window opened')) .catch(error => console.error('Error showing alert:', error)); - } + }) }); }); diff --git a/User/src/renderer/js/share_file.js b/User/src/renderer/js/share_file.js index 4a64652..d7eb6ef 100644 --- a/User/src/renderer/js/share_file.js +++ b/User/src/renderer/js/share_file.js @@ -10,7 +10,6 @@ document.addEventListener("DOMContentLoaded", function() { } } - // Call the function to update file name on DOMContentLoaded updateFileName(); async function fetchUsersAndCreateCheckboxes() { @@ -60,13 +59,7 @@ document.addEventListener("DOMContentLoaded", function() { document.getElementById('backButton').addEventListener('click', async function () { console.log('Back button clicked'); - - try { - await window.electronAPI.changeContent('main_menu.html'); - console.log('Content changed successfully'); - } catch (error) { - console.error('Error changing content:', error); - } + fadeOut('main_menu.html'); }); document.getElementById('submitButton').addEventListener('click', async function (event) { diff --git a/User/src/renderer/js/sign_up_confirmation.js b/User/src/renderer/js/sign_up_confirmation.js index c13607f..a52c0a8 100644 --- a/User/src/renderer/js/sign_up_confirmation.js +++ b/User/src/renderer/js/sign_up_confirmation.js @@ -1,7 +1,4 @@ document.addEventListener('DOMContentLoaded', async function() { await new Promise(resolve => setTimeout(resolve, 2000)); - - window.electronAPI.changeContent('login.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); + fadeOut('login.html'); }); diff --git a/User/src/renderer/js/sign_up_departments.js b/User/src/renderer/js/sign_up_departments.js index 4d08d0d..9da4ab2 100644 --- a/User/src/renderer/js/sign_up_departments.js +++ b/User/src/renderer/js/sign_up_departments.js @@ -1,93 +1,88 @@ -document.addEventListener('DOMContentLoaded', async function() { - try { - // Make API call to fetch department data - const response = await fetch('http://localhost:5000/departments', { - method: 'GET', - headers: { - 'x-api-key': 'uc_api' - } - }); - const res = await response.json(); +document.addEventListener('DOMContentLoaded', async function () { + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) + + await fetch(`http://${ip}/users/departments`, { + method: 'GET', + headers: { + 'x-api-key': 'uc_api' + } + }).then(async result => { + const res = await result.json(); const data = res['data']; const formContent = document.querySelector('.signup-form-content'); - data.forEach(department => { + Object.entries(data).forEach(([key, department]) => { const label = document.createElement('label'); - label.innerHTML = `${department.name}`; + label.innerHTML = `${department.name}`; formContent.appendChild(label); }); - } catch (error) { + }).catch(async error => { await window.electronAPI.showAlert(error.message) .then(() => console.log('Alert window opened')) .catch(error => console.error('Error changing content:', error)); - } + }); - document.getElementById('back').addEventListener('click', async function() { - try { - await window.electronAPI.changeContent('sign_up_profile.html'); - console.log('Content changed successfully'); - } catch (error) { - console.error('Error changing content:', error); - } + document.getElementById('back').addEventListener('click', async function () { + fadeOut('sign_up_profile.html'); }); // Handler for the continue button - document.getElementById('submit').addEventListener('click', async function(e) { + document.getElementById('submit').addEventListener('click', async function (e) { e.preventDefault(); - const selectedDept = document.querySelector('input[name="dept"]:checked').value; + await window.electronAPI.readFile('signupData.json') + .then(async result => { + const selectedDept = document.querySelector('input[name="dept"]:checked').value; + if (!selectedDept) { + throw new Error('No department had been selected!.'); + } - try { - if (!selectedDept) { - throw new Error('No department had been selected!.'); - } + const data = JSON.parse(result.content); - let result = await window.electronAPI.readFile('signupData.json'); - if (!result.success) { - throw new Error('Error reading the file. Please try again later.'); - } + const email = data.email; + const name = data.name; + const password = data.password; - const data = JSON.parse(result.content); - - const email = data.email; - const name = data.name; - const password = data.password; - - result = await window.electronAPI.deleteFile('signupData.json'); - if (!result.success) { - throw new Error('Error deleting the file. Please try again later.'); - } - - await fetch('http://localhost:5000/users/register', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ + const userData = { name: name, email: email, password: password, department: selectedDept, - }) - }).then(async response => { - if(!response.ok){ - await window.electronAPI.showAlert("Internal server error. Try again later!") - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error changing content:', error)); } - window.electronAPI.changeContent('sign_up_confirmation.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); - }).catch(error => { - console.error(error); - }); + await fetch(`http://${ip}/users/register`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify(userData) + }) + .then(async response => { + let data = await response.json(); - } catch (error) { - await window.electronAPI.showAlert(error.message) - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error changing content:', error)); - } + if (!response.ok) { + console.log(data); + throw new Error(data.message); + } + + data = data.data; + userData['id'] = data.id; + + await window.electronAPI.writeFile('loginData.json', JSON.stringify(userData)); + fadeOut('sign_up_confirmation.html'); + }) + }) + .catch(async error => { + await window.electronAPI.showAlert(error.message) + .then(() => console.log('Alert window opened')) + .catch(error => console.error('Error changing content:', error)); + }) }); -}); +}) + diff --git a/User/src/renderer/js/sign_up_profile.js b/User/src/renderer/js/sign_up_profile.js index a9cfb63..8e90ef2 100644 --- a/User/src/renderer/js/sign_up_profile.js +++ b/User/src/renderer/js/sign_up_profile.js @@ -1,81 +1,71 @@ -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener('DOMContentLoaded', async function () { const cancelButton = document.getElementById('login'); const continueButton = document.getElementById('continue'); + const signupDataExists = await window.electronAPI.checkFileExists('signupData.json'); + if(signupDataExists){ + await window.electronAPI.readFile('signupData.json') + .then(result => { + const signupData = JSON.parse(result.content); + + // Assign the values to the form inputs + if (signupData.email) document.querySelector('input[name="email"]').value = signupData.email; + if (signupData.name) document.querySelector('input[name="name"]').value = signupData.name; + if (signupData.password) document.querySelector('input[name="password"]').value = signupData.password; + }) + .catch(error => { + console.error('Error reading signup data:', error.message); + }); + } + + let ip = ''; + await window.electronAPI.readFile('ipConfig.json') + .then(result => { + const jsonData = JSON.parse(result.content); + ip = jsonData.ip; + }) + cancelButton.addEventListener('click', function () { console.log(`'Login' button clicked!`); - window.electronAPI.changeContent('login.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); + fadeOut('login.html'); }); continueButton.addEventListener('click', async function (e) { - try { - e.preventDefault(); - console.log('Continue button clicked'); + e.preventDefault(); + console.log('Continue button clicked'); - const form = document.getElementById('signupForm'); - const formData = new FormData(form); + const form = document.getElementById('signupForm'); + const formData = new FormData(form); - const email = formData.get('email'); - const name = formData.get('name'); - const password = formData.get('password'); + const email = formData.get('email'); - if (!email || !name || !password) { - throw new Error('All fields are required.'); - } - - if(password.length < 8){ - throw new Error('Password must have minimum length 8!'); - } - - let statusFetch = 200; - - await fetch('http://localhost:5000/users/validate_email', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api' - }, - body: JSON.stringify({ - email: email - }) - }).then(async response => { - const responseData = await response.json(); - statusFetch = response.status; - console.error(responseData.message); + await fetch(`http://${ip}/users/validate_email`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify({ + email: email }) - .catch(error => { - console.log(error); - }) - - switch(statusFetch){ - case 500: - throw new Error('Internal server error! Try again later'); - case 400: - throw new Error('Not a valid email!'); - case 409: - throw new Error('Email already exists in system!'); + }).then(async response => { + if (!response.ok) { + const data = await response.json(); + throw new Error(data.message); } + }).then(async () => { const formDataJSON = {}; formData.forEach((value, key) => { formDataJSON[key] = value; }); - const result = await window.electronAPI.writeFile('signupData.json', JSON.stringify(formDataJSON)); - if (!result.success) { - throw new Error('Error writing to file. Please try again later.'); - } - - window.electronAPI.changeContent('sign_up_departments.html') - .then(() => console.log('Content changed successfully')) - .catch(error => console.error('Error changing content:', error)); - } - catch (error) { - await window.electronAPI.showAlert(error.message) - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error changing content:', error));; - } + await window.electronAPI.writeFile('signupData.json', JSON.stringify(formDataJSON)); + fadeOut('sign_up_departments.html'); + }).catch(async error => { + await window.electronAPI.showAlert(error.message) + .then(() => console.log('Alert window opened')) + .catch(error => console.error('Error changing content:', error)); + }) }); }); \ No newline at end of file diff --git a/User/src/renderer/js/transition.js b/User/src/renderer/js/transition.js new file mode 100644 index 0000000..b5cb1c8 --- /dev/null +++ b/User/src/renderer/js/transition.js @@ -0,0 +1,16 @@ +function fadeIn() { + document.querySelector('.container').classList.remove('fade-out'); + document.querySelector('.container').classList.add('fade-in'); +} + +function fadeOut(destination) { + const container = document.querySelector('.container'); + container.classList.remove('fade-in'); + container.classList.add('fade-out'); + + container.addEventListener('animationend', async () => { + await window.electronAPI.changeContent(destination) + .then(() => console.log('Navigated to dashboard')) + .catch(error => console.error('Error navigating:', error)); + }); +} \ No newline at end of file