diff --git a/.gitignore b/.gitignore index 126023e..e2bed4b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ node_modules .env encrypted/ !example/encrypted/ -decrypted/ \ No newline at end of file +decrypted/ +test/ \ No newline at end of file diff --git a/cli/helpers.js b/cli/helpers.js index d283a29..d21b781 100644 --- a/cli/helpers.js +++ b/cli/helpers.js @@ -270,16 +270,41 @@ function genFile(data, outputFilePath, templateFilePath) { } exports.genFile = genFile; +/** + * @param {string} path + * @param {string} fullRootDirectory + * @param {string} outputDirectory + * @returns {string} + */ +function getFullOutputPath(path, fullRootDirectory, outputDirectory) { + const relativePath = pathModule.relative(fullRootDirectory, path); + return outputDirectory + "/" + relativePath; +} +exports.getFullOutputPath = getFullOutputPath; + +/** + * @param {string} inputFilePath + * @param {string} outputFilePath + */ +function copyFile(inputFilePath, outputFilePath) { + // create output directory if it does not exist + createDirectoryStructureForFile(outputFilePath); + + try { + fs.copyFileSync(inputFilePath, outputFilePath, fs.constants.COPYFILE_FICLONE); + } catch (e) { + console.error(e); + exitWithError(`could not write file at path "${filePath}"`); + } +} + /** * @param {string} filePath * @param {string} contents */ function writeFile(filePath, contents) { // create output directory if it does not exist - const dirname = pathModule.dirname(filePath); - if (!fs.existsSync(dirname)) { - fs.mkdirSync(dirname, { recursive: true }); - } + createDirectoryStructureForFile(filePath); try { fs.writeFileSync(filePath, contents); @@ -290,6 +315,16 @@ function writeFile(filePath, contents) { } exports.writeFile = writeFile; +/** + * @param {string} filePath + */ +function createDirectoryStructureForFile(filePath) { + const dirname = pathModule.dirname(filePath); + if (!fs.existsSync(dirname)) { + fs.mkdirSync(dirname, { recursive: true }); + } +} + /** * @param {string} templatePathParameter * @returns {boolean} @@ -302,10 +337,11 @@ exports.isCustomPasswordTemplateDefault = isCustomPasswordTemplateDefault; /** * @param {string} path + * @param {string} outputDirectory * @param {string} rootDirectory * @param {(fullPath: string, rootDirectoryFromArgument: string) => void} callback */ -function recursivelyApplyCallbackToFiles(callback, path, rootDirectory = "") { +function recursivelyApplyCallbackToHtmlFiles(callback, path, outputDirectory, rootDirectory = "") { const fullPath = pathModule.resolve(path); const fullRootDirectory = rootDirectory || pathModule.dirname(fullPath); @@ -313,14 +349,22 @@ function recursivelyApplyCallbackToFiles(callback, path, rootDirectory = "") { fs.readdirSync(fullPath).forEach((filePath) => { const fullFilePath = `${fullPath}/${filePath}`; - recursivelyApplyCallbackToFiles(callback, fullFilePath, fullRootDirectory); + recursivelyApplyCallbackToHtmlFiles(callback, fullFilePath, outputDirectory, fullRootDirectory); }); return; } - callback(fullPath, fullRootDirectory); + // apply the callback if it's an HTML file + if (fullPath.endsWith(".html")) { + callback(fullPath, fullRootDirectory); + } + // else just copy the file as is + else { + const fullOutputPath = getFullOutputPath(fullPath, fullRootDirectory, outputDirectory); + copyFile(fullPath, fullOutputPath); + } } -exports.recursivelyApplyCallbackToFiles = recursivelyApplyCallbackToFiles; +exports.recursivelyApplyCallbackToHtmlFiles = recursivelyApplyCallbackToHtmlFiles; function parseCommandLineArguments() { return ( diff --git a/cli/index.js b/cli/index.js index afb96e0..9140637 100755 --- a/cli/index.js +++ b/cli/index.js @@ -30,10 +30,11 @@ const { getValidatedSalt, isOptionSetByUser, parseCommandLineArguments, - recursivelyApplyCallbackToFiles, + recursivelyApplyCallbackToHtmlFiles, validatePassword, writeConfig, writeFile, + getFullOutputPath, } = require("./helpers.js"); // parse arguments @@ -106,9 +107,13 @@ async function runStatiCrypt() { const outputDirectory = isOutputDirectoryDefault ? "decrypted" : namedArgs.directory; positionalArguments.forEach((path) => { - recursivelyApplyCallbackToFiles((fullPath, fullRootDirectory) => { - decodeAndGenerateFile(fullPath, fullRootDirectory, hashedPassword, outputDirectory); - }, path); + recursivelyApplyCallbackToHtmlFiles( + (fullPath, fullRootDirectory) => { + decodeAndGenerateFile(fullPath, fullRootDirectory, hashedPassword, outputDirectory); + }, + path, + namedArgs.directory + ); }); return; @@ -139,21 +144,25 @@ async function runStatiCrypt() { // encode all the files positionalArguments.forEach((path) => { - recursivelyApplyCallbackToFiles((fullPath, fullRootDirectory) => { - encodeAndGenerateFile( - fullPath, - fullRootDirectory, - hashedPassword, - salt, - baseTemplateData, - isRememberEnabled, - namedArgs - ); - }, path); + recursivelyApplyCallbackToHtmlFiles( + (fullPath, fullRootDirectory) => { + encodeAndGenerateFile( + fullPath, + fullRootDirectory, + hashedPassword, + salt, + baseTemplateData, + isRememberEnabled, + namedArgs + ); + }, + path, + namedArgs.directory + ); }); } -async function decodeAndGenerateFile(path, rootDirectoryFromArguments, hashedPassword, outputDirectory) { +async function decodeAndGenerateFile(path, fullRootDirectory, hashedPassword, outputDirectory) { // get the file content const encryptedFileContent = getFileContent(path); @@ -172,8 +181,7 @@ async function decodeAndGenerateFile(path, rootDirectoryFromArguments, hashedPas return console.log(`ERROR: could not decrypt ${path}`); } - const relativePath = pathModule.relative(rootDirectoryFromArguments, path); - const outputFilepath = outputDirectory + "/" + relativePath; + const outputFilepath = getFullOutputPath(path, fullRootDirectory, outputDirectory); writeFile(outputFilepath, decoded); } diff --git a/example/encrypted/example.html b/example/encrypted/example.html index ae97cea..90e430a 100644 --- a/example/encrypted/example.html +++ b/example/encrypted/example.html @@ -768,7 +768,7 @@ exports.init = init; })()); const templateError = "Bad password!", isRememberEnabled = true, - staticryptConfig = {"staticryptEncryptedMsgUniqueVariableName":"2271533ff6ba1c6223131c45fe772d77252bb175b03931aaabb9a4be7450f21edd6e55ab868304a493ffb7b5cb4d42ea21c0572063343d472699afd770cb115b6934a767bb7167c6c2737ca06671349e8ebf30bdd24f21f864c522197de1f223399a46c83694428ec32733f9c908697f240c597bea92679e607fe7c1021b2b5795eaf87dc65d981585d6b280ed953a3d744614230c709e09be866f6dfbecc169a31425efed49fc9dd6372b6a3148d9a9612dd3e9a44be08199c89a948a8609b7","isRememberEnabled":true,"rememberDurationInDays":0,"staticryptSaltUniqueVariableName":"b93bbaf35459951c47721d1f3eaeb5b9"}; + staticryptConfig = {"staticryptEncryptedMsgUniqueVariableName":"da67de28fb1fec9f04aaf615aa0e80a9675a43473e21b51a1dee72cb6153728dde06e9c242c6de08ab4608d18e73c9f922466a4695fe60e8f684f7d5d7b54149d7749bc2e626e39844d6757289f17696ea7992d1c87b49f76903c57d6506bb5aee0f0cdf4183bb20f71ad0f719c5a3ee338a486c70a1d433c00fd4384c2ec65471c436dc4cf0c4ba13a2189db1ee335f113652439c1feb2c02bf237ddada4ae46bd404f3f8417cc6b27d2e7960024afe2323edb19e8f38c699b9f4ce0db36d37","isRememberEnabled":true,"rememberDurationInDays":0,"staticryptSaltUniqueVariableName":"b93bbaf35459951c47721d1f3eaeb5b9"}; // you can edit these values to customize some of the behavior of StatiCrypt const templateConfig = { diff --git a/package.json b/package.json index 47191ca..acfe243 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "staticrypt", - "version": "3.3.1", - "description": "Based on the [crypto-js](https://github.com/brix/crypto-js) library, StatiCrypt uses AES-256 to encrypt your input with your long password and put it in a HTML file with a password prompt that can decrypted in-browser (client side).", + "version": "3.3.2", + "description": "Baed on the [crypto-js](https://github.com/brix/crypto-js) library, StatiCrypt uses AES-256 to encrypt your input with your long password and put it in a HTML file with a password prompt that can decrypted in-browser (client side).", "main": "index.js", "files": [ "/cli",