support encrypting multiple files

pull/177/head
robinmoisson 2023-04-19 09:47:05 +02:00
rodzic 5a8425387a
commit 4696a24324
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 9419716500078583
8 zmienionych plików z 123 dodań i 31 usunięć

Wyświetl plik

@ -47,10 +47,12 @@ staticrypt test.html -p MY_LONG_PASSWORD --share https://example.com/test_encryp
# => https://example.com/test_encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f
```
**Encrypt all html files from a directory** and put them in a `encrypted/` directory (`{}` will be replaced with each file name by the `find` command):
**Encrypt multiple files at once** and put them in a `encrypted/` directory:
```bash
find . -type f -name "*.html" -exec staticrypt {} -p MY_LONG_PASSWORD \;
# 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/...
```
**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:
@ -68,7 +70,7 @@ staticrypt test.html -p MY_LONG_PASSWORD --salt 12345678901234567890123456789012
The password argument is optional if `STATICRYPT_PASSWORD` is set in the environment or `.env` file.
Usage: staticrypt <filename> [options]
Usage: staticrypt <filename> [<filename> ...] [options]
Options:
--help Show help [boolean]

Wyświetl plik

@ -146,7 +146,7 @@ function getFileContent(filepath) {
try {
return fs.readFileSync(filepath, "utf8");
} catch (e) {
exitWithError("input file does not exist!");
exitWithError(`input file '${filepath}' does not exist!`);
}
}
exports.getFileContent = getFileContent;
@ -289,7 +289,7 @@ function isCustomPasswordTemplateDefault(templatePathParameter) {
exports.isCustomPasswordTemplateDefault = isCustomPasswordTemplateDefault;
function parseCommandLineArguments() {
return Yargs.usage("Usage: staticrypt <filename> [options]")
return Yargs.usage("Usage: staticrypt <filename> [<filename> ...] [options]")
.option("c", {
alias: "config",
type: "string",

Wyświetl plik

@ -15,7 +15,7 @@ require('dotenv').config();
const cryptoEngine = require("../lib/cryptoEngine.js");
const codec = require("../lib/codec.js");
const { generateRandomSalt } = cryptoEngine;
const { encode } = codec.init(cryptoEngine);
const { encodeWithHashedPassphrase } = codec.init(cryptoEngine);
const { parseCommandLineArguments, buildStaticryptJS, isOptionSetByUser, genFile, getFileContent,
getValidatedSalt,
getValidatedPassword, getConfig, writeConfig
@ -31,7 +31,7 @@ async function runStatiCrypt() {
const positionalArguments = namedArgs._;
// validate the number of arguments
// require at least one positional argument unless some specific flags are passed
if (!hasShareFlag && !(hasSaltFlag && !namedArgs.salt)) {
if (positionalArguments.length === 0) {
console.log("ERROR: Invalid number of arguments. Please provide an input file.\n");
@ -81,24 +81,11 @@ async function runStatiCrypt() {
writeConfig(configPath, config);
}
// get the file content
const inputFilepath = positionalArguments[0].toString();
const contents = getFileContent(inputFilepath);
// encrypt input
const encryptedMsg = await encode(contents, password, salt);
const isRememberEnabled = namedArgs.remember !== "false";
const data = {
const baseTemplateData = {
is_remember_enabled: JSON.stringify(isRememberEnabled),
js_staticrypt: buildStaticryptJS(),
staticrypt_config: {
encryptedMsg,
isRememberEnabled,
rememberDurationInDays: namedArgs.remember,
salt,
},
template_button: namedArgs.templateButton,
template_error: namedArgs.templateError,
template_instructions: namedArgs.templateInstructions,
@ -109,9 +96,32 @@ async function runStatiCrypt() {
template_color_secondary: namedArgs.templateColorSecondary,
};
const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + inputFilepath;
const hashedPassword = await cryptoEngine.hashPassphrase(password, salt);
genFile(data, outputFilepath, namedArgs.template);
for (const positionalArgument of positionalArguments) {
const inputFilepath = positionalArgument.toString();
// get the file content
const contents = getFileContent(inputFilepath);
// encrypt input
const encryptedMsg = await encodeWithHashedPassphrase(contents, hashedPassword);
const staticryptConfig = {
encryptedMsg,
isRememberEnabled,
rememberDurationInDays: namedArgs.remember,
salt,
};
const templateData = {
...baseTemplateData,
staticrypt_config: staticryptConfig,
};
const outputFilepath = namedArgs.directory.replace(/\/+$/, '') + "/" + inputFilepath;
genFile(templateData, outputFilepath, namedArgs.template);
}
}
runStatiCrypt();

Wyświetl plik

@ -488,8 +488,8 @@ function init(cryptoEngine) {
async function encode(msg, password, salt) {
const hashedPassphrase = await cryptoEngine.hashPassphrase(password, salt);
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
@ -498,6 +498,26 @@ function init(cryptoEngine) {
}
exports.encode = encode;
/**
* Encode using a password that has already been hashed. This is useful to encode multiple messages in a row, that way
* we don't need to hash the password multiple times.
*
* @param {string} msg
* @param {string} hashedPassphrase
*
* @returns {string} The encoded text
*/
async function encodeWithHashedPassphrase(msg, hashedPassphrase) {
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
return hmac + encrypted;
}
exports.encodeWithHashedPassphrase = encodeWithHashedPassphrase;
/**
* Top-level function for decoding a message.
* Includes signature check and decryption.
@ -770,7 +790,7 @@ exports.init = init;
})())
const templateError = 'Bad password!',
isRememberEnabled = true,
staticryptConfig = {"encryptedMsg":"87f21fbcd8377a4add0382f281123d5f3d7422d99eeac1e8bf287931f307ab42ed795ce671de90d2127951422f748d7f3b93e711e4e0ddf450371c741031208ae7a9c7a7cc38b7969c86dc22beb869ce9b98aa1abd29d2dd658b2e163729341fe247d79e15e172c716e4d99bc7e7b7581a648bc7f87a0639c497b299d2f2fe2b85dd43e8ac7018ef3d0028a39fb3d156ae0f4e303b575e70c4fb0079f353f0510798816b9009a4156d7803b286db1c82e55e68eb2b280be7fb20e4c01dc417f0","isRememberEnabled":true,"rememberDurationInDays":0,"salt":"b93bbaf35459951c47721d1f3eaeb5b9"};
staticryptConfig = {"encryptedMsg":"8ad22b42e255e1467bbd5369c84ae7420583384946876422f9450a5ab7fb3eaf33f5b73b1980988ef451c513871bb24582fabe01c8a5d0bde2a0580d564bf9c232cffc7fca5169005c024de005a25f479c172a65f6554405874082906b4a3be1ca7c0118728b25cd3ae915277e19f574c4f794affeffb2a1c3e923ea12fd83f5005a1c1b9606d36448082bd0f8ef70f8cc99f5205075e702b2f2b795c9150e20f2de2c6c86631c2d59ebbe2543c8ec13e450b21bbefdc2f2cb219190a0510538","isRememberEnabled":true,"rememberDurationInDays":0,"salt":"b93bbaf35459951c47721d1f3eaeb5b9"};
// you can edit these values to customize some of the behavior of StatiCrypt
const templateConfig = {

Wyświetl plik

@ -494,8 +494,8 @@ function init(cryptoEngine) {
async function encode(msg, password, salt) {
const hashedPassphrase = await cryptoEngine.hashPassphrase(password, salt);
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
@ -504,6 +504,26 @@ function init(cryptoEngine) {
}
exports.encode = encode;
/**
* Encode using a password that has already been hashed. This is useful to encode multiple messages in a row, that way
* we don't need to hash the password multiple times.
*
* @param {string} msg
* @param {string} hashedPassphrase
*
* @returns {string} The encoded text
*/
async function encodeWithHashedPassphrase(msg, hashedPassphrase) {
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
return hmac + encrypted;
}
exports.encodeWithHashedPassphrase = encodeWithHashedPassphrase;
/**
* Top-level function for decoding a message.
* Includes signature check and decryption.
@ -903,8 +923,8 @@ function init(cryptoEngine) {
async function encode(msg, password, salt) {
const hashedPassphrase = await cryptoEngine.hashPassphrase(password, salt);
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
@ -913,6 +933,26 @@ function init(cryptoEngine) {
}
exports.encode = encode;
/**
* Encode using a password that has already been hashed. This is useful to encode multiple messages in a row, that way
* we don't need to hash the password multiple times.
*
* @param {string} msg
* @param {string} hashedPassphrase
*
* @returns {string} The encoded text
*/
async function encodeWithHashedPassphrase(msg, hashedPassphrase) {
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
return hmac + encrypted;
}
exports.encodeWithHashedPassphrase = encodeWithHashedPassphrase;
/**
* Top-level function for decoding a message.
* Includes signature check and decryption.

Wyświetl plik

@ -19,8 +19,8 @@ function init(cryptoEngine) {
async function encode(msg, password, salt) {
const hashedPassphrase = await cryptoEngine.hashPassphrase(password, salt);
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
@ -29,6 +29,26 @@ function init(cryptoEngine) {
}
exports.encode = encode;
/**
* Encode using a password that has already been hashed. This is useful to encode multiple messages in a row, that way
* we don't need to hash the password multiple times.
*
* @param {string} msg
* @param {string} hashedPassphrase
*
* @returns {string} The encoded text
*/
async function encodeWithHashedPassphrase(msg, hashedPassphrase) {
const encrypted = await cryptoEngine.encrypt(msg, hashedPassphrase);
// we use the hashed password in the HMAC because this is effectively what will be used a password (so we can store
// it in localStorage safely, we don't use the clear text password)
const hmac = await cryptoEngine.signMessage(hashedPassphrase, encrypted);
return hmac + encrypted;
}
exports.encodeWithHashedPassphrase = encodeWithHashedPassphrase;
/**
* Top-level function for decoding a message.
* Includes signature check and decryption.

4
package-lock.json wygenerowano
Wyświetl plik

@ -1,12 +1,12 @@
{
"name": "staticrypt",
"version": "3.1.1",
"version": "3.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "staticrypt",
"version": "3.1.1",
"version": "3.2.0",
"license": "MIT",
"dependencies": {
"dotenv": "^16.0.3",

Wyświetl plik

@ -1,6 +1,6 @@
{
"name": "staticrypt",
"version": "3.1.1",
"version": "3.2.0",
"description": "Based on the [crypto-js](https://github.com/brix/crypto-js) library, StatiCrypt uses AES-256 to encrypt your input with your passphrase and put it in a HTML file with a password prompt that can decrypted in-browser (client side).",
"main": "index.js",
"files": [