Skip to content

Commit dfeffc8

Browse files
committed
add recursive flag to handle encrypting directories (closes #165)
1 parent 5ef120b commit dfeffc8

3 files changed

Lines changed: 67 additions & 27 deletions

File tree

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ You can then run it with `npx staticrypt ...`. You can also install globally wit
3030

3131
```bash
3232
staticrypt test.html -p MY_LONG_PASSWORD
33+
34+
# or do not include the password if you want to be prompted for it:
35+
staticrypt test.html
3336
```
3437

3538
**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
3942
staticrypt test.html
4043
```
4144

42-
**Encrypt a file and get a shareable link containing the hashed password** - you can include your file URL or leave blank:
43-
44-
```bash
45-
# you can also pass '--share' without specifying the URL to get the `#staticrypt_pwd=...`
46-
staticrypt test.html -p MY_LONG_PASSWORD --share https://example.com/test_encrypted.html
47-
# => https://example.com/test_encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f
48-
```
49-
5045
**Encrypt multiple files at once** and put them in a `encrypted/` directory:
5146

5247
```bash
5348
# this will encrypt test_A.html, test_B.html and all files in the test/ directory
5449
staticrypt test_A.html test_B.html test/* -p MY_LONG_PASSWORD
5550
# => encrypted files are in encrypted/test_A.html, encrypted/test_B.html, encrypted/test/...
51+
52+
# you can also use the -r flag to recursively encrypt all files in a directory
53+
staticrypt dir_to_encrypt -p MY_LONG_PASSWORD -r
54+
```
55+
56+
**Encrypt a file and get a shareable link containing the hashed password** - you can include your file URL or leave blank:
57+
58+
```bash
59+
# you can also pass '--share' without specifying the URL to get the `#staticrypt_pwd=...`
60+
staticrypt test.html -p MY_LONG_PASSWORD --share https://example.com/test_encrypted.html
61+
# => https://example.com/test_encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f
5662
```
5763

5864
**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
8490
empty to be prompted for it. If
8591
STATICRYPT_PASSWORD is set in the env, we'll
8692
use that instead. [string] [default: null]
93+
-r, --recursive Whether to recursively encrypt the input
94+
directory. [boolean] [default: false]
8795
--remember Expiration in days of the "Remember me"
8896
checkbox that will save the (salted + hashed)
8997
password in localStorage when entered by the

cli/helpers.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ function parseCommandLineArguments() {
309309
" is set in the env, we'll use that instead.",
310310
default: null,
311311
})
312+
.option("r", {
313+
alias: "recursive",
314+
type: "boolean",
315+
describe: "Whether to recursively encrypt the input directory.",
316+
default: false,
317+
})
312318
.option("remember", {
313319
type: "number",
314320
describe:

cli/index.js

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ if (nodeVersion[0] < 16) {
1212
// parse .env file into process.env
1313
require('dotenv').config();
1414

15+
const fs = require("fs");
16+
1517
const cryptoEngine = require("../lib/cryptoEngine.js");
1618
const codec = require("../lib/codec.js");
1719
const { generateRandomSalt } = cryptoEngine;
@@ -98,30 +100,54 @@ async function runStatiCrypt() {
98100

99101
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
100102

101-
for (const positionalArgument of positionalArguments) {
102-
const inputFilepath = positionalArgument.toString();
103-
104-
// get the file content
105-
const contents = getFileContent(inputFilepath);
103+
positionalArguments.forEach(path => encodeAndGenerateFile(
104+
path.toString(),
105+
hashedPassword,
106+
salt,
107+
baseTemplateData,
108+
isRememberEnabled,
109+
namedArgs
110+
));
111+
}
106112

107-
// encrypt input
108-
const encryptedMsg = await encodeWithHashedPassword(contents, hashedPassword);
113+
async function encodeAndGenerateFile(path, hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs) {
114+
// if the path is a directory, get into it and process all files
115+
if (fs.statSync(path).isDirectory()) {
116+
if (!namedArgs.recursive) {
117+
console.log("ERROR: The path '" + path + "' is a directory. Use the -r|--recursive flag to process all files in the directory.");
109118

110-
const staticryptConfig = {
111-
encryptedMsg,
112-
isRememberEnabled,
113-
rememberDurationInDays: namedArgs.remember,
114-
salt,
115-
};
116-
const templateData = {
117-
...baseTemplateData,
118-
staticrypt_config: staticryptConfig,
119-
};
119+
// just return instead of exiting the process, that way all other files can be processed
120+
return;
121+
}
120122

121-
const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + inputFilepath;
123+
fs.readdirSync(path).forEach(filePath => {
124+
const fullPath = `${path}/${filePath}`;
122125

123-
genFile(templateData, outputFilepath, namedArgs.template);
126+
encodeAndGenerateFile(fullPath, hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs);
127+
});
128+
return;
124129
}
130+
131+
// get the file content
132+
const contents = getFileContent(path);
133+
134+
// encrypt input
135+
const encryptedMsg = await encodeWithHashedPassword(contents, hashedPassword);
136+
137+
const staticryptConfig = {
138+
encryptedMsg,
139+
isRememberEnabled,
140+
rememberDurationInDays: namedArgs.remember,
141+
salt,
142+
};
143+
const templateData = {
144+
...baseTemplateData,
145+
staticrypt_config: staticryptConfig,
146+
};
147+
148+
const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + path;
149+
150+
genFile(templateData, outputFilepath, namedArgs.template);
125151
}
126152

127153
runStatiCrypt();

0 commit comments

Comments
 (0)