diff --git a/README.md b/README.md index 0e1682e..5463287 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ You can then run it with `npx staticrypt ...`. You can also install globally wit ```bash staticrypt test.html -p MY_LONG_PASSWORD + +# or do not include the password if you want to be prompted for it: +staticrypt test.html ``` **Encrypt a file with the password in an environment variable:** set your long password in the `STATICRYPT_PASSWORD` environment variable ([`.env` files](https://www.npmjs.com/package/dotenv#usage) are supported): @@ -39,20 +42,23 @@ staticrypt test.html -p MY_LONG_PASSWORD staticrypt test.html ``` -**Encrypt a file and get a shareable link containing the hashed password** - you can include your file URL or leave blank: - -```bash -# you can also pass '--share' without specifying the URL to get the `#staticrypt_pwd=...` -staticrypt test.html -p MY_LONG_PASSWORD --share https://example.com/test_encrypted.html -# => https://example.com/test_encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f -``` - **Encrypt multiple files at once** and put them in a `encrypted/` directory: ```bash # this will encrypt test_A.html, test_B.html and all files in the test/ directory staticrypt test_A.html test_B.html test/* -p MY_LONG_PASSWORD # => encrypted files are in encrypted/test_A.html, encrypted/test_B.html, encrypted/test/... + +# you can also use the -r flag to recursively encrypt all files in a directory +staticrypt dir_to_encrypt -p MY_LONG_PASSWORD -r +``` + +**Encrypt a file and get a shareable link containing the hashed password** - you can include your file URL or leave blank: + +```bash +# you can also pass '--share' without specifying the URL to get the `#staticrypt_pwd=...` +staticrypt test.html -p MY_LONG_PASSWORD --share https://example.com/test_encrypted.html +# => https://example.com/test_encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f ``` **Pin the salt to use staticrypt in your CI in a build step** - if you want want the "Remember-me" or share features to work accross multiple pages or multiple successive deployment, the salt needs to stay the same ([see why](https://github.com/robinmoisson/staticrypt#why-does-staticrypt-create-a-config-file)). If you run StatiCrypt in a CI step, you can pin the salt in two ways: @@ -84,6 +90,8 @@ The password argument is optional if `STATICRYPT_PASSWORD` is set in the environ empty to be prompted for it. If STATICRYPT_PASSWORD is set in the env, we'll use that instead. [string] [default: null] + -r, --recursive Whether to recursively encrypt the input + directory. [boolean] [default: false] --remember Expiration in days of the "Remember me" checkbox that will save the (salted + hashed) password in localStorage when entered by the diff --git a/cli/helpers.js b/cli/helpers.js index d3e684b..cc65bf5 100644 --- a/cli/helpers.js +++ b/cli/helpers.js @@ -309,6 +309,12 @@ function parseCommandLineArguments() { " is set in the env, we'll use that instead.", default: null, }) + .option("r", { + alias: "recursive", + type: "boolean", + describe: "Whether to recursively encrypt the input directory.", + default: false, + }) .option("remember", { type: "number", describe: diff --git a/cli/index.js b/cli/index.js index ca017ce..317cf15 100755 --- a/cli/index.js +++ b/cli/index.js @@ -12,6 +12,8 @@ if (nodeVersion[0] < 16) { // parse .env file into process.env require('dotenv').config(); +const fs = require("fs"); + const cryptoEngine = require("../lib/cryptoEngine.js"); const codec = require("../lib/codec.js"); const { generateRandomSalt } = cryptoEngine; @@ -98,30 +100,54 @@ async function runStatiCrypt() { const hashedPassword = await cryptoEngine.hashPassword(password, salt); - for (const positionalArgument of positionalArguments) { - const inputFilepath = positionalArgument.toString(); + positionalArguments.forEach(path => encodeAndGenerateFile( + path.toString(), + hashedPassword, + salt, + baseTemplateData, + isRememberEnabled, + namedArgs + )); +} - // get the file content - const contents = getFileContent(inputFilepath); +async function encodeAndGenerateFile(path, hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs) { + // if the path is a directory, get into it and process all files + if (fs.statSync(path).isDirectory()) { + if (!namedArgs.recursive) { + console.log("ERROR: The path '" + path + "' is a directory. Use the -r|--recursive flag to process all files in the directory."); - // encrypt input - const encryptedMsg = await encodeWithHashedPassword(contents, hashedPassword); + // just return instead of exiting the process, that way all other files can be processed + return; + } - const staticryptConfig = { - encryptedMsg, - isRememberEnabled, - rememberDurationInDays: namedArgs.remember, - salt, - }; - const templateData = { - ...baseTemplateData, - staticrypt_config: staticryptConfig, - }; + fs.readdirSync(path).forEach(filePath => { + const fullPath = `${path}/${filePath}`; - const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + inputFilepath; - - genFile(templateData, outputFilepath, namedArgs.template); + encodeAndGenerateFile(fullPath, hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs); + }); + return; } + + // get the file content + const contents = getFileContent(path); + + // encrypt input + const encryptedMsg = await encodeWithHashedPassword(contents, hashedPassword); + + const staticryptConfig = { + encryptedMsg, + isRememberEnabled, + rememberDurationInDays: namedArgs.remember, + salt, + }; + const templateData = { + ...baseTemplateData, + staticrypt_config: staticryptConfig, + }; + + const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + path; + + genFile(templateData, outputFilepath, namedArgs.template); } runStatiCrypt();