From 869305a491173cd3a2cb47360ea04be5eddeef30 Mon Sep 17 00:00:00 2001 From: andrei-mihnea-cerbu Date: Fri, 19 Apr 2024 16:48:10 +0300 Subject: [PATCH] backup + decriptare toate fisiere done --- UC/backend/src/app.js | 7 +- UC/backend/src/db/backup_schemes.json | 8 +- UC/backend/src/models/dirStructureModel.js | 5 +- UC/backend/src/routes/backup_schemes.js | 8 +- UC/backend/src/routes/users.js | 4 +- User/.idea/.name | 1 + User/backupSchemes.json | 7 + .../New Microsoft Excel Worksheet.xlsx | Bin 0 -> 8482 bytes .../to_backup/alte fis/alt fisier.txt} | 0 .../to_backup/alte fis/fisier now.txt} | 0 .../to_backup/fisier_random.txt} | 0 User/dirBackup.json | 18 ++ User/helpers/http_status.js | 36 +++ User/helpers/lock_mechanism.js | 33 +++ User/ipConfig.json | 2 +- User/iv.key | 2 +- User/jobs/backup.js | 217 ++++++++++++++++++ User/jobs/backup_endpoints.js | 79 +++++++ User/jobs/fetcher.js | 209 +++++++++++++++++ User/loginData.json | Bin 144 -> 160 bytes User/package-lock.json | 181 +++++++++++++++ User/package.json | 6 + User/secret.key | 2 +- User/src/main/aes_encrypt.js | 43 +++- User/src/main/main.js | 84 ++----- User/src/main/preload.js | 2 +- User/src/renderer/css/alert_modal.css | 8 +- User/src/renderer/css/change_department.css | 12 +- User/src/renderer/css/ip_submit.css | 12 +- User/src/renderer/css/login.css | 16 +- User/src/renderer/css/main_menu.css | 30 +-- User/src/renderer/css/profile.css | 12 +- .../css/sending_file_confirmation.css | 6 +- User/src/renderer/css/share_file.css | 38 +-- .../src/renderer/css/sign_up_confirmation.css | 2 +- User/src/renderer/css/sign_up_department.css | 14 +- User/src/renderer/css/sing_up_profile.css | 10 +- User/src/renderer/html/alert_modal.html | 18 +- User/src/renderer/html/change_department.html | 14 +- User/src/renderer/html/decrypting_files.html | 10 +- User/src/renderer/html/ip_submit.html | 14 +- User/src/renderer/html/login.html | 18 +- User/src/renderer/html/main_menu.html | 22 +- User/src/renderer/html/profile.html | 20 +- .../html/sending_file_confirmation.html | 10 +- User/src/renderer/html/share_file.html | 16 +- .../renderer/html/sign_up_confirmation.html | 8 +- .../renderer/html/sign_up_departments.html | 14 +- User/src/renderer/html/sign_up_profile.html | 20 +- User/src/renderer/js/login.js | 14 +- User/src/renderer/js/main_menu.js | 8 +- User/src/renderer/js/share_file.js | 4 +- User/src/renderer/js/sign_up_confirmation.js | 2 +- User/src/renderer/js/sign_up_profile.js | 10 +- User/usersInSystem.json | 2 + 55 files changed, 1073 insertions(+), 265 deletions(-) create mode 100644 User/.idea/.name create mode 100644 User/backupSchemes.json create mode 100644 User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/New Microsoft Excel Worksheet.xlsx rename User/{jobs/decrypt_files.js => backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/alt fisier.txt} (100%) rename User/{jobs/receiver.js => backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/fisier now.txt} (100%) rename User/{jobs/send_files.js => backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/fisier_random.txt} (100%) create mode 100644 User/dirBackup.json create mode 100644 User/helpers/http_status.js create mode 100644 User/helpers/lock_mechanism.js create mode 100644 User/jobs/backup_endpoints.js create mode 100644 User/usersInSystem.json diff --git a/UC/backend/src/app.js b/UC/backend/src/app.js index c33ac73..911ae8f 100644 --- a/UC/backend/src/app.js +++ b/UC/backend/src/app.js @@ -6,7 +6,12 @@ const app = express(); const port = process.env.PORT || 5000; app.use(cors({ - allowedHeaders: ['Authorization', 'Content-Type'] // Add 'Authorization' to the list of allowed headers + origin: '*', // Allow all origins + methods: 'GET,POST,PUT,DELETE,PATCH', // Allow all methods + allowedHeaders: '*', // Allow all headers + credentials: true, // Enable credentials + preflightContinue: false, + optionsSuccessStatus: 204 // Some legacy browsers (IE11, various SmartTVs) choke on 204 })); app.use(json()); diff --git a/UC/backend/src/db/backup_schemes.json b/UC/backend/src/db/backup_schemes.json index 9e26dfe..2cb1939 100644 --- a/UC/backend/src/db/backup_schemes.json +++ b/UC/backend/src/db/backup_schemes.json @@ -1 +1,7 @@ -{} \ No newline at end of file +{ + "4659e71f-9bb4-4902-97d8-097efa138333": { + "ip": "192.168.0.195", + "directoryStructure": "{\"to_backup\":{\"files\":[\"fisier_random.txt\"],\"alte fis\":{\"files\":[\"alt fisier.txt\",\"fisier now.txt\",\"New Microsoft Excel Worksheet.xlsx\"]}}}", + "totalSize": 6197 + } +} \ No newline at end of file diff --git a/UC/backend/src/models/dirStructureModel.js b/UC/backend/src/models/dirStructureModel.js index 2c2d686..08625f7 100644 --- a/UC/backend/src/models/dirStructureModel.js +++ b/UC/backend/src/models/dirStructureModel.js @@ -10,13 +10,12 @@ const dirStructureModel = Joi.object({ 'string.ip': 'The IP address "{{#value}}" is not valid.', 'any.required': 'IP address is required.' }), - dir_config: Joi.string().required().messages({ + directoryStructure: Joi.string().required().messages({ 'any.required': 'Directory configuration is required', 'string.empty': 'Directory configuration must not be empty' }), - total_space: Joi.number().positive().required().messages({ + totalSize: Joi.number().required().messages({ 'any.required': 'Total space is required', - 'number.positive': 'Total space must be a positive number', 'number.base': 'Total space must be a number' }) }); diff --git a/UC/backend/src/routes/backup_schemes.js b/UC/backend/src/routes/backup_schemes.js index 526314e..73cf8e5 100644 --- a/UC/backend/src/routes/backup_schemes.js +++ b/UC/backend/src/routes/backup_schemes.js @@ -11,6 +11,7 @@ function validateBody(req, res, next) { } if(validationSchema !== undefined){ + console.log(req.body); const {error} = validationSchema.validate(req.body); if(error){ const errorMessage = error.details.map(detail => detail.message).join(', '); @@ -22,15 +23,16 @@ function validateBody(req, res, next) { router.patch('/', validateBody, (req, res) => { const backupSchemesDB = req.app.get('backupSchemesDB'); - const { id, ip, backup_schema, size } = req.body; + const { id, ip, directoryStructure, totalSize } = req.body; let backupSchemesJson = backupSchemesDB.readFile(); backupSchemesJson[id] = { ip: ip, - backup_schema: backup_schema, - size: size + directoryStructure: directoryStructure, + totalSize: totalSize } + backupSchemesDB.writeFile(backupSchemesJson); return res.status(httpStatus.OK).json({message: 'Backup schema updated'}); }); diff --git a/UC/backend/src/routes/users.js b/UC/backend/src/routes/users.js index 9e7e617..354d7c8 100644 --- a/UC/backend/src/routes/users.js +++ b/UC/backend/src/routes/users.js @@ -74,12 +74,12 @@ router.post('/login', validateBody, (req, res) => { const hashedPassword = crypto.createHash('sha256').update(password).digest('hex'); if(usersDB.readFile().length === 0){ - return res.status(httpStatus.NOT_FOUND).json({message: 'Invalid credentials.'}); + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({message: 'Internal server error.'}); } if(usersDB.findIndexByKeyValueInArray('email', email) !== usersDB.findIndexByKeyValueInArray('password', hashedPassword)){ - return res.status(httpStatus.NOT_FOUND).json({message: 'Invalid credentials.'}); + return res.status(httpStatus.UNAUTHORIZED).json({message: 'Invalid credentials.'}); } const userIndex = usersDB.findIndexByKeyValueInArray('email', email); diff --git a/User/.idea/.name b/User/.idea/.name new file mode 100644 index 0000000..d3296ce --- /dev/null +++ b/User/.idea/.name @@ -0,0 +1 @@ +login.css \ No newline at end of file diff --git a/User/backupSchemes.json b/User/backupSchemes.json new file mode 100644 index 0000000..2cb1939 --- /dev/null +++ b/User/backupSchemes.json @@ -0,0 +1,7 @@ +{ + "4659e71f-9bb4-4902-97d8-097efa138333": { + "ip": "192.168.0.195", + "directoryStructure": "{\"to_backup\":{\"files\":[\"fisier_random.txt\"],\"alte fis\":{\"files\":[\"alt fisier.txt\",\"fisier now.txt\",\"New Microsoft Excel Worksheet.xlsx\"]}}}", + "totalSize": 6197 + } +} \ No newline at end of file diff --git a/User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/New Microsoft Excel Worksheet.xlsx b/User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/New Microsoft Excel Worksheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a12bb7fb5e1949026b4018ff0ee86642a4171af3 GIT binary patch literal 8482 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 QJPfH%t1s@q{&WyQ6i`Z&VgLXD literal 0 HcmV?d00001 diff --git a/User/jobs/decrypt_files.js b/User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/alt fisier.txt similarity index 100% rename from User/jobs/decrypt_files.js rename to User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/alt fisier.txt diff --git a/User/jobs/receiver.js b/User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/fisier now.txt similarity index 100% rename from User/jobs/receiver.js rename to User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/alte fis/fisier now.txt diff --git a/User/jobs/send_files.js b/User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/fisier_random.txt similarity index 100% rename from User/jobs/send_files.js rename to User/backup_directories/4659e71f-9bb4-4902-97d8-097efa138333/to_backup/fisier_random.txt diff --git a/User/dirBackup.json b/User/dirBackup.json new file mode 100644 index 0000000..580e37a --- /dev/null +++ b/User/dirBackup.json @@ -0,0 +1,18 @@ +{ + "path": "C:\\Users\\Andrei Cerbu\\Documents\\to_backup", + "structure": { + "to_backup": { + "files": [ + "fisier_random.txt" + ], + "alte fis": { + "files": [ + "alt fisier.txt", + "fisier now.txt", + "New Microsoft Excel Worksheet.xlsx" + ] + } + } + }, + "size": 6197 +} \ No newline at end of file diff --git a/User/helpers/http_status.js b/User/helpers/http_status.js new file mode 100644 index 0000000..b03796e --- /dev/null +++ b/User/helpers/http_status.js @@ -0,0 +1,36 @@ +const httpStatus = { + // Informational + CONTINUE: 100, + SWITCHING_PROTOCOLS: 101, + PROCESSING: 102, + + // Success + OK: 200, + CREATED: 201, + ACCEPTED: 202, + NO_CONTENT: 204, + + // Redirection + MOVED_PERMANENTLY: 301, + FOUND: 302, + SEE_OTHER: 303, + NOT_MODIFIED: 304, + TEMPORARY_REDIRECT: 307, + + // Client Error + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + FORBIDDEN: 403, + NOT_FOUND: 404, + METHOD_NOT_ALLOWED: 405, + CONFLICT: 409, + GONE: 410, + UNSUPPORTED_MEDIA_TYPE: 415, + + // Server Error + INTERNAL_SERVER_ERROR: 500, + NOT_IMPLEMENTED: 501, + SERVICE_UNAVAILABLE: 503 +}; + +module.exports = { httpStatus }; diff --git a/User/helpers/lock_mechanism.js b/User/helpers/lock_mechanism.js new file mode 100644 index 0000000..2d55fc5 --- /dev/null +++ b/User/helpers/lock_mechanism.js @@ -0,0 +1,33 @@ +const lockfile = require('proper-lockfile'); + +async function lockFile(filePath) { + try { + await lockfile.lock(filePath, { + realpath: false, + retries: { + retries: 10, // Number of retries + factor: 2, // The exponential factor + minTimeout: 1000, // The number of milliseconds before starting the first retry + maxTimeout: 5000, // The maximum number of milliseconds between two retries + randomize: true, // Randomizes the timeouts by multiplying with a factor between 1 to 2 + } + }); + console.log(`File locked: ${filePath}`); + } catch (error) { + console.error(`Error locking file ${filePath}: ${error.message}`); + throw error; // Propagate the error if unable to lock after retries + } +} + +async function unlockFile(filePath) { + try { + await lockfile.unlock(filePath); + console.log(`File unlocked: ${filePath}`); + } catch (error) { + console.error(`Error unlocking file ${filePath}: ${error.message}`); + // Decide whether to throw the error or not, based on your error handling strategy + throw error; + } +} + +module.exports = {lockFile, unlockFile} \ No newline at end of file diff --git a/User/ipConfig.json b/User/ipConfig.json index 81d3eb7..51f378a 100644 --- a/User/ipConfig.json +++ b/User/ipConfig.json @@ -1 +1 @@ -ԗ۰s_(kK:Fn]C$ \ No newline at end of file +);'F w-`e/dK \ No newline at end of file diff --git a/User/iv.key b/User/iv.key index dbf14ed..0d7c548 100644 --- a/User/iv.key +++ b/User/iv.key @@ -1 +1 @@ -李a%l:I \ No newline at end of file +i60@SLi \ No newline at end of file diff --git a/User/jobs/backup.js b/User/jobs/backup.js index e69de29..cc342c3 100644 --- a/User/jobs/backup.js +++ b/User/jobs/backup.js @@ -0,0 +1,217 @@ +const fs = require('fs').promises; // Ensure you use the promise-based API +const path = require('path'); +const { decryptFileInPlace, encryptFileInPlace, encryptFileWithKey, decryptFileWithKey} = require("../src/main/aes_encrypt"); +const {lockFile, unlockFile} = require("../helpers/lock_mechanism"); + +function extractFilePaths(directoryStructure) { + let paths = []; + const traverse = (dir, currentPath) => { + Object.keys(dir).forEach(key => { + if (key === 'files') { + dir[key].forEach(file => paths.push(path.join(currentPath, file))); + } else { + traverse(dir[key], path.join(currentPath, key)); + } + }); + }; + traverse(directoryStructure, ''); + return paths; +} + +async function fetchFiles(ip, filePaths) { + let results = {}; + + for (const filePath of filePaths) { + const url = `http://${ip}:3000/file_path`; + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ filePath }) + }); + + if (!response.ok) throw new Error(`HTTP status ${response.status}`); + + const arrayBuffer = await response.arrayBuffer(); // Fetch the response as an ArrayBuffer + results[filePath] = Buffer.from(arrayBuffer); + } catch (error) { + console.error(`Error fetching ${filePath}:`, error); + results[filePath] = null; + } + } + + return results; +} + +async function removeDirectory(directoryPath) { + try { + // Check if the directory exists + const stats = await fs.stat(directoryPath); + if (!stats.isDirectory()) { + console.log('The specified path is not a directory.'); + return; + } + + // Read all the contents of the directory + const files = await fs.readdir(directoryPath); + + // Loop through each file/directory and delete them + for (const file of files) { + const currentPath = path.join(directoryPath, file); + const currentStats = await fs.stat(currentPath); + + if (currentStats.isDirectory()) { + // Recursive call for directories + await removeDirectory(currentPath); + } else { + // Delete file + await fs.unlink(currentPath); + } + } + + // Finally, delete the directory itself + await fs.rmdir(directoryPath); + //console.log(`Directory removed: ${directoryPath}`); + } catch (error) { + console.error(`Error removing directory: ${error.message}`); + } +} + +async function decryptUserSystemConfig() { + const configPath = path.join(__dirname, '..', 'usersInSystem.json'); + await lockFile(configPath); + await decryptFileInPlace(configPath); +} + +async function encryptUserSystemConfig(){ + const configPath = path.join(__dirname, '..', 'usersInSystem.json'); + await unlockFile(configPath); + await encryptFileInPlace(configPath); +} + +async function processBackup() { + await decryptUserSystemConfig(); + const usersConfigPath = path.join(__dirname, '..', 'usersInSystem.json'); + const backupConfigPath = path.join(__dirname, '..', 'backupSchemes.json'); + const baseBackupDirPath = path.join(__dirname, '..', 'backup_directories'); + + try { + // Read and parse the users configuration + const usersData = await fs.readFile(usersConfigPath, 'utf8'); + const usersConfig = JSON.parse(usersData); + + // Read and parse the backup configuration + const backupData = await fs.readFile(backupConfigPath, 'utf8'); + const jsonData = JSON.parse(backupData); + + for (const key in jsonData) { + const userBackupDir = path.join(baseBackupDirPath, key); + await removeDirectory(userBackupDir); + + const node = jsonData[key]; + const directoryStructure = JSON.parse(node.directoryStructure); + const filePaths = extractFilePaths(directoryStructure); + const files = await fetchFiles(node.ip, filePaths); + + await fs.mkdir(userBackupDir, { recursive: true }); + + // Find the encryption key for the user's department + let encryptionKey = ''; + for (const dept in usersConfig) { + if (usersConfig[dept].users.includes(key)) { + encryptionKey = usersConfig[dept].key; + break; + } + } + + for (const file in files) { + if (files[file]) { + const fullPath = path.join(userBackupDir, file); + await fs.mkdir(path.dirname(fullPath), { recursive: true }); + await fs.writeFile(fullPath, files[file]); // Write the binary data + + // Encrypt the file in place after writing it + if (encryptionKey) { + await encryptFileWithKey(fullPath, encryptionKey); + } + } + } + } + } catch (error) { + console.error('Failed to read or process the JSON file:', error); + } + + await encryptUserSystemConfig(); +} + +async function getAllFilePaths(dirPath) { + let filePaths = []; + async function recurse(currentPath) { + const entries = await fs.readdir(currentPath, { withFileTypes: true }); + // Create promises for each entry and process them in parallel + const entryPromises = entries.map(async (entry) => { + const resolvedPath = path.join(currentPath, entry.name); + if (entry.isDirectory()) { + // If it's a directory, recurse into it + await recurse(resolvedPath); + } else { + // If it's a file, add it to the file paths array + filePaths.push(resolvedPath); + } + }); + // Wait for all promises to complete + await Promise.all(entryPromises); + } + await recurse(dirPath); + return filePaths; +} + +async function decryptUserFilesToDirectory(destinationDir) { + await decryptUserSystemConfig(); // Ensure user config is decrypted + const usersConfigPath = path.join(__dirname, '..', 'usersInSystem.json'); + const usersConfig = JSON.parse(await fs.readFile(usersConfigPath, 'utf8')); + const sourceDir = path.join(__dirname, '..', 'backup_directories'); + + try { + for (const department in usersConfig) { + const { key, users } = usersConfig[department]; + for (const userId of users) { + const userDir = path.join(sourceDir, userId); + try { + const files = await getAllFilePaths(userDir); + for (const filePath of files) { + const stats = await fs.stat(filePath); + if (stats.isFile()) { + // Extract the part of the file path after the userId + const relativePath = path.relative(userDir, filePath); + + // Construct the destination file path + const destinationFilePath = path.join(destinationDir, userId, relativePath); + await fs.mkdir(path.dirname(destinationFilePath), { recursive: true }); + + // Decrypt the file in its original location + await decryptFileWithKey(filePath, key); + + // Copy the decrypted file to the destination directory + await fs.copyFile(filePath, destinationFilePath); + console.log(`Decrypted file copied to: ${destinationFilePath}`); + + // Re-encrypt the file in its original location (optional) + await encryptFileWithKey(filePath, key); + } + } + } catch (error) { + console.error(`Error processing files for user ${userId}: ${error.message}`); + } + } + } + } catch (error) { + console.error(`Error processing decryption: ${error.message}`); + } +} + + +processBackup(); +decryptUserFilesToDirectory("C:\\Users\\Andrei Cerbu\\Documents\\decrypted"); diff --git a/User/jobs/backup_endpoints.js b/User/jobs/backup_endpoints.js new file mode 100644 index 0000000..ef20e54 --- /dev/null +++ b/User/jobs/backup_endpoints.js @@ -0,0 +1,79 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const Joi = require('joi'); +const fetch = require('node-fetch'); +const { httpStatus } = require('../helpers/http_status'); + +const app = express(); +app.use(express.json()); + +const filePathSchema = Joi.object({ + filePath: Joi.string().required() +}); + +async function getBaseDirectory() { + const filePath = path.join(__dirname, '..', 'dirBackup.json'); + try { + const data = await fs.promises.readFile(filePath, 'utf8'); + const jsonData = JSON.parse(data); + return jsonData.path; + } catch (error) { + console.error('Error reading the base directory:', error); + throw error; + } +} + +app.post('/file_path', async (req, res) => { + const { error, value } = filePathSchema.validate(req.body); + if (error) { + return res.status(httpStatus.BAD_REQUEST).json({ + message: 'Invalid input', + data: error.details + }); + } + + try { + const basePath = await getBaseDirectory(); + let { filePath } = value; + const baseDirName = path.basename(basePath); + if (filePath.startsWith(baseDirName + path.sep)) { + filePath = filePath.slice(baseDirName.length + 1); + } + const fullPath = path.resolve(basePath, filePath); + + fs.stat(fullPath, (err, stats) => { + if (err) { + if (err.code === 'ENOENT') { + return res.status(httpStatus.NOT_FOUND).json({ + message: 'File not found' + }); + } + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + message: 'Error accessing the file' + }); + } + + if (!stats.isFile()) { + return res.status(httpStatus.BAD_REQUEST).json({ + message: 'Path is not a file' + }); + } + + // Stream the file as binary data + res.writeHead(httpStatus.OK, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename="${path.basename(fullPath)}"` + }); + const fileStream = fs.createReadStream(fullPath); + fileStream.pipe(res); + }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + message: 'Error processing request' + }); + } +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); diff --git a/User/jobs/fetcher.js b/User/jobs/fetcher.js index e69de29..f390bf3 100644 --- a/User/jobs/fetcher.js +++ b/User/jobs/fetcher.js @@ -0,0 +1,209 @@ +const fs = require('fs').promises; +const path = require('path'); +const ip = require('ip'); +const {encryptFileInPlace, decryptFileInPlace} = require('../src/main/aes_encrypt'); +const {lockFile, unlockFile} = require("../helpers/lock_mechanism"); + +async function fetchBackupSchemes(serverIp) { + // Fetching backup schemes from the server + const depResponse = await fetch(`http://${serverIp}/backup_schemes`, { + method: 'GET', + headers: {'x-api-key': 'uc_api'} + }); + const backupSchemesJson = await depResponse.json(); + const backupSchemes = backupSchemesJson['data']; + + // Specify the path where the backup schemes will be saved + const destPath = path.join(__dirname, '..', 'backupSchemes.json'); + + // Write the fetched backup schemes to the specified file + try { + await lockFile(destPath); + await fs.writeFile(destPath, JSON.stringify(backupSchemes, null, 2)); // Use null, 2 for pretty formatting + await unlockFile(destPath); + console.log('Backup schemes saved successfully to', destPath); + } catch (error) { + console.error('Failed to save backup schemes:', error); + } +} + +async function fetchUsersAndDepartments(serverIp) { + try { + // Fetch departments + const depResponse = await fetch(`http://${serverIp}/users/departments`, { + method: 'GET', + headers: {'x-api-key': 'uc_api'} + }); + const departmentsJson = await depResponse.json(); + const departments = departmentsJson['data']; + + // Fetch users + const userResponse = await fetch(`http://${serverIp}/users`, { + method: 'GET', + headers: {'x-api-key': 'uc_api'} + }); + const usersJson = await userResponse.json(); + const users = usersJson['data']; + + // Combine the JSON data + const combinedData = Object.values(departments).reduce((acc, {name, key}) => { + acc[name] = { + key, + users: users.filter(user => user.department === name).map(user => user.id) + }; + return acc; + }, {}); + + // Write combined data to a file + const filePath = path.join(__dirname, '..', 'usersInSystem.json'); + await lockFile(filePath); + await fs.writeFile(filePath, JSON.stringify(combinedData, null, 2), 'utf8'); + + await encryptFileInPlace(filePath); + await unlockFile(filePath); + console.log('Data has been encrypted and saved.'); + } catch (error) { + console.error('Failed to fetch or process data:', error); + } +} + +async function decryptAndGetServerIP(filePath) { + try { + await lockFile(filePath); + await decryptFileInPlace(filePath); + + const fileContent = await fs.readFile(filePath, 'utf8'); + const jsonData = JSON.parse(fileContent); + const serverIP = jsonData.ip; + + await encryptFileInPlace(filePath) + await unlockFile(filePath); + return serverIP; + } catch (error) { + console.error('An error occurred:', error); + return null; + } +} + +async function getDirectoryStructure(dirPath) { + const baseName = path.basename(dirPath); + const entries = await fs.readdir(dirPath, {withFileTypes: true}); + const result = {}; + result[baseName] = {files: []}; + let totalSize = 0; + + for (let entry of entries) { + const entryPath = path.join(dirPath, entry.name); + if (entry.isDirectory()) { + // Recursively get structure for subdirectories + const {structure, size: subSize} = await getDirectoryStructure(entryPath); + result[baseName][entry.name] = structure[Object.keys(structure)[0]]; // Object.keys to fetch the first key name + totalSize += subSize; + } else { + // Add file name to the 'files' array and calculate total size + const stats = await fs.stat(entryPath); + result[baseName].files.push(entry.name); + totalSize += stats.size; + } + } + return {structure: result, size: totalSize}; +} + +async function createBackupScheme(serverIp, structure, size) { + let filePath = path.join(__dirname, '..', 'loginData.json'); + await lockFile(filePath); + await decryptFileInPlace(filePath); + + const userContent = await fs.readFile(filePath, 'utf8'); + const userJson = JSON.parse(userContent); + + await encryptFileInPlace(filePath) + await unlockFile(filePath); + + // Find the IP address of the machine + const machineIP = ip.address(); + + // Prepare the data to be sent + const dataToSend = { + id: userJson.id, + ip: machineIP, + directoryStructure: JSON.stringify(structure), + totalSize: size + }; + + const response = await fetch(`http://${serverIp}/backup_schemes`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': 'uc_api' + }, + body: JSON.stringify(dataToSend) + }); + + if (response.ok) { + console.log("Backup dir structure submitted.") + } else { + const data = await response.json() + console.log(data.message); + } +} + +async function watchDirectoryChanges(serverIp) { + async function readBackupConfig(filePath) { + await lockFile(filePath); + const fileContent = await fs.readFile(filePath, 'utf8'); + await unlockFile(filePath); + return JSON.parse(fileContent); + } + + async function updateBackupConfig(filePath, structure, size) { + const data = { + path: filePath, + structure: structure, + size: size + }; + await lockFile(filePath); + await fs.writeFile(path.join(__dirname, '..', 'dirBackup.json'), JSON.stringify(data, null, 2)); + await unlockFile(filePath); + } + + const configPath = path.join(__dirname, '..', 'dirBackup.json'); + const backupConfig = await readBackupConfig(configPath); + const storedStructure = backupConfig.structure; + + const {structure: currentStructure, size: currentSize} = await getDirectoryStructure(backupConfig.path); + + if (JSON.stringify(storedStructure) !== JSON.stringify(currentStructure)) { + console.log("Directory structure has changed. Updating backup..."); + await createBackupScheme(serverIp, currentStructure, currentSize); + + await updateBackupConfig(backupConfig.path, currentStructure, currentSize); + } else { + console.log("No changes detected in the directory structure."); + } +} + +process.on('SIGINT', () => { + console.log('Process terminated'); + process.exit(0); +}); + +let serverIp = null +decryptAndGetServerIP(path.join(__dirname, '..', 'ipConfig.json')).then(ip => { + serverIp = ip; +}); + +setInterval(() => { + fetchUsersAndDepartments(serverIp); +}, 5000); + +setInterval(() => { + watchDirectoryChanges(serverIp); +}, 5000); + +setInterval(() => { + fetchBackupSchemes(serverIp); +}, 5000); + + +console.log("Service running. Press CTRL+C to stop."); diff --git a/User/loginData.json b/User/loginData.json index 4b94fa687bd8865c7c28e2dd428a691874622b55..94564345e159ff33d1a1a1c7e8052d7cdc7e905f 100644 GIT binary patch literal 160 zcmV;R0AK%S_TkSitrPScwh`P0?`+%^E^?vD2o5v~V!G0)-g7HV2sMpe5$rxk-@8U_ zbW9q9VJ`51&M+#E@Sy*Yrzl13fXXeblws0AuM%X;OV;`aAne4le!!=MF)mMm6in3% z$X!Jqw2yu{7Ua~4UuHscRcsh&jmAePd`|P|d<4`d&%<3eC4p}2FbNJ3ZtA54)$MC# OH1tBM&}2k{{&QOA@=M?V literal 144 zcmV;B0B`?gKEbaKkpNEqOhpK|PO2fSo1$d~=XrEBZm0H*2 ysL}jfnhFkYs|`6Yyc>%oQ?+!D!Z-yol9sv{UtWbY1FRl&sepzQXhREA@_{sN6-W{Q diff --git a/User/package-lock.json b/User/package-lock.json index b5b9d88..1459e85 100644 --- a/User/package-lock.json +++ b/User/package-lock.json @@ -9,10 +9,16 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "body-parser": "^1.20.2", "bootstrap": "^5.3.3", + "cors": "^2.8.5", "electron": "^29.1.5", "express": "^4.19.2", + "ip": "^2.0.1", + "joi": "^17.12.3", + "node-fetch": "^3.3.2", "nodemon": "^3.1.0", + "proper-lockfile": "^4.1.2", "toastify-js": "^1.12.0" }, "devDependencies": { @@ -39,6 +45,19 @@ "global-agent": "^3.0.0" } }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -49,6 +68,24 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -447,6 +484,26 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -747,6 +804,28 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -788,6 +867,17 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1085,6 +1175,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1131,6 +1226,18 @@ "node": ">=0.12.0" } }, + "node_modules/joi": { + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -1291,6 +1398,41 @@ "node": ">= 0.6" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", @@ -1365,6 +1507,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -1455,6 +1605,16 @@ "node": ">=0.4.0" } }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1570,6 +1730,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -1742,6 +1910,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1943,6 +2116,14 @@ "node": ">=8.0.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/User/package.json b/User/package.json index 195543c..2ab3b89 100644 --- a/User/package.json +++ b/User/package.json @@ -11,10 +11,16 @@ "author": "Cerbu Andrei - Mihnea", "license": "ISC", "dependencies": { + "body-parser": "^1.20.2", "bootstrap": "^5.3.3", + "cors": "^2.8.5", "electron": "^29.1.5", "express": "^4.19.2", + "ip": "^2.0.1", + "joi": "^17.12.3", + "node-fetch": "^3.3.2", "nodemon": "^3.1.0", + "proper-lockfile": "^4.1.2", "toastify-js": "^1.12.0" }, "devDependencies": { diff --git a/User/secret.key b/User/secret.key index c209bc5..5931e61 100644 --- a/User/secret.key +++ b/User/secret.key @@ -1 +1 @@ - 4~n`'TnoC:%:x \ No newline at end of file +`]'hźV8nkAVf7K \ No newline at end of file diff --git a/User/src/main/aes_encrypt.js b/User/src/main/aes_encrypt.js index aa33b9e..aaa5abe 100644 --- a/User/src/main/aes_encrypt.js +++ b/User/src/main/aes_encrypt.js @@ -6,7 +6,7 @@ async function readKeyFromFile(filePath) { try { await fs.promises.access(filePath, fs.constants.F_OK); return fs.promises.readFile(filePath); // Use asynchronous readFile - } catch(error) { + } catch (error) { console.error('Error reading key file:', error); return null; } @@ -70,7 +70,46 @@ async function decryptFileInPlace(filePath) { }); } +function cryptForKey(content, key, decrypt = false) { + const algorithm = 'aes-256-ctr'; + const secretKey = crypto.createHash('sha256').update(String(key)).digest('base64').substr(0, 32); + let cipher; + + if (decrypt) { + cipher = crypto.createDecipheriv(algorithm, secretKey, Buffer.alloc(16, 0)); // Using a zeroed IV for CTR + } else { + cipher = crypto.createCipheriv(algorithm, secretKey, Buffer.alloc(16, 0)); + } + + return Buffer.concat([cipher.update(content), cipher.final()]); +} + +// Encrypts a file in place with a given key +async function encryptFileWithKey(filePath, key) { + try { + const fileContent = await fs.promises.readFile(filePath); + const encryptedContent = cryptForKey(fileContent, key, false); + await fs.promises.writeFile(filePath, encryptedContent); + console.log(`File encrypted successfully: ${filePath}`); + } catch (error) { + console.error(`Error encrypting file: ${error.message}`); + } +} + +async function decryptFileWithKey(filePath, key) { + try { + const fileContent = await fs.promises.readFile(filePath); + const decryptedContent = cryptForKey(fileContent, key, true); + await fs.promises.writeFile(filePath, decryptedContent); + console.log(`File decrypted successfully: ${filePath}`); + } catch (error) { + console.error(`Error decrypting file: ${error.message}`); + } +} + module.exports = { encryptFileInPlace, - decryptFileInPlace + decryptFileInPlace, + encryptFileWithKey, + decryptFileWithKey, } diff --git a/User/src/main/main.js b/User/src/main/main.js index c77857f..d7cefd9 100644 --- a/User/src/main/main.js +++ b/User/src/main/main.js @@ -1,10 +1,11 @@ -const { app, BrowserWindow, screen, ipcMain, dialog } = require('electron'); +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 {fork} = require('child_process'); const {encryptFileInPlace, decryptFileInPlace} = require('./aes_encrypt'); +const {lockFile, unlockFile} = require("../../helpers/lock_mechanism"); const isMac = process.platform === 'darwin'; let html_page = undefined; @@ -117,8 +118,8 @@ function showAlert(message) { if (alertWindow === undefined) { const title = 'Alert'; const mainScreen = screen.getPrimaryDisplay(); - const { width, height } = mainScreen.size; - createAlertWindow(title, width/4, height/4); + const {width, height} = mainScreen.size; + createAlertWindow(title, width / 4, height / 4); } alertWindow.webContents.once('dom-ready', () => { @@ -129,11 +130,11 @@ function showAlert(message) { app.whenReady().then(() => { const title = "Application"; const mainScreen = screen.getPrimaryDisplay(); - const { width, height } = mainScreen.size; + const {width, height} = mainScreen.size; createMainWindow(title, width / 1.5, height / 1.5); app.on('activate', () => { - if(BrowserWindow.getAllWindows().length === 0){ + if (BrowserWindow.getAllWindows().length === 0) { createMainWindow(title, width, height); } }); @@ -152,7 +153,7 @@ app.on('before-quit', () => { }); app.on('window-all-closed', () => { - if(!isMac){ + if (!isMac) { app.quit(); } }); @@ -160,40 +161,45 @@ app.on('window-all-closed', () => { ipcMain.handle('write-file', async (event, fileName, content) => { try { let filePath = path.join(__dirname, '..', '..', fileName); + await lockFile(filePath); await fs.promises.writeFile(filePath, content); await encryptFileInPlace(filePath); + await unlockFile(filePath) console.log(`File successfully written to ${filePath}`); - return { success: true }; + return {success: true}; } catch (error) { console.error('Failed to write file:', error); - return { success: false, error: error.message }; + return {success: false, error: error.message}; } }); ipcMain.handle('delete-file', async (event, fileName) => { try { let filePath = path.join(__dirname, '..', '..', fileName); - console.log(filePath); + await fs.promises.unlink(filePath); + console.log(`File ${filePath} successfully deleted`); - return { success: true }; + return {success: true}; } catch (error) { console.error('Failed to delete file:', error); - return { success: false, error: error.message }; + return {success: false, error: error.message}; } }); ipcMain.handle('read-file', async (event, fileName) => { try { let filePath = path.join(__dirname, '..', '..', fileName); + await lockFile(filePath); await decryptFileInPlace(filePath); const content = await fs.promises.readFile(filePath, 'utf-8'); await encryptFileInPlace(filePath); - return { success: true, content }; + await unlockFile(filePath); + return {success: true, content}; } catch (error) { console.error('Error reading file:', error); - return { success: false, error: error.message }; + return {success: false, error: error.message}; } }); @@ -229,7 +235,7 @@ ipcMain.handle('open-backup-dir-dialog', async (event) => { return true; } catch (error) { console.error('Error opening file dialog:', error); - return { error: error.message }; + return {error: error.message}; } }); @@ -253,7 +259,7 @@ ipcMain.handle('check-file-exists', async (event, fileName) => { } }); -ipcMain.handle('show-alert', async (event, message) =>{ +ipcMain.handle('show-alert', async (event, message) => { showAlert(message); }); @@ -265,10 +271,9 @@ ipcMain.on('close-alert-window', () => { }); //External processes - ipcMain.handle('start-fetcher', async (event, args) => { if (fetcherProcess === null) { - fetcherProcess = fork(path.join(__dirname, '..', '..', 'jobs', 'fetcher.js'), args, { silent: false }); + 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 @@ -276,46 +281,3 @@ ipcMain.handle('start-fetcher', async (event, args) => { } 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 d259984..42e12c8 100644 --- a/User/src/main/preload.js +++ b/User/src/main/preload.js @@ -1,4 +1,4 @@ -const { contextBridge, ipcRenderer } = require('electron'); +const {contextBridge, ipcRenderer} = require('electron'); contextBridge.exposeInMainWorld('electronAPI', { writeFile: (fileName, content) => ipcRenderer.invoke('write-file', fileName, content), diff --git a/User/src/renderer/css/alert_modal.css b/User/src/renderer/css/alert_modal.css index 7b2604c..3ee2c08 100644 --- a/User/src/renderer/css/alert_modal.css +++ b/User/src/renderer/css/alert_modal.css @@ -22,12 +22,12 @@ body, html { min-height: 100vh; } -h1{ +h1 { margin: 0; padding: 0; } -.main_component{ +.main_component { display: flex; flex-wrap: wrap; flex-direction: column; @@ -43,7 +43,7 @@ h1{ height: 80vh; } -.header{ +.header { color: #1B1A55; font-size: 0.8rem; text-align: center; @@ -61,7 +61,7 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } diff --git a/User/src/renderer/css/change_department.css b/User/src/renderer/css/change_department.css index d34a81d..bf02450 100644 --- a/User/src/renderer/css/change_department.css +++ b/User/src/renderer/css/change_department.css @@ -33,7 +33,7 @@ body, html { width: 25%; } -.department-form-title{ +.department-form-title { margin-bottom: 5vh; color: #FFFFFF; text-align: center; @@ -46,11 +46,11 @@ body, html { font-size: 5vh; } -.department-form-title hr{ +.department-form-title hr { width: 65%; } -.department-form-content{ +.department-form-content { display: flex; margin-left: 2rem; flex-direction: column; @@ -60,11 +60,11 @@ body, html { font-weight: bold; } -.department-form-content input{ +.department-form-content input { margin: 0.7rem; } -.department-form-footer{ +.department-form-footer { margin-top: 7vh; display: flex; flex-wrap: wrap; @@ -84,7 +84,7 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } diff --git a/User/src/renderer/css/ip_submit.css b/User/src/renderer/css/ip_submit.css index 1b40e46..09fbc06 100644 --- a/User/src/renderer/css/ip_submit.css +++ b/User/src/renderer/css/ip_submit.css @@ -34,23 +34,23 @@ body, html { width: 25%; } -.ip-form-title{ +.ip-form-title { margin: 0 0 5vh 0; text-align: center; } -.ip-form-title h2{ +.ip-form-title h2 { color: #FFFFFF; font-size: 5vh; margin: 0; padding: 0; } -.ip-form hr{ +.ip-form hr { width: 40%; } -.ip-form-content{ +.ip-form-content { display: flex; flex-wrap: wrap; justify-content: center; @@ -79,11 +79,11 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } -.ip-form-footer{ +.ip-form-footer { margin-top: 3vh; display: flex; flex-wrap: wrap; diff --git a/User/src/renderer/css/login.css b/User/src/renderer/css/login.css index 00530ae..2e9d6d5 100644 --- a/User/src/renderer/css/login.css +++ b/User/src/renderer/css/login.css @@ -16,7 +16,7 @@ body, html { .container { opacity: 0; - + display: flex; flex-direction: row; justify-content: space-evenly; @@ -24,7 +24,7 @@ body, html { min-height: 100vh; } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; @@ -41,23 +41,23 @@ body, html { width: 25%; } -.login-form-title{ +.login-form-title { margin: 0 0 5vh 0; text-align: center; } -.login-form-title h2{ +.login-form-title h2 { color: #FFFFFF; font-size: 5vh; margin: 0; padding: 0; } -.login-form hr{ +.login-form hr { width: 40%; } -.login-form-content{ +.login-form-content { display: flex; flex-wrap: wrap; justify-content: center; @@ -86,11 +86,11 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } -.login-form-footer{ +.login-form-footer { margin-top: 3vh; display: flex; flex-wrap: wrap; diff --git a/User/src/renderer/css/main_menu.css b/User/src/renderer/css/main_menu.css index 54b52d9..60df4ae 100644 --- a/User/src/renderer/css/main_menu.css +++ b/User/src/renderer/css/main_menu.css @@ -95,7 +95,7 @@ input { text-align: center; } -.left_block{ +.left_block { display: flex; flex-direction: column; background-color: #535C91; @@ -106,29 +106,29 @@ input { color: white; } -.left_block_top{ +.left_block_top { display: flex; flex-direction: row; justify-content: space-between; text-align: left; } -.left_block_top h1{ +.left_block_top h1 { padding: 0; margin: 0; } -.left_block_top img{ +.left_block_top img { margin: 0 3vw 0 5vw; width: 8vw; height: 8vw; } -.left_block_content{ +.left_block_content { margin: 2rem 0 2rem 0; } -.left_block_buttons{ +.left_block_buttons { display: flex; flex-direction: row; align-content: center; @@ -136,7 +136,7 @@ input { justify-content: center; } -button{ +button { margin: 0 1rem 0 1rem; width: 15vw; height: 10vh; @@ -155,17 +155,17 @@ button{ transition: background-color 0.3s ease; } -button:hover{ +button:hover { filter: brightness(85%); } -.left_block_footer{ +.left_block_footer { display: flex; align-items: center; justify-content: end; } -.right_block{ +.right_block { display: flex; flex-direction: column; background-color: #535C91; @@ -176,7 +176,7 @@ button:hover{ color: white; } -.notifications{ +.notifications { display: flex; margin: 1rem 2rem 2rem 3rem; flex-direction: column; @@ -208,7 +208,7 @@ button:hover{ background: #555; /* Updated handle color on hover */ } -button[name="logout"]{ +button[name="logout"] { margin: 0; padding: 0; width: 10vw; @@ -216,17 +216,17 @@ button[name="logout"]{ background-color: #F44336; } -button[name="alert"]{ +button[name="alert"] { margin: 0.7rem; background-color: #F44336; } -button[name="notification"]{ +button[name="notification"] { margin: 0.7rem; background-color: #23BDEE; } -button[name="menu_button"]{ +button[name="menu_button"] { margin: 0.7rem; background-color: #1B1A55; } \ No newline at end of file diff --git a/User/src/renderer/css/profile.css b/User/src/renderer/css/profile.css index 3197e2e..5bbe960 100644 --- a/User/src/renderer/css/profile.css +++ b/User/src/renderer/css/profile.css @@ -25,7 +25,7 @@ body, html { text-align: center; /* Center the text for all child elements */ } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; @@ -42,11 +42,11 @@ body, html { width: 25%; } -.profile-form-title{ +.profile-form-title { margin-bottom: 5vh; } -.profile-form hr{ +.profile-form hr { width: 40%; } @@ -58,13 +58,13 @@ body, html { font-size: 5vh; } -.profile-form-content{ +.profile-form-content { display: flex; flex-wrap: wrap; justify-content: center; } -.profile-form-footer{ +.profile-form-footer { margin-top: 7vh; display: flex; flex-direction: row; @@ -94,7 +94,7 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } diff --git a/User/src/renderer/css/sending_file_confirmation.css b/User/src/renderer/css/sending_file_confirmation.css index ea7177f..db2f969 100644 --- a/User/src/renderer/css/sending_file_confirmation.css +++ b/User/src/renderer/css/sending_file_confirmation.css @@ -25,7 +25,7 @@ body, html { text-align: center; /* Center the text for all child elements */ } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; @@ -33,7 +33,7 @@ body, html { margin-bottom: 10rem; } -img{ - width:20%; +img { + width: 20%; height: 20%; } diff --git a/User/src/renderer/css/share_file.css b/User/src/renderer/css/share_file.css index 128b495..671485b 100644 --- a/User/src/renderer/css/share_file.css +++ b/User/src/renderer/css/share_file.css @@ -25,16 +25,16 @@ body, html { text-align: center; } -h1, h2{ +h1, h2 { padding: 0; margin: 0; } -h2{ +h2 { font-size: 1rem; } -.left_block{ +.left_block { display: flex; flex-direction: column; background-color: #535C91; @@ -45,25 +45,25 @@ h2{ color: white; } -.left_block_top{ +.left_block_top { display: flex; flex-direction: row; justify-content: space-between; } -.left_block_top_left{ +.left_block_top_left { display: flex; flex-direction: column; justify-content: start; text-align: left; } -.left_block_top_left hr{ +.left_block_top_left hr { margin: 0 0 1rem 0; width: 45%; } -.left_block_top_right{ +.left_block_top_right { width: 10vw; display: flex; @@ -77,14 +77,14 @@ h2{ border-radius: 1rem; } -.left_block_content{ +.left_block_content { display: flex; justify-content: start; align-items: center; margin: 2rem 0 2rem 0; } -.left_block_buttons{ +.left_block_buttons { display: flex; flex-direction: row; align-content: center; @@ -92,7 +92,7 @@ h2{ justify-content: center; } -button{ +button { margin: 0 1rem 0 1rem; width: 10vw; height: 5vh; @@ -111,17 +111,17 @@ button{ transition: background-color 0.3s ease; } -button:hover{ +button:hover { filter: brightness(85%); } -.left_block_footer{ +.left_block_footer { display: flex; align-items: center; justify-content: end; } -.right_block{ +.right_block { display: flex; flex-direction: column; background-color: #535C91; @@ -132,7 +132,7 @@ button:hover{ color: white; } -.choose_user_form_title{ +.choose_user_form_title { display: flex; flex-wrap: wrap; flex-direction: column; @@ -140,11 +140,11 @@ button:hover{ align-content: start; } -.choose_user_form_title hr{ +.choose_user_form_title hr { width: 80%; } -.choose_user_form_content{ +.choose_user_form_content { display: flex; margin: 1rem 7rem 2rem 0.5rem; flex-direction: column; @@ -176,15 +176,15 @@ button:hover{ background: #555; /* Updated handle color on hover */ } -button[name="back"]{ +button[name="back"] { background-color: #23BDEE; } -button[name="submit"]{ +button[name="submit"] { background-color: #F44336; } -button[name="select_file"]{ +button[name="select_file"] { margin: 0; width: 8vw; background-color: #1B1A55; diff --git a/User/src/renderer/css/sign_up_confirmation.css b/User/src/renderer/css/sign_up_confirmation.css index 183c9f9..dbd61b2 100644 --- a/User/src/renderer/css/sign_up_confirmation.css +++ b/User/src/renderer/css/sign_up_confirmation.css @@ -25,7 +25,7 @@ body, html { text-align: center; /* Center the text for all child elements */ } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; diff --git a/User/src/renderer/css/sign_up_department.css b/User/src/renderer/css/sign_up_department.css index 009caab..6993c9c 100644 --- a/User/src/renderer/css/sign_up_department.css +++ b/User/src/renderer/css/sign_up_department.css @@ -25,7 +25,7 @@ body, html { text-align: center; } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; @@ -42,7 +42,7 @@ body, html { width: 25%; } -.signup-form-title{ +.signup-form-title { margin-bottom: 5vh; } @@ -54,15 +54,15 @@ body, html { font-size: 5vh; } -.signup-form hr{ +.signup-form hr { width: 65%; } -input{ +input { margin: 0 0 1rem 0; } -.signup-form-content{ +.signup-form-content { display: flex; margin: 1rem 2rem 2rem 3rem; flex-direction: column; @@ -94,7 +94,7 @@ input{ background: #555; /* Updated handle color on hover */ } -.signup-form-footer{ +.signup-form-footer { margin-top: 5vh; display: flex; flex-wrap: wrap; @@ -114,7 +114,7 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } diff --git a/User/src/renderer/css/sing_up_profile.css b/User/src/renderer/css/sing_up_profile.css index 9fda52d..f882050 100644 --- a/User/src/renderer/css/sing_up_profile.css +++ b/User/src/renderer/css/sing_up_profile.css @@ -25,7 +25,7 @@ body, html { text-align: center; } -.header{ +.header { color: #1B1A55; font-size: 4vh; text-transform: uppercase; @@ -42,7 +42,7 @@ body, html { width: 25%; } -.signup-form-title{ +.signup-form-title { margin-bottom: 5vh; } @@ -54,7 +54,7 @@ body, html { font-size: 5vh; } -.signup-form hr{ +.signup-form hr { width: 40%; } @@ -70,7 +70,7 @@ input { border-radius: 10px; } -.signup-form-footer{ +.signup-form-footer { margin-top: 3vh; display: flex; flex-wrap: wrap; @@ -90,7 +90,7 @@ button { cursor: pointer; } -button:hover{ +button:hover { filter: brightness(85%); } diff --git a/User/src/renderer/html/alert_modal.html b/User/src/renderer/html/alert_modal.html index 340c97b..34cdd4f 100644 --- a/User/src/renderer/html/alert_modal.html +++ b/User/src/renderer/html/alert_modal.html @@ -2,20 +2,20 @@ - - + + Alert Modal -
-
-
- -

-
- +
+
+
+ +

+
+
diff --git a/User/src/renderer/html/change_department.html b/User/src/renderer/html/change_department.html index d8e0564..2af2131 100644 --- a/User/src/renderer/html/change_department.html +++ b/User/src/renderer/html/change_department.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -15,7 +15,7 @@
-
+

Choose your department


@@ -24,8 +24,8 @@
diff --git a/User/src/renderer/html/decrypting_files.html b/User/src/renderer/html/decrypting_files.html index 5f80209..9af7fd1 100644 --- a/User/src/renderer/html/decrypting_files.html +++ b/User/src/renderer/html/decrypting_files.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -17,7 +17,7 @@

SENDING THE FILE!

PlEASE WAIT

- Description of GIF + Description of GIF
diff --git a/User/src/renderer/html/ip_submit.html b/User/src/renderer/html/ip_submit.html index 007ccfd..0352f05 100644 --- a/User/src/renderer/html/ip_submit.html +++ b/User/src/renderer/html/ip_submit.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -15,16 +15,16 @@
-
+

IP Config


- +
diff --git a/User/src/renderer/html/login.html b/User/src/renderer/html/login.html index 5a8f5c4..6305146 100644 --- a/User/src/renderer/html/login.html +++ b/User/src/renderer/html/login.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -19,18 +19,18 @@

DO WE KNOW

EACH OTHER?

- diff --git a/User/src/renderer/html/main_menu.html b/User/src/renderer/html/main_menu.html index d230d08..f7cb909 100644 --- a/User/src/renderer/html/main_menu.html +++ b/User/src/renderer/html/main_menu.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -15,13 +15,13 @@ -
-
+
+

CEO Authentication

- +
- - + +
@@ -33,7 +33,7 @@

Hope you have a productive day!

- +
@@ -57,7 +57,7 @@

NOTIFICATIONS


-
+
diff --git a/User/src/renderer/html/profile.html b/User/src/renderer/html/profile.html index 3840aaf..860ae39 100644 --- a/User/src/renderer/html/profile.html +++ b/User/src/renderer/html/profile.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -15,19 +15,19 @@
-
+

Profile


- - - + + +
diff --git a/User/src/renderer/html/sending_file_confirmation.html b/User/src/renderer/html/sending_file_confirmation.html index 5f80209..9af7fd1 100644 --- a/User/src/renderer/html/sending_file_confirmation.html +++ b/User/src/renderer/html/sending_file_confirmation.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -17,7 +17,7 @@

SENDING THE FILE!

PlEASE WAIT

- Description of GIF + Description of GIF
diff --git a/User/src/renderer/html/share_file.html b/User/src/renderer/html/share_file.html index 4f7fc47..f578673 100644 --- a/User/src/renderer/html/share_file.html +++ b/User/src/renderer/html/share_file.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -28,14 +28,14 @@
- +
-
+

USERS


diff --git a/User/src/renderer/html/sign_up_confirmation.html b/User/src/renderer/html/sign_up_confirmation.html index 089c38b..ac3c893 100644 --- a/User/src/renderer/html/sign_up_confirmation.html +++ b/User/src/renderer/html/sign_up_confirmation.html @@ -2,11 +2,11 @@ - - + + - - + + diff --git a/User/src/renderer/html/sign_up_departments.html b/User/src/renderer/html/sign_up_departments.html index 86bf10c..3a2b6a5 100644 --- a/User/src/renderer/html/sign_up_departments.html +++ b/User/src/renderer/html/sign_up_departments.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -20,7 +20,7 @@

ABOUT

YOUR WORK

- +
diff --git a/User/src/renderer/html/sign_up_profile.html b/User/src/renderer/html/sign_up_profile.html index 01b3448..346418f 100644 --- a/User/src/renderer/html/sign_up_profile.html +++ b/User/src/renderer/html/sign_up_profile.html @@ -2,11 +2,11 @@ - - + + - - + + @@ -19,19 +19,19 @@

LET US MEET

EACH OTHER

- \ No newline at end of file diff --git a/User/src/renderer/js/login.js b/User/src/renderer/js/login.js index 3f1b4bd..f086f95 100644 --- a/User/src/renderer/js/login.js +++ b/User/src/renderer/js/login.js @@ -3,7 +3,7 @@ document.addEventListener('DOMContentLoaded', async function () { const submitButton = document.getElementById('submit'); const signupDataExists = await window.electronAPI.checkFileExists('signupData.json'); - if(signupDataExists){ + if (signupDataExists) { await window.electronAPI.deleteFile('signupData.json'); } @@ -32,9 +32,11 @@ document.addEventListener('DOMContentLoaded', async function () { email: email, password: password }) - }).then(response => { + }).then(async response => { if (response.ok) { fadeOut('main_menu.html'); + } else { + await window.electronAPI.deleteFile('loginData.json'); } }).catch(error => { console.error(error); @@ -80,8 +82,8 @@ document.addEventListener('DOMContentLoaded', async function () { return response.json(); }).then(async data => { - console.log(data) - await window.electronAPI.writeFile('loginData.json', JSON.stringify(responseBody.message, null, 2)); + data.data.password = password + await window.electronAPI.writeFile('loginData.json', JSON.stringify(data.data, null, 2)); fadeOut('main_menu.html'); }) .catch(async error => { @@ -90,4 +92,8 @@ document.addEventListener('DOMContentLoaded', async function () { .catch(error => console.error('Error showing alert:', error)); }) }); + + function delayWithTimeout(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } }); diff --git a/User/src/renderer/js/main_menu.js b/User/src/renderer/js/main_menu.js index 6f9f80d..7d3682b 100644 --- a/User/src/renderer/js/main_menu.js +++ b/User/src/renderer/js/main_menu.js @@ -34,11 +34,11 @@ document.addEventListener('DOMContentLoaded', async function () { handleOverlayOpen('decrypt'); }); - ceoBackButton.addEventListener('click', function() { + ceoBackButton.addEventListener('click', function () { overlay.style.display = 'none'; }); - ceoSubmitButton.addEventListener('click', async function(event) { + ceoSubmitButton.addEventListener('click', async function (event) { event.preventDefault(); const password = document.getElementById('ceo_password').value; @@ -53,12 +53,12 @@ document.addEventListener('DOMContentLoaded', async function () { }) }).then(async result => { const data = await result.json(); - if(!result.ok){ + if (!result.ok) { throw new Error(data.message); } if (triggerSource === 'change_department') { fadeOut('change_department.html'); - }else if (triggerSource === 'decrypt'){ + } else if (triggerSource === 'decrypt') { fadeOut('decrypting_files.html'); } }) diff --git a/User/src/renderer/js/share_file.js b/User/src/renderer/js/share_file.js index d7eb6ef..5d8cdee 100644 --- a/User/src/renderer/js/share_file.js +++ b/User/src/renderer/js/share_file.js @@ -1,4 +1,4 @@ -document.addEventListener("DOMContentLoaded", function() { +document.addEventListener("DOMContentLoaded", function () { let pathToFile = ''; function updateFileName() { @@ -83,7 +83,7 @@ document.addEventListener("DOMContentLoaded", function() { } }); - if(selectedUserIds === []){ + if (selectedUserIds === []) { await window.electronAPI.showAlert('No user selected!') .then(() => console.log('Alert window opened')) .catch(error => console.error('Error changing content:', error)); diff --git a/User/src/renderer/js/sign_up_confirmation.js b/User/src/renderer/js/sign_up_confirmation.js index a52c0a8..b443e84 100644 --- a/User/src/renderer/js/sign_up_confirmation.js +++ b/User/src/renderer/js/sign_up_confirmation.js @@ -1,4 +1,4 @@ -document.addEventListener('DOMContentLoaded', async function() { +document.addEventListener('DOMContentLoaded', async function () { await new Promise(resolve => setTimeout(resolve, 2000)); fadeOut('login.html'); }); diff --git a/User/src/renderer/js/sign_up_profile.js b/User/src/renderer/js/sign_up_profile.js index 8e90ef2..2578b72 100644 --- a/User/src/renderer/js/sign_up_profile.js +++ b/User/src/renderer/js/sign_up_profile.js @@ -3,7 +3,7 @@ document.addEventListener('DOMContentLoaded', async function () { const continueButton = document.getElementById('continue'); const signupDataExists = await window.electronAPI.checkFileExists('signupData.json'); - if(signupDataExists){ + if (signupDataExists) { await window.electronAPI.readFile('signupData.json') .then(result => { const signupData = JSON.parse(result.content); @@ -63,9 +63,9 @@ document.addEventListener('DOMContentLoaded', async function () { 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)); - }) + 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/usersInSystem.json b/User/usersInSystem.json new file mode 100644 index 0000000..e59098a --- /dev/null +++ b/User/usersInSystem.json @@ -0,0 +1,2 @@ +sHݐ|W`݀v/Ɣ]r'=^uϼ./χPI̗ Xz+Cw E쭬02P[/ ++;8"&nB}eD-$b~JBVh C+rg&h:V*y8< {nY!y>OOdiÆ.lDY);&+\w}Bsر #=Xuٶqcudۭ qdOI \ No newline at end of file