Skip to content

Instantly share code, notes, and snippets.

@cblair
Created August 21, 2024 20:06
Show Gist options
  • Save cblair/0dd50282951ec616f23c0e2d033edad8 to your computer and use it in GitHub Desktop.
Save cblair/0dd50282951ec616f23c0e2d033edad8 to your computer and use it in GitHub Desktop.
// WIP
// Objective: Create a Node.js script that encrypts text files within a specified directory using asynchronous programming. This script should encrypt the content of each text file using a basic Caesar Cipher for simplicity, then save the encrypted content to a new file in a different directory. The process should handle multiple files concurrently, support both encryption and decryption modes, and log the completion of each file operation.
// Requirements:
// Mode Selection: The script should accept a mode argument (encrypt or decrypt) as the first command-line argument to determine the operation mode.
// Directory Arguments: Accept two additional command-line arguments for the input directory (containing text files to process) and the output directory (where encrypted or decrypted files will be saved).
const { assert } = require("node:console");
const { argv } = require("node:process");
const { readdir, readFile } = require('node:fs/promises');
// Requirements:
// Asynchronous Processing: Utilize Node.js's fs.promises module for asynchronous file operations to ensure non-blocking I/O.
// Caesar Cipher Transformation: Implement a simple Caesar Cipher for text transformation. For encryption, shift each letter by a fixed number (e.g., 3 positions forward). For decryption, reverse the shift. Non-letter characters remain unchanged.
// Concurrency: Process all files found in the input directory concurrently, taking advantage of Node.js's asynchronous capabilities.
// Logging: Upon completion of processing a file, log a message indicating the file name and whether it was encrypted or decrypted.
class Encrypt {
iDir = null;
oDir = null;
iFilePaths = [];
numToShift = 3;
letterRE = new RegExp("[a-zA-Z]+");
constructor(iDir, oDir) {
this.iDir = iDir;
this.oDir = oDir;
}
async init() {
try {
this.iFilePaths = await readdir(this.iDir);
this.iFilePaths = this.iFilePaths.map(fname => `${this.iDir}${fname}`);
} catch (err) {
console.error(err);
return;
}
}
processInputFiles(mode) {
this.iFilePaths.forEach(fname => {
// We are assuming file of small enough size to load all in memory. When that changes, then readlines instead.
readFile(fname, 'utf-8')
.then(contents => {
if (mode === 'encrypt') {
this.encryptFile(fname, contents);
} else if (mode === 'decrypt') {
//
} else {
console.error("mode was not a correct value.")
}
})
.catch(err => console.error('Could not read file, error: ' + err.message));
});
}
// We're assuming file size is small enough to load all in memory for now, for simplicity.
encryptFile(fname, content) {
const encryptedContent = content.split('').map(char => {
const c = this.ceaserShiftChar(char, this.numToShift);
return c;
}).join('');
const testDecrypt = content.split('').map(char => {
const c = this.ceaserShiftChar(char, -this.numToShift);
return c;
}).join('');
}
// decryptFile(fname)
// Caesar Cipher Transformation: Implement a simple Caesar Cipher for text transformation. For encryption, shift each letter by a fixed number (e.g., 3 positions forward). For decryption, reverse the shift. Non-letter characters remain unchanged.
ceaserShiftChar(char, numOfShifts) {
const isCharLetter = this.letterRE.test();
let result = char;
if (isCharLetter) {
// a = 97, z = 122, A = 65, Z = 90
let charCode = char.charCodeAt(0)
// Process upper chars
if (charCode >= 65 && charCode <= 90) {
let newCharCode = charCode + this.numToShift;
// Overflow the end
if (newCharCode > 90) {
newCharCode = (newCharCode % 90) + 65;
}
// Underflow the begining
result = String.fromCharCode(newCharCode);
}
// Process lower chars
else if (charCode >= 97 && charCode <= 122) {
let newCharCode = charCode + this.numToShift;
// Overflow
if (newCharCode > 122) {
newCharCode = (newCharCode % 122) + 97;
}
result = String.fromCharCode(newCharCode);
}
}
return result;
}
}
// Args
const args = {};
argv.forEach((argument, index) => {
if (index === 2) {
args['mode'] = argument;
} else if(index === 3) {
args['iDir'] = argument;
} else if (index === 4) {
args['oDir'] = argument;
}
});
assert(args['mode'] !== undefined);
assert(args['iDir'] !== undefined);
assert(args['oDir'] !== undefined);
const encrypt = new Encrypt(args.iDir, args.oDir);
// Run main
(async function main() {
await encrypt.init();
encrypt.processInputFiles(args['mode']);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment