kopia lustrzana https://github.com/robinmoisson/staticrypt
support encrypting multiple files
rodzic
5a8425387a
commit
4696a24324
|
@ -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]
|
||||
|
|
|
@ -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",
|
||||
|
|
46
cli/index.js
46
cli/index.js
|
@ -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();
|
||||
|
|
|
@ -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 = {
|
||||
|
|
44
index.html
44
index.html
|
@ -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.
|
||||
|
|
22
lib/codec.js
22
lib/codec.js
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": [
|
||||
|
|
Ładowanie…
Reference in New Issue