From 5ebdc1b69abc944a95e50b6d24421e9126d237f8 Mon Sep 17 00:00:00 2001 From: andrei-mihnea-cerbu Date: Thu, 25 Apr 2024 00:29:16 +0300 Subject: [PATCH] v2.9 --- .../New Microsoft Excel Worksheet.xlsx | Bin 6191 -> 0 bytes .../fisiere/New Microsoft Word Document.docx | Bin 13172 -> 0 bytes .../New Microsoft Excel Worksheet.xlsx | Bin 6191 -> 0 bytes .../fisiere/New Microsoft Word Document.docx | Bin 13172 -> 0 bytes CEO/filesReceived.json | 1 + CEO/jobs/external_endpoints.js | 98 ++++++----- CEO/src/main/main.js | 94 +++++++---- CEO/src/main/preload.js | 5 +- CEO/src/renderer/js/login.js | 1 - CEO/src/renderer/js/main_menu.js | 50 +++++- UC/backend/src/db/backup_schemes.json | 2 +- User/jobs/external_endpoints.js | 36 ++-- User/src/main/main.js | 99 +++++++---- User/src/main/preload.js | 5 +- User/src/renderer/js/main_menu.js | 156 +++++++----------- 15 files changed, 327 insertions(+), 220 deletions(-) delete mode 100644 CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Excel Worksheet.xlsx delete mode 100644 CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Word Document.docx delete mode 100644 CEO/backup_directories/7c0ef9d5-23ed-47a6-bfb4-fdcfce436904/backup_dir/fisiere/New Microsoft Excel Worksheet.xlsx delete mode 100644 CEO/backup_directories/7c0ef9d5-23ed-47a6-bfb4-fdcfce436904/backup_dir/fisiere/New Microsoft Word Document.docx create mode 100644 CEO/filesReceived.json diff --git a/CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Excel Worksheet.xlsx b/CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Excel Worksheet.xlsx deleted file mode 100644 index d8b87bb270569256a64d027ee2002af37bd99042..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6191 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 NIe5C)mjWQN&KOnH22%h4 diff --git a/CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Word Document.docx b/CEO/backup_directories/59c712d9-e6dd-438f-aec9-31ca2ae750e6/backup_dir/fisiere/New Microsoft Word Document.docx deleted file mode 100644 index ff9468957375124debddb0cda2fb6fb6e860b795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13172 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 Nf3T^Yuro+UHHxJJBk%wK diff --git a/CEO/backup_directories/7c0ef9d5-23ed-47a6-bfb4-fdcfce436904/backup_dir/fisiere/New Microsoft Word Document.docx b/CEO/backup_directories/7c0ef9d5-23ed-47a6-bfb4-fdcfce436904/backup_dir/fisiere/New Microsoft Word Document.docx deleted file mode 100644 index ebcad29d7631870b1546b7a66641979a0c65d8d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13172 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 aHn^PV7F(;T68&>pKnFj8sGjnUFm}Z>RE%i= diff --git a/CEO/filesReceived.json b/CEO/filesReceived.json new file mode 100644 index 0000000..45ae4b1 --- /dev/null +++ b/CEO/filesReceived.json @@ -0,0 +1 @@ +riº6Û‘Ñ»Û2d²–{ŽùãÇÛë%`nT´`ÐÄs \ No newline at end of file diff --git a/CEO/jobs/external_endpoints.js b/CEO/jobs/external_endpoints.js index 5a8fe16..73d3dc4 100644 --- a/CEO/jobs/external_endpoints.js +++ b/CEO/jobs/external_endpoints.js @@ -1,15 +1,15 @@ const express = require('express'); const fs = require('fs'); -const multer = require('multer'); const fsExtra = require('fs-extra'); const path = require('path'); const Joi = require('joi'); const { httpStatus } = require('../helpers/http_status'); const {lockFile, unlockFile} = require("../helpers/lock_mechanism"); +const {decryptFileInPlace, encryptFileInPlace} = require("../src/main/aes_encrypt"); const app = express(); app.use(express.json()); -app.use('/share_file', express.raw({ type: 'application/octet-stream', limit: 'Infinity' })); + const server = require('http').createServer(app); const connections = []; @@ -93,66 +93,82 @@ app.post('/file_path', async (req, res) => { async function addFilePathToJson(filePath) { const jsonFilePath = path.join(__dirname, '..', 'filesReceived.json'); + let data = { receivedFiles: [] }; try { - let data = { receivedFiles: [] }; - if (await fsExtra.pathExists(jsonFilePath)) { + // Check if the JSON file exists + const fileExists = await fsExtra.pathExists(jsonFilePath); + + if (fileExists) { await lockFile(jsonFilePath); + await decryptFileInPlace(jsonFilePath); data = await fsExtra.readJson(jsonFilePath); - }else{ + } else { + await fsExtra.writeJson(jsonFilePath, data, { spaces: 2 }); await lockFile(jsonFilePath); } - data.receivedFiles.push(filePath); + if (data.receivedFiles.findIndex(existingFilePath => existingFilePath === filePath) === -1) { + data.receivedFiles.push(filePath); + } + // Write the updated data back to the file await fsExtra.writeJson(jsonFilePath, data, { spaces: 2 }); + // Unlock the file after updating await unlockFile(jsonFilePath); + await encryptFileInPlace(jsonFilePath); console.log('File path added successfully.'); } catch (error) { console.error('Error updating JSON file:', error); - throw error; // Rethrow the error for further handling if necessary + await encryptFileInPlace(jsonFilePath); + await unlockFile(jsonFilePath); } } -const storage = multer.diskStorage({ - destination: function (req, file, cb) { - const baseDir = path.join(__dirname, '..', 'uploads', req.body.idUser); // Temp storage location - fsExtra.ensureDirSync(baseDir); - cb(null, baseDir); - }, - filename: function (req, file, cb) { - cb(null, req.body.nameOfFile); // Using directly assuming it has been validated already +app.use('/share_file', express.raw({ + type: 'application/octet-stream', + limit: '50mb' +})); + +async function getShareDir(filePath) { + try { + await lockFile(filePath); + + const fileContent = await fs.promises.readFile(filePath, 'utf8'); + const jsonData = JSON.parse(fileContent); + const path = jsonData.path; + + await unlockFile(filePath); + return path; + } catch (error) { + console.error('An error occurred:', error); + return null; } -}); +} -const upload = multer({ storage: storage }).single('file'); -// Route for file upload -app.post('/upload', async (req, res) => { - const shareFileSchema = Joi.object({ - idUser: Joi.string().required(), - nameOfFile: Joi.string().required(), - sizeOfFile: Joi.number().required() - }); +app.post('/share_file', async (req, res) => { + // Extract metadata from headers + const idUser = req.headers['x-iduser']; + const nameOfFile = req.headers['x-nameoffile']; + const sizeOfFile = req.headers['x-sizeoffile']; + + // You might want to validate the metadata here + if (!idUser || !nameOfFile || !sizeOfFile) { + return res.status(httpStatus.BAD_REQUEST).json({message: 'Missing metadata headers'}); + } + + // Construct the file path using the metadata + const shareDirPath = await getShareDir(path.join(__dirname, '..', 'dirShare.json')); + const baseDir = path.join(shareDirPath, idUser); + fsExtra.ensureDirSync(baseDir); + + const filePath = path.join(baseDir, nameOfFile); try { - const { error, value } = shareFileSchema.validate(req.body); - if (error) { - return res.status(httpStatus.BAD_REQUEST).send(`Validation error: ${error.message}`); - } - - await upload(req, res, async (err) => { - if (err instanceof multer.MulterError) { - res.status(httpStatus.INTERNAL_SERVER_ERROR).send(`Multer error: ${err.message}`); - return; - } else if (err) { - res.status(httpStatus.BAD_REQUEST).send(`Upload error: ${err.message}`); - return; - } - - // File upload logic - res.status(httpStatus.OK).json({ message: 'Upload successful.' }); - }); + fs.writeFileSync(filePath, req.body); + await addFilePathToJson(filePath); + res.status(httpStatus.OK).json({ message: 'Upload successful.' }); } catch (error) { console.error('Error during file upload:', error); res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ message: 'Internal server error.' }); diff --git a/CEO/src/main/main.js b/CEO/src/main/main.js index 6cbedb3..3e38464 100644 --- a/CEO/src/main/main.js +++ b/CEO/src/main/main.js @@ -1,4 +1,4 @@ -const {app, BrowserWindow, screen, ipcMain, dialog} = require('electron'); +const {app, BrowserWindow, screen, ipcMain, dialog, shell} = require('electron'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); @@ -6,6 +6,7 @@ const {fork} = require('child_process'); const {encryptFileInPlace, decryptFileInPlace} = require('./aes_encrypt'); const {lockFile, unlockFile} = require("../../helpers/lock_mechanism"); +const exec = require("nodemon/lib/config/exec"); const isMac = process.platform === 'darwin'; let html_page = undefined; @@ -31,32 +32,11 @@ const createInitialKeys = () => { console.log(`IV saved to ${ivPath}`); } -const deleteMainComponentsAtErrorStart = () => { - 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 checkForServerConnection = async () => { const pathToIpConfig = path.join(__dirname, '..', '..', 'ipConfig.json'); try { + console.log('Checking for server connection'); await fs.promises.access(pathToIpConfig); await lockFile(pathToIpConfig); @@ -71,17 +51,35 @@ const checkForServerConnection = async () => { return response.ok; } catch (error) { console.error("Error:", error); - return false; - } finally{ try{ fs.unlinkSync(pathToIpConfig); } catch{ } + return false; } }; +async function runStartupChecks() { + 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) { + console.error("Startup error detected:", err); + + // Run the npm clean script + await exec('npm run clean', { cwd: path.join(__dirname, '..', '..') }, (error, stdout, stderr) => { + if (error) { + console.error('Error occurred while running npm run clean:', stderr); + return; + } + console.log('npm run clean output:', stdout); + createInitialKeys(); + }); + } +} + const createMainWindow = (async (title, width, height) => { mainWindow = new BrowserWindow({ title: title, @@ -94,14 +92,7 @@ const createMainWindow = (async (title, width, height) => { } }); - 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) { - createInitialKeys(); - deleteMainComponentsAtErrorStart(); - } - + await runStartupChecks(); html_page = await checkForServerConnection() ? 'login.html' : 'ip_submit.html'; //mainWindow.setMenu(null); @@ -392,3 +383,40 @@ ipcMain.handle('decrypt-backup-files', async(event, destPath) => { }); } }) + +// Handle showing a file in the system file explorer +ipcMain.handle('show-file-in-explorer', async (event, filePath) => { + try { + // Ensure the file exists before attempting to show it + await fs.promises.access(filePath, fs.constants.F_OK); + shell.showItemInFolder(filePath); // Opens the file explorer and highlights the file + return true; + } catch (error) { + console.error('File does not exist:', error); + return false + } +}); + +// Handle removing a path from 'filesReceived.json' +ipcMain.handle('remove-path-from-received-files', async (event, filePath) => { + try { + const jsonFilePath = path.join(__dirname, '..', '..', 'filesReceived.json'); + await lockFile(jsonFilePath); + await decryptFileInPlace(jsonFilePath); + const data = await fs.promises.readFile(jsonFilePath, 'utf8'); + + const jsonData = JSON.parse(data); + + // Filter out the specified file path + jsonData.receivedFiles = jsonData.receivedFiles.filter(file => file !== filePath); + + await fs.promises.writeFile(jsonFilePath, JSON.stringify(jsonData, null, 2), 'utf8'); + await encryptFileInPlace(jsonFilePath); + await unlockFile(jsonFilePath); + + return true; + } catch (error) { + console.error('Error updating filesReceived.json:', error); + throw new Error('Failed to update received files list.'); + } +}); diff --git a/CEO/src/main/preload.js b/CEO/src/main/preload.js index 2aec160..a1ac5ca 100644 --- a/CEO/src/main/preload.js +++ b/CEO/src/main/preload.js @@ -14,5 +14,8 @@ contextBridge.exposeInMainWorld('electronAPI', { startMainProcesses: async (args) => ipcRenderer.invoke('start-main-processes', args), killBeforeLogout: async() => ipcRenderer.invoke('kill-before-logout'), - decryptFiles: async(destPath) => ipcRenderer.invoke('decrypt-backup-files', destPath) + decryptFiles: async(destPath) => ipcRenderer.invoke('decrypt-backup-files', destPath), + + showFileInExplorer: (filePath) => ipcRenderer.invoke('show-file-in-explorer', filePath), + removePathFromReceivedFiles: (filePath) => ipcRenderer.invoke('remove-path-from-received-files', filePath) }); \ No newline at end of file diff --git a/CEO/src/renderer/js/login.js b/CEO/src/renderer/js/login.js index 76c7bc8..2109265 100644 --- a/CEO/src/renderer/js/login.js +++ b/CEO/src/renderer/js/login.js @@ -18,7 +18,6 @@ document.addEventListener('DOMContentLoaded', async function () { 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}/ceo/login`, { diff --git a/CEO/src/renderer/js/main_menu.js b/CEO/src/renderer/js/main_menu.js index 8335dd0..737a480 100644 --- a/CEO/src/renderer/js/main_menu.js +++ b/CEO/src/renderer/js/main_menu.js @@ -1,5 +1,6 @@ document.addEventListener('DOMContentLoaded', async function () { await insertUsername(); + setInterval(loadReceivedFiles, 3000); // Call loadReceivedFiles every 5000 ms (5 seconds) const backupButton = document.getElementById('backup'); const shareButton = document.getElementById('share_dir'); @@ -11,6 +12,53 @@ document.addEventListener('DOMContentLoaded', async function () { const decryptButton = document.getElementById('decrypt'); const logoutButton = document.getElementById('logout'); + async function loadReceivedFiles() { + const checkFileReceived = await window.electronAPI.checkFileExists('filesReceived.json'); + if (!checkFileReceived) { + return; + } + + try { + const fileData = await window.electronAPI.readFile('filesReceived.json'); + const filesJson = JSON.parse(fileData.content); + const receivedFiles = filesJson.receivedFiles; + + const notificationsDiv = document.getElementById('notifications'); + const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath')); + + receivedFiles.forEach(filePath => { + // Check if the button for this file path already exists + if (!existingButtons.includes(filePath)) { + const button = document.createElement('button'); + button.setAttribute('data-filepath', filePath); // Set a custom attribute to track the file path + button.name = 'notification'; + button.textContent = 'You received a file'; + button.addEventListener('click', () => handleFileReceivedButtonPressed(filePath, button)); + notificationsDiv.appendChild(button); + } + }); + } catch (error) { + console.error('Error loading received files:', error); + } + } + + async function handleFileReceivedButtonPressed(filePath, button) { + console.log('Notification button clicked!'); + + // Open file in file explorer + await window.electronAPI.showFileInExplorer(filePath) + .then(() => console.log('File explorer opened')) + .catch(error => console.error('Error opening file explorer:', error)); + + // Remove the button + button.remove(); + + // Call to remove the path from the JSON file + await window.electronAPI.removePathFromReceivedFiles(filePath) + .then(() => console.log('Path removed from received files')) + .catch(error => console.error('Error removing path:', error)); + } + checkDirBackupFileExists() .then(() => console.log('verificare backupDir facuta')); @@ -134,7 +182,7 @@ document.addEventListener('DOMContentLoaded', async function () { .then(() => console.log('Alert window opened')) .catch(error => console.error('Error showing alert:', error))); - const button = document.getElementById('backup_alert'); + const button = document.getElementById('share_alert'); button.remove(); } diff --git a/UC/backend/src/db/backup_schemes.json b/UC/backend/src/db/backup_schemes.json index 97eca47..0bbe8e8 100644 --- a/UC/backend/src/db/backup_schemes.json +++ b/UC/backend/src/db/backup_schemes.json @@ -1,6 +1,6 @@ { "7c0ef9d5-23ed-47a6-bfb4-fdcfce436904": { - "ip": "192.168.0.253", + "ip": "192.168.0.195", "directoryStructure": "{\"backup_dir\":{\"files\":[],\"fisiere\":{\"files\":[\"New Microsoft Excel Worksheet.xlsx\",\"New Microsoft Word Document.docx\"]}}}", "totalSize": 19363 }, diff --git a/User/jobs/external_endpoints.js b/User/jobs/external_endpoints.js index 58e1126..73d3dc4 100644 --- a/User/jobs/external_endpoints.js +++ b/User/jobs/external_endpoints.js @@ -93,24 +93,35 @@ app.post('/file_path', async (req, res) => { async function addFilePathToJson(filePath) { const jsonFilePath = path.join(__dirname, '..', 'filesReceived.json'); + let data = { receivedFiles: [] }; try { - let data = { receivedFiles: [] }; - if (await fsExtra.pathExists(jsonFilePath)) { + // Check if the JSON file exists + const fileExists = await fsExtra.pathExists(jsonFilePath); + + if (fileExists) { await lockFile(jsonFilePath); + await decryptFileInPlace(jsonFilePath); data = await fsExtra.readJson(jsonFilePath); - }else{ + } else { + await fsExtra.writeJson(jsonFilePath, data, { spaces: 2 }); await lockFile(jsonFilePath); } - data.receivedFiles.push(filePath); + if (data.receivedFiles.findIndex(existingFilePath => existingFilePath === filePath) === -1) { + data.receivedFiles.push(filePath); + } + // Write the updated data back to the file await fsExtra.writeJson(jsonFilePath, data, { spaces: 2 }); + // Unlock the file after updating await unlockFile(jsonFilePath); + await encryptFileInPlace(jsonFilePath); console.log('File path added successfully.'); } catch (error) { console.error('Error updating JSON file:', error); - throw error; // Rethrow the error for further handling if necessary + await encryptFileInPlace(jsonFilePath); + await unlockFile(jsonFilePath); } } @@ -119,18 +130,16 @@ app.use('/share_file', express.raw({ limit: '50mb' })); -async function decryptAndGetShareDir(filePath) { +async function getShareDir(filePath) { try { await lockFile(filePath); - await decryptFileInPlace(filePath); const fileContent = await fs.promises.readFile(filePath, 'utf8'); const jsonData = JSON.parse(fileContent); - const serverIP = jsonData.path; + const path = jsonData.path; - await encryptFileInPlace(filePath) await unlockFile(filePath); - return serverIP; + return path; } catch (error) { console.error('An error occurred:', error); return null; @@ -146,18 +155,19 @@ app.post('/share_file', async (req, res) => { // You might want to validate the metadata here if (!idUser || !nameOfFile || !sizeOfFile) { - return res.status(httpStatus.BAD_REQUEST).send('Missing metadata headers'); + return res.status(httpStatus.BAD_REQUEST).json({message: 'Missing metadata headers'}); } // Construct the file path using the metadata - const shareDirPath = await decryptAndGetShareDir(path.join(__dirname, '..', 'shareDir.json')); + const shareDirPath = await getShareDir(path.join(__dirname, '..', 'dirShare.json')); const baseDir = path.join(shareDirPath, idUser); fsExtra.ensureDirSync(baseDir); - const filePath = path.join(shareDirPath, nameOfFile); + const filePath = path.join(baseDir, nameOfFile); try { fs.writeFileSync(filePath, req.body); + await addFilePathToJson(filePath); res.status(httpStatus.OK).json({ message: 'Upload successful.' }); } catch (error) { console.error('Error during file upload:', error); diff --git a/User/src/main/main.js b/User/src/main/main.js index a5d2755..3e38464 100644 --- a/User/src/main/main.js +++ b/User/src/main/main.js @@ -1,4 +1,4 @@ -const {app, BrowserWindow, screen, ipcMain, dialog} = require('electron'); +const {app, BrowserWindow, screen, ipcMain, dialog, shell} = require('electron'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); @@ -6,6 +6,7 @@ const {fork} = require('child_process'); const {encryptFileInPlace, decryptFileInPlace} = require('./aes_encrypt'); const {lockFile, unlockFile} = require("../../helpers/lock_mechanism"); +const exec = require("nodemon/lib/config/exec"); const isMac = process.platform === 'darwin'; let html_page = undefined; @@ -31,32 +32,11 @@ const createInitialKeys = () => { console.log(`IV saved to ${ivPath}`); } -const deleteMainComponentsAtErrorStart = () => { - 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 checkForServerConnection = async () => { const pathToIpConfig = path.join(__dirname, '..', '..', 'ipConfig.json'); try { + console.log('Checking for server connection'); await fs.promises.access(pathToIpConfig); await lockFile(pathToIpConfig); @@ -71,10 +51,35 @@ const checkForServerConnection = async () => { return response.ok; } catch (error) { console.error("Error:", error); + try{ + fs.unlinkSync(pathToIpConfig); + } + catch{ + + } return false; } }; +async function runStartupChecks() { + 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) { + console.error("Startup error detected:", err); + + // Run the npm clean script + await exec('npm run clean', { cwd: path.join(__dirname, '..', '..') }, (error, stdout, stderr) => { + if (error) { + console.error('Error occurred while running npm run clean:', stderr); + return; + } + console.log('npm run clean output:', stdout); + createInitialKeys(); + }); + } +} + const createMainWindow = (async (title, width, height) => { mainWindow = new BrowserWindow({ title: title, @@ -87,14 +92,7 @@ const createMainWindow = (async (title, width, height) => { } }); - 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) { - createInitialKeys(); - deleteMainComponentsAtErrorStart(); - } - + await runStartupChecks(); html_page = await checkForServerConnection() ? 'login.html' : 'ip_submit.html'; //mainWindow.setMenu(null); @@ -336,7 +334,7 @@ ipcMain.handle('start-main-processes', async (event, args) => { }); } - if (externalEndpointsProcess) { + if (!externalEndpointsProcess) { externalEndpointsProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'external_endpoints.js'), args, { silent: false }); externalEndpointsProcess.on('exit', () => { externalEndpointsProcess = null; @@ -385,3 +383,40 @@ ipcMain.handle('decrypt-backup-files', async(event, destPath) => { }); } }) + +// Handle showing a file in the system file explorer +ipcMain.handle('show-file-in-explorer', async (event, filePath) => { + try { + // Ensure the file exists before attempting to show it + await fs.promises.access(filePath, fs.constants.F_OK); + shell.showItemInFolder(filePath); // Opens the file explorer and highlights the file + return true; + } catch (error) { + console.error('File does not exist:', error); + return false + } +}); + +// Handle removing a path from 'filesReceived.json' +ipcMain.handle('remove-path-from-received-files', async (event, filePath) => { + try { + const jsonFilePath = path.join(__dirname, '..', '..', 'filesReceived.json'); + await lockFile(jsonFilePath); + await decryptFileInPlace(jsonFilePath); + const data = await fs.promises.readFile(jsonFilePath, 'utf8'); + + const jsonData = JSON.parse(data); + + // Filter out the specified file path + jsonData.receivedFiles = jsonData.receivedFiles.filter(file => file !== filePath); + + await fs.promises.writeFile(jsonFilePath, JSON.stringify(jsonData, null, 2), 'utf8'); + await encryptFileInPlace(jsonFilePath); + await unlockFile(jsonFilePath); + + return true; + } catch (error) { + console.error('Error updating filesReceived.json:', error); + throw new Error('Failed to update received files list.'); + } +}); diff --git a/User/src/main/preload.js b/User/src/main/preload.js index 2aec160..a1ac5ca 100644 --- a/User/src/main/preload.js +++ b/User/src/main/preload.js @@ -14,5 +14,8 @@ contextBridge.exposeInMainWorld('electronAPI', { startMainProcesses: async (args) => ipcRenderer.invoke('start-main-processes', args), killBeforeLogout: async() => ipcRenderer.invoke('kill-before-logout'), - decryptFiles: async(destPath) => ipcRenderer.invoke('decrypt-backup-files', destPath) + decryptFiles: async(destPath) => ipcRenderer.invoke('decrypt-backup-files', destPath), + + showFileInExplorer: (filePath) => ipcRenderer.invoke('show-file-in-explorer', filePath), + removePathFromReceivedFiles: (filePath) => ipcRenderer.invoke('remove-path-from-received-files', filePath) }); \ No newline at end of file diff --git a/User/src/renderer/js/main_menu.js b/User/src/renderer/js/main_menu.js index bc84454..737a480 100644 --- a/User/src/renderer/js/main_menu.js +++ b/User/src/renderer/js/main_menu.js @@ -1,68 +1,64 @@ document.addEventListener('DOMContentLoaded', async function () { await insertUsername(); + setInterval(loadReceivedFiles, 3000); // Call loadReceivedFiles every 5000 ms (5 seconds) - const backupButton = document.getElementById('backup_dir'); + const backupButton = document.getElementById('backup'); const shareButton = document.getElementById('share_dir'); - const departmentButton = document.getElementById('department_dir'); - const changeDepartmentButton = document.getElementById('change_department'); + const manageDepartmentButton = document.getElementById('manage_department'); + const manageUsersButton = document.getElementById('manage_users'); const changeInfoButton = document.getElementById('change_info'); const shareFileButton = document.getElementById('share_file'); const decryptButton = document.getElementById('decrypt'); const logoutButton = document.getElementById('logout'); - const overlay = document.getElementById('overlay'); - const ceoBackButton = document.getElementById('back_button'); - const ceoSubmitButton = document.getElementById('submit_button'); + async function loadReceivedFiles() { + const checkFileReceived = await window.electronAPI.checkFileExists('filesReceived.json'); + if (!checkFileReceived) { + return; + } - let ip = ''; - await window.electronAPI.readFile('ipConfig.json') - .then(result => { - const jsonData = JSON.parse(result.content); - ip = jsonData.ip; - }) + try { + const fileData = await window.electronAPI.readFile('filesReceived.json'); + const filesJson = JSON.parse(fileData.content); + const receivedFiles = filesJson.receivedFiles; - let triggerSource = ''; + const notificationsDiv = document.getElementById('notifications'); + const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath')); - function handleOverlayOpen(buttonId) { - overlay.style.display = 'block'; - triggerSource = buttonId; // Remember the button that triggered the overlay - console.log(`${buttonId} button clicked!`); + receivedFiles.forEach(filePath => { + // Check if the button for this file path already exists + if (!existingButtons.includes(filePath)) { + const button = document.createElement('button'); + button.setAttribute('data-filepath', filePath); // Set a custom attribute to track the file path + button.name = 'notification'; + button.textContent = 'You received a file'; + button.addEventListener('click', () => handleFileReceivedButtonPressed(filePath, button)); + notificationsDiv.appendChild(button); + } + }); + } catch (error) { + console.error('Error loading received files:', error); + } } - ceoBackButton.addEventListener('click', function () { - overlay.style.display = 'none'; - }); + async function handleFileReceivedButtonPressed(filePath, button) { + console.log('Notification button clicked!'); - ceoSubmitButton.addEventListener('click', async function (event) { - event.preventDefault(); - const password = document.getElementById('ceo_password').value; + // Open file in file explorer + await window.electronAPI.showFileInExplorer(filePath) + .then(() => console.log('File explorer opened')) + .catch(error => console.error('Error opening file explorer:', error)); - await fetch(`http://${ip}/users/validate_ceo_password`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': 'uc_api', - }, - 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') { - console.log('astept decryptarea') - fadeOut('decrypting_backup.html'); - } - }) + // Remove the button + button.remove(); + + // Call to remove the path from the JSON file + await window.electronAPI.removePathFromReceivedFiles(filePath) + .then(() => console.log('Path removed from received files')) + .catch(error => console.error('Error removing path:', error)); + } - overlay.style.display = 'none'; - triggerSource = ''; - }); checkDirBackupFileExists() .then(() => console.log('verificare backupDir facuta')); @@ -70,9 +66,6 @@ document.addEventListener('DOMContentLoaded', async function () { checkShareDirFileExists() .then(() => console.log('verificare ShareDir facuta')); - checkDepartmentDirFileExists() - .then(() => {console.log('verificare departmentDir facuta')}) - backupButton.addEventListener('click', function () { console.log('Set backup directory button clicked!'); @@ -87,20 +80,14 @@ document.addEventListener('DOMContentLoaded', async function () { console.log('Set backup directory button clicked!'); window.electronAPI.openJsonDirConfigDialog('dirShare.json') - .then(() => console.log('Share directory set')) + .then(() => console.log('Back-up directory set')) .catch(async error => await window.electronAPI.showAlert(error.message) .then(() => console.log('Alert window opened')) .catch(error => console.error('Error showing alert:', error))); }); - departmentButton.addEventListener('click', function () { - console.log('Set backup directory button clicked!'); - - window.electronAPI.openJsonDirConfigDialog('dirDepartment.json') - .then(() => console.log('Department directory set')) - .catch(async error => await window.electronAPI.showAlert(error.message) - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error))); + manageUsersButton.addEventListener('click', async function(){ + fadeOut('manage_users.html'); }); changeInfoButton.addEventListener('click', function () { @@ -108,12 +95,13 @@ document.addEventListener('DOMContentLoaded', async function () { fadeOut('profile.html'); }); - changeDepartmentButton.addEventListener('click', function () { - handleOverlayOpen('change_department'); + decryptButton.addEventListener('click', function () { + fadeOut('decrypting_backup.html'); }); - decryptButton.addEventListener('click', function () { - handleOverlayOpen('decrypt'); + changeInfoButton.addEventListener('click', function () { + console.log('Change your info button clicked!'); + fadeOut('profile.html'); }); shareFileButton.addEventListener('click', function () { @@ -121,6 +109,10 @@ document.addEventListener('DOMContentLoaded', async function () { fadeOut('share_file.html'); }); + manageDepartmentButton.addEventListener('click', function() { + fadeOut('manage_departments.html'); + }) + logoutButton.addEventListener('click', async function () { console.log('Logout button clicked!'); await window.electronAPI.killBeforeLogout(); @@ -128,6 +120,9 @@ document.addEventListener('DOMContentLoaded', async function () { fadeOut('login.html'); }); + decryptButton.addEventListener('click', async function (){ + + }); async function checkDirBackupFileExists() { try { // Make an IPC call to check file existence @@ -154,7 +149,7 @@ document.addEventListener('DOMContentLoaded', async function () { if (!fileExists) { const notificationsDiv = document.getElementById('notifications'); const button = document.createElement('button'); - button.id = 'share_dir_alert'; + button.id = 'share_file_alert'; button.name = 'alert'; button.textContent = 'Set your share directory!'; button.addEventListener('click', handleShareButtonPressed); @@ -165,24 +160,6 @@ document.addEventListener('DOMContentLoaded', async function () { } } - async function checkDepartmentDirFileExists() { - try { - const fileExists = await window.electronAPI.checkFileExists('dirDepartment.json'); - - if (!fileExists) { - const notificationsDiv = document.getElementById('notifications'); - const button = document.createElement('button'); - button.id = 'department_alert'; - button.name = 'alert'; - button.textContent = 'Set your department directory!'; - button.addEventListener('click', handleDepartmentButtonPressed); - notificationsDiv.appendChild(button); - } - } catch (error) { - console.error('Error checking file existence:', error); - } - } - async function handleBackupButtonPressed() { console.log('Button clicked!'); @@ -205,20 +182,7 @@ document.addEventListener('DOMContentLoaded', async function () { .then(() => console.log('Alert window opened')) .catch(error => console.error('Error showing alert:', error))); - const button = document.getElementById('share_dir_alert'); - button.remove(); - } - - async function handleDepartmentButtonPressed() { - console.log('Button clicked!'); - - await window.electronAPI.openJsonDirConfigDialog('dirDepartment.json') - .then(() => console.log('Department directory set')) - .catch(async error => await window.electronAPI.showAlert(error.message) - .then(() => console.log('Alert window opened')) - .catch(error => console.error('Error showing alert:', error))); - - const button = document.getElementById('department_alert'); + const button = document.getElementById('share_alert'); button.remove(); }