kopia lustrzana https://github.com/robinmoisson/staticrypt
Porównaj commity
4 Commity
3ca758eb0a
...
8cf1ab5cd6
Autor | SHA1 | Data |
---|---|---|
robinmoisson | 8cf1ab5cd6 | |
robinmoisson | e3cc2acda2 | |
robinmoisson | a256971e22 | |
robinmoisson | 5d99ce92ba |
|
@ -5,3 +5,4 @@ node_modules
|
|||
.env
|
||||
encrypted/
|
||||
!example/encrypted/
|
||||
decrypted/
|
66
README.md
66
README.md
|
@ -20,19 +20,20 @@ Staticrypt is available through npm as a CLI, install with
|
|||
npm install staticrypt
|
||||
```
|
||||
|
||||
You can then run it with `npx staticrypt ...`. You can also install globally with `npm install -g staticrypt` and then just call `staticrypt ...`.
|
||||
You can then run it with `npx staticrypt ...`. You can also install globally with `npm install -g staticrypt` and then just call `staticrypt ...` from anywhere.
|
||||
|
||||
### Examples
|
||||
|
||||
> These examples will create a `.staticrypt.json` file in the current directory, see the FAQ as to why. You can prevent it by setting the `--config` flag to "false".
|
||||
> These examples will create a `.staticrypt.json` file in the current directory, see [the FAQ](#why-does-staticrypt-create-a-config-file) as to why. You can prevent it by setting the `--config` flag to "false".
|
||||
|
||||
**Encrypt a file:** encrypt `test.html` and create a `encrypted/test.html` file (use `-d my_directory` to change the output directory):
|
||||
|
||||
```bash
|
||||
staticrypt test.html -p MY_LONG_PASSWORD
|
||||
|
||||
# or do not include the password if you want to be prompted for it:
|
||||
# this will prompt you for the password, which won't stay in your terminal command history
|
||||
staticrypt test.html
|
||||
|
||||
# you can also pass the password as an argument
|
||||
staticrypt test.html -p <long-password>
|
||||
```
|
||||
|
||||
**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):
|
||||
|
@ -42,34 +43,47 @@ staticrypt test.html
|
|||
staticrypt test.html
|
||||
```
|
||||
|
||||
**Encrypt multiple files at once** and put them in a `encrypted/` directory:
|
||||
**Encrypt multiple files at once** and put them in an `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/...
|
||||
# this will encrypt test_A.html and test_B.html
|
||||
staticrypt test_A.html test_B.html
|
||||
# => encrypted files are in encrypted/test_A.html and encrypted/test_B.html
|
||||
|
||||
# you can also use the -r flag to recursively encrypt all files in a directory
|
||||
staticrypt dir_to_encrypt -p MY_LONG_PASSWORD -r
|
||||
staticrypt dir_to_encrypt -r
|
||||
# => encrypted files are in encrypted/dir_to_encrypt/...
|
||||
|
||||
# if you don't want to include the directory name in the output path, you can use dir_to_encrypt/* instead. `-r` will
|
||||
# include potential subdirectories as well
|
||||
staticrypt dir_to_encrypt/* -r
|
||||
# => encrypted files are in encrypted/...
|
||||
```
|
||||
|
||||
**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/encrypted.html
|
||||
staticrypt test.html --share https://example.com/encrypted.html
|
||||
# => https://example.com/encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f
|
||||
```
|
||||
|
||||
**Decrypt files you encrypted earlier** with StatiCrypt straight from the CLI by including the `--decrypt` flag, so you can keep only the encrypted files. The `-r|--recursive` flag and output `-d|--directory` option work the same way as when encrypting (default name for the output directory is `decrypted`):
|
||||
|
||||
```bash
|
||||
staticrypt encrypted/test.html --decrypt
|
||||
# => decrypted file is in decrypted/test.html
|
||||
```
|
||||
|
||||
**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:
|
||||
|
||||
```bash
|
||||
# either commit the .staticrypt.json config file - you can generate a random salt and
|
||||
# config file on your local machine:
|
||||
# config file on your local machine with:
|
||||
staticrypt --salt
|
||||
|
||||
# or hardcode the salt in the CI script command:
|
||||
staticrypt test.html -p MY_LONG_PASSWORD --salt 12345678901234567890123456789012
|
||||
# or hardcode the salt in the encryption command in the CI script:
|
||||
staticrypt test.html --salt 12345678901234567890123456789012
|
||||
```
|
||||
|
||||
### CLI Reference
|
||||
|
@ -83,9 +97,12 @@ The password argument is optional if `STATICRYPT_PASSWORD` is set in the environ
|
|||
--version Show version number [boolean]
|
||||
-c, --config Path to the config file. Set to "false" to
|
||||
disable.[string] [default: ".staticrypt.json"]
|
||||
-d, --directory Name of the directory where the encrypted
|
||||
files will be saved.
|
||||
[string] [default: "encrypted/"]
|
||||
-d, --directory Name of the directory where the generated
|
||||
files will be saved. If the '--decrypt' flag
|
||||
is set, default will be 'decrypted'.
|
||||
[string] [default: "encrypted"]
|
||||
--decrypt Include this flag to decrypt files instead of
|
||||
encrypt. [boolean] [default: false]
|
||||
-p, --password The password to encrypt your file with. Leave
|
||||
empty to be prompted for it. If
|
||||
STATICRYPT_PASSWORD is set in the env, we'll
|
||||
|
@ -157,6 +174,21 @@ Yes! Just copy `lib/password_template.html`, modify it to suit your style and po
|
|||
|
||||
Be careful to not break the encrypting javascript part, the variables replaced by StatiCrypt are in this format: `/*[|variable|]*/0`. Don't leave out the `0` at the end, this weird syntax is to avoid conflict with other templating engines while still being read as valid JS to parsers so we can use auto-formatting on the template files.
|
||||
|
||||
### Can I support multiple users with different passwords?
|
||||
|
||||
At the moment you can only use one passsword per page (though there is a reflection on supporting decryption with multiple different passwords in [#158](https://github.com/robinmoisson/staticrypt/issues/158)). If you want to support multiple users so you can invalidate passwords individualy, the current recommended way is the following:
|
||||
|
||||
- Make a script that will encrypt your files with different passwords and different output folders
|
||||
|
||||
```
|
||||
staticrypt test.html -p <john-password> -d john
|
||||
...
|
||||
```
|
||||
|
||||
- send each user the link to their folder with their password: `https://example.com/john/test.html`
|
||||
|
||||
In a way, the username input becomes the folder in the `https://example.com/<username>` URL, and the password input is the HTML form. You can then invalidate a single password by changing it in your script and running it again.
|
||||
|
||||
### Why doesn't StatiCrypt work in HTTP?
|
||||
|
||||
From version 3.x StatiCrypt only uses the browser WebCrypto API, which makes it more secure but is only available in HTTPS or on localhost. If you need to use it in HTTP, you can use version 2.x which offers the CryptoJS engine as an option, and will work everywhere.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const path = require("path");
|
||||
const pathModule = require("path");
|
||||
const fs = require("fs");
|
||||
const readline = require("readline");
|
||||
|
||||
|
@ -6,7 +6,9 @@ const { generateRandomSalt, generateRandomString } = require("../lib/cryptoEngin
|
|||
const { renderTemplate } = require("../lib/formater.js");
|
||||
const Yargs = require("yargs");
|
||||
|
||||
const PASSWORD_TEMPLATE_DEFAULT_PATH = path.join(__dirname, "..", "lib", "password_template.html");
|
||||
const PASSWORD_TEMPLATE_DEFAULT_PATH = pathModule.join(__dirname, "..", "lib", "password_template.html");
|
||||
const OUTPUT_DIRECTORY_DEFAULT_PATH = "encrypted";
|
||||
exports.OUTPUT_DIRECTORY_DEFAULT_PATH = OUTPUT_DIRECTORY_DEFAULT_PATH;
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
|
@ -71,16 +73,19 @@ function prompt(question) {
|
|||
});
|
||||
}
|
||||
|
||||
async function getValidatedPassword(passwordArgument, isShortAllowed) {
|
||||
const password = await getPassword(passwordArgument);
|
||||
|
||||
/**
|
||||
* @param {string} password
|
||||
* @param {boolean} isShortAllowed
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function validatePassword(password, isShortAllowed) {
|
||||
if (password.length < 14 && !isShortAllowed) {
|
||||
const shouldUseShort = await prompt(
|
||||
`WARNING: Your password is less than 14 characters (length: ${password.length})` +
|
||||
" and it's easy to try brute-forcing on public files. For better security we recommend using a longer one, for example: " +
|
||||
" and it's easy to try brute-forcing on public files, so we recommend using a longer one. Here's a generated one: " +
|
||||
generateRandomString(21) +
|
||||
"\nYou can hide this warning by increasing your password length or adding the '--short' flag." +
|
||||
" Do you want to use the short password? [y/N] "
|
||||
"\nDo you want to still want to use the shorter password? [y/N] "
|
||||
);
|
||||
|
||||
if (!shouldUseShort.match(/^\s*(y|yes)\s*$/i)) {
|
||||
|
@ -88,10 +93,8 @@ async function getValidatedPassword(passwordArgument, isShortAllowed) {
|
|||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
exports.getValidatedPassword = getValidatedPassword;
|
||||
exports.validatePassword = validatePassword;
|
||||
|
||||
/**
|
||||
* Get the config from the config file.
|
||||
|
@ -137,6 +140,7 @@ async function getPassword(passwordArgument) {
|
|||
// prompt the user for their password
|
||||
return prompt("Enter your long, unusual password: ");
|
||||
}
|
||||
exports.getPassword = getPassword;
|
||||
|
||||
/**
|
||||
* @param {string} filepath
|
||||
|
@ -200,8 +204,8 @@ function getSalt(namedArgs, config) {
|
|||
* @param {string} modulePath - path from staticrypt root directory
|
||||
*/
|
||||
function convertCommonJSToBrowserJS(modulePath) {
|
||||
const rootDirectory = path.join(__dirname, "..");
|
||||
const resolvedPath = path.join(rootDirectory, ...modulePath.split("/")) + ".js";
|
||||
const rootDirectory = pathModule.join(__dirname, "..");
|
||||
const resolvedPath = pathModule.join(rootDirectory, ...modulePath.split("/")) + ".js";
|
||||
|
||||
if (!fs.existsSync(resolvedPath)) {
|
||||
exitWithError(`could not find module to convert at path "${resolvedPath}"`);
|
||||
|
@ -262,20 +266,29 @@ function genFile(data, outputFilePath, templateFilePath) {
|
|||
|
||||
const renderedTemplate = renderTemplate(templateContents, data);
|
||||
|
||||
writeFile(outputFilePath, renderedTemplate);
|
||||
}
|
||||
exports.genFile = genFile;
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {string} contents
|
||||
*/
|
||||
function writeFile(filePath, contents) {
|
||||
// create output directory if it does not exist
|
||||
const dirname = path.dirname(outputFilePath);
|
||||
const dirname = pathModule.dirname(filePath);
|
||||
if (!fs.existsSync(dirname)) {
|
||||
fs.mkdirSync(dirname, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
fs.writeFileSync(outputFilePath, renderedTemplate);
|
||||
fs.writeFileSync(filePath, contents);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
exitWithError("could not generate output file");
|
||||
exitWithError(`could not write file at path "${filePath}"`);
|
||||
}
|
||||
}
|
||||
exports.genFile = genFile;
|
||||
exports.writeFile = writeFile;
|
||||
|
||||
/**
|
||||
* @param {string} templatePathParameter
|
||||
|
@ -287,6 +300,28 @@ function isCustomPasswordTemplateDefault(templatePathParameter) {
|
|||
}
|
||||
exports.isCustomPasswordTemplateDefault = isCustomPasswordTemplateDefault;
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @param {string} rootDirectory
|
||||
* @param {(fullPath: string, rootDirectoryFromArgument: string) => void} callback
|
||||
*/
|
||||
function recursivelyApplyCallbackToFiles(callback, path, rootDirectory = "") {
|
||||
const fullPath = pathModule.resolve(path);
|
||||
const fullRootDirectory = rootDirectory || pathModule.dirname(fullPath);
|
||||
|
||||
if (fs.statSync(fullPath).isDirectory()) {
|
||||
fs.readdirSync(fullPath).forEach((filePath) => {
|
||||
const fullFilePath = `${fullPath}/${filePath}`;
|
||||
|
||||
recursivelyApplyCallbackToFiles(callback, fullFilePath, fullRootDirectory);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fullPath, fullRootDirectory);
|
||||
}
|
||||
exports.recursivelyApplyCallbackToFiles = recursivelyApplyCallbackToFiles;
|
||||
|
||||
function parseCommandLineArguments() {
|
||||
return (
|
||||
Yargs.usage("Usage: staticrypt <filename> [<filename> ...] [options]")
|
||||
|
@ -299,8 +334,15 @@ function parseCommandLineArguments() {
|
|||
.option("d", {
|
||||
alias: "directory",
|
||||
type: "string",
|
||||
describe: "Name of the directory where the encrypted files will be saved.",
|
||||
default: "encrypted/",
|
||||
describe:
|
||||
"Name of the directory where the generated files will be saved. If the '--decrypt' flag is " +
|
||||
"set, default will be 'decrypted'.",
|
||||
default: OUTPUT_DIRECTORY_DEFAULT_PATH,
|
||||
})
|
||||
.option("decrypt", {
|
||||
type: "boolean",
|
||||
describe: "Include this flag to decrypt files instead of encrypt.",
|
||||
default: false,
|
||||
})
|
||||
.option("p", {
|
||||
alias: "password",
|
||||
|
|
129
cli/index.js
129
cli/index.js
|
@ -12,22 +12,28 @@ if (nodeVersion[0] < 16) {
|
|||
// parse .env file into process.env
|
||||
require("dotenv").config();
|
||||
|
||||
const pathModule = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
const cryptoEngine = require("../lib/cryptoEngine.js");
|
||||
const codec = require("../lib/codec.js");
|
||||
const { generateRandomSalt } = cryptoEngine;
|
||||
const { encodeWithHashedPassword } = codec.init(cryptoEngine);
|
||||
const { decode, encodeWithHashedPassword } = codec.init(cryptoEngine);
|
||||
const {
|
||||
parseCommandLineArguments,
|
||||
OUTPUT_DIRECTORY_DEFAULT_PATH,
|
||||
buildStaticryptJS,
|
||||
isOptionSetByUser,
|
||||
exitWithError,
|
||||
genFile,
|
||||
getFileContent,
|
||||
getValidatedSalt,
|
||||
getValidatedPassword,
|
||||
getConfig,
|
||||
getFileContent,
|
||||
getPassword,
|
||||
getValidatedSalt,
|
||||
isOptionSetByUser,
|
||||
parseCommandLineArguments,
|
||||
recursivelyApplyCallbackToFiles,
|
||||
validatePassword,
|
||||
writeConfig,
|
||||
writeFile,
|
||||
} = require("./helpers.js");
|
||||
|
||||
// parse arguments
|
||||
|
@ -67,23 +73,49 @@ async function runStatiCrypt() {
|
|||
writeConfig(configPath, config);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the salt & password
|
||||
const salt = getValidatedSalt(namedArgs, config);
|
||||
const password = await getValidatedPassword(namedArgs.password, namedArgs.short);
|
||||
const password = await getPassword(namedArgs.password);
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
|
||||
// display the share link with the hashed password if the --share flag is set
|
||||
if (hasShareFlag) {
|
||||
await validatePassword(password, namedArgs.short);
|
||||
|
||||
const url = namedArgs.share || "";
|
||||
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
|
||||
console.log(url + "#staticrypt_pwd=" + hashedPassword);
|
||||
process.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// only process a directory if the --recursive flag is set
|
||||
const directoriesInArguments = positionalArguments.filter((path) => fs.statSync(path).isDirectory());
|
||||
if (directoriesInArguments.length > 0 && !namedArgs.recursive) {
|
||||
exitWithError(
|
||||
`'${directoriesInArguments[0].toString()}' is a directory. Use the -r|--recursive flag to process directories.`
|
||||
);
|
||||
}
|
||||
|
||||
// if asking for decryption, decrypt all the files
|
||||
if (namedArgs.decrypt) {
|
||||
const isOutputDirectoryDefault =
|
||||
namedArgs.directory === OUTPUT_DIRECTORY_DEFAULT_PATH && !isOptionSetByUser("d", yargs);
|
||||
const outputDirectory = isOutputDirectoryDefault ? "decrypted" : namedArgs.directory;
|
||||
|
||||
positionalArguments.forEach((path) => {
|
||||
recursivelyApplyCallbackToFiles((fullPath, fullRootDirectory) => {
|
||||
decodeAndGenerateFile(fullPath, fullRootDirectory, hashedPassword, outputDirectory);
|
||||
}, path);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await validatePassword(password, namedArgs.short);
|
||||
|
||||
// write salt to config file
|
||||
if (config.salt !== salt) {
|
||||
config.salt = salt;
|
||||
|
@ -105,35 +137,56 @@ async function runStatiCrypt() {
|
|||
template_color_secondary: namedArgs.templateColorSecondary,
|
||||
};
|
||||
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
|
||||
positionalArguments.forEach((path) =>
|
||||
encodeAndGenerateFile(path.toString(), hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs)
|
||||
);
|
||||
// encode all the files
|
||||
positionalArguments.forEach((path) => {
|
||||
recursivelyApplyCallbackToFiles((fullPath, fullRootDirectory) => {
|
||||
encodeAndGenerateFile(
|
||||
fullPath,
|
||||
fullRootDirectory,
|
||||
hashedPassword,
|
||||
salt,
|
||||
baseTemplateData,
|
||||
isRememberEnabled,
|
||||
namedArgs
|
||||
);
|
||||
}, path);
|
||||
});
|
||||
}
|
||||
|
||||
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."
|
||||
);
|
||||
async function decodeAndGenerateFile(path, rootDirectoryFromArguments, hashedPassword, outputDirectory) {
|
||||
// get the file content
|
||||
const encryptedFileContent = getFileContent(path);
|
||||
|
||||
// just return instead of exiting the process, that way all other files can be processed
|
||||
return;
|
||||
}
|
||||
// extract the cipher text from the encrypted file
|
||||
const cipherTextMatch = encryptedFileContent.match(/"staticryptEncryptedMsgUniqueVariableName":\s*"([^"]+)"/);
|
||||
const saltMatch = encryptedFileContent.match(/"staticryptSaltUniqueVariableName":\s*"([^"]+)"/);
|
||||
|
||||
fs.readdirSync(path).forEach((filePath) => {
|
||||
const fullPath = `${path}/${filePath}`;
|
||||
|
||||
encodeAndGenerateFile(fullPath, hashedPassword, salt, baseTemplateData, isRememberEnabled, namedArgs);
|
||||
});
|
||||
return;
|
||||
if (!cipherTextMatch || !saltMatch) {
|
||||
return console.log(`ERROR: could not extract cipher text or salt from ${path}`);
|
||||
}
|
||||
|
||||
// decrypt input
|
||||
const { success, decoded } = await decode(cipherTextMatch[1], hashedPassword, saltMatch[1]);
|
||||
|
||||
if (!success) {
|
||||
return console.log(`ERROR: could not decrypt ${path}`);
|
||||
}
|
||||
|
||||
const relativePath = pathModule.relative(rootDirectoryFromArguments, path);
|
||||
const outputFilepath = outputDirectory + "/" + relativePath;
|
||||
|
||||
writeFile(outputFilepath, decoded);
|
||||
}
|
||||
|
||||
async function encodeAndGenerateFile(
|
||||
path,
|
||||
rootDirectoryFromArguments,
|
||||
hashedPassword,
|
||||
salt,
|
||||
baseTemplateData,
|
||||
isRememberEnabled,
|
||||
namedArgs
|
||||
) {
|
||||
// get the file content
|
||||
const contents = getFileContent(path);
|
||||
|
||||
|
@ -141,17 +194,19 @@ async function encodeAndGenerateFile(path, hashedPassword, salt, baseTemplateDat
|
|||
const encryptedMsg = await encodeWithHashedPassword(contents, hashedPassword);
|
||||
|
||||
const staticryptConfig = {
|
||||
encryptedMsg,
|
||||
staticryptEncryptedMsgUniqueVariableName: encryptedMsg,
|
||||
isRememberEnabled,
|
||||
rememberDurationInDays: namedArgs.remember,
|
||||
salt,
|
||||
staticryptSaltUniqueVariableName: salt,
|
||||
};
|
||||
const templateData = {
|
||||
...baseTemplateData,
|
||||
staticrypt_config: staticryptConfig,
|
||||
};
|
||||
|
||||
const outputFilepath = namedArgs.directory.replace(/\/+$/, "") + "/" + path;
|
||||
// remove the base path so that the actual output path is relative to the base path
|
||||
const relativePath = pathModule.relative(rootDirectoryFromArguments, path);
|
||||
const outputFilepath = namedArgs.directory + "/" + relativePath;
|
||||
|
||||
genFile(templateData, outputFilepath, namedArgs.template);
|
||||
}
|
||||
|
|
|
@ -553,10 +553,10 @@ const decode = codec.init(cryptoEngine).decode;
|
|||
* Initialize the staticrypt module, that exposes functions callbable by the password_template.
|
||||
*
|
||||
* @param {{
|
||||
* encryptedMsg: string,
|
||||
* staticryptEncryptedMsgUniqueVariableName: string,
|
||||
* isRememberEnabled: boolean,
|
||||
* rememberDurationInDays: number,
|
||||
* salt: string,
|
||||
* staticryptSaltUniqueVariableName: string,
|
||||
* }} staticryptConfig - object of data that is stored on the password_template at encryption time.
|
||||
*
|
||||
* @param {{
|
||||
|
@ -576,10 +576,14 @@ function init(staticryptConfig, templateConfig) {
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function decryptAndReplaceHtml(hashedPassword) {
|
||||
const { encryptedMsg, salt } = staticryptConfig;
|
||||
const { staticryptEncryptedMsgUniqueVariableName, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { replaceHtmlCallback } = templateConfig;
|
||||
|
||||
const result = await decode(encryptedMsg, hashedPassword, salt);
|
||||
const result = await decode(
|
||||
staticryptEncryptedMsgUniqueVariableName,
|
||||
hashedPassword,
|
||||
staticryptSaltUniqueVariableName
|
||||
);
|
||||
if (!result.success) {
|
||||
return false;
|
||||
}
|
||||
|
@ -606,11 +610,11 @@ function init(staticryptConfig, templateConfig) {
|
|||
* expose more information in the future we can do it without breaking the password_template
|
||||
*/
|
||||
async function handleDecryptionOfPage(password, isRememberChecked) {
|
||||
const { isRememberEnabled, rememberDurationInDays, salt } = staticryptConfig;
|
||||
const { isRememberEnabled, rememberDurationInDays, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
|
||||
|
||||
// decrypt and replace the whole page
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
|
||||
|
||||
const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);
|
||||
|
||||
|
@ -764,7 +768,7 @@ exports.init = init;
|
|||
})());
|
||||
const templateError = "Bad password!",
|
||||
isRememberEnabled = true,
|
||||
staticryptConfig = {"encryptedMsg":"bf0f821fe4fdab54ffde29fd6d812fdf7dd423a0e4e36369c41864d369b71aa6a826caf47e563ba5e4bdfc2b55ea323c5d9fabc6ece3e99cdacc30afd560ec57b6bdda0beef1b2b220e934f214202134e8eb284a5a58f94418c970ca2172622b9286eb5931fff69e345d737c00832ecfbb77057a4e814dd633ab1ef294514d28ef7cb047bb541000b12b8f4c15851fa8ca1e6cd0cbee64c67b4467a46e2bc154896bb4deed9987e222f0c280c8d766ea16769515f9d337592e6807dfa07534ef","isRememberEnabled":true,"rememberDurationInDays":0,"salt":"b93bbaf35459951c47721d1f3eaeb5b9"};
|
||||
staticryptConfig = {"staticryptEncryptedMsgUniqueVariableName":"85cf880a1573985224adbac66ceeba6c026484ad101ffabc6bc0d874a1e4eb75ddee7d265055e80d8e87369a694f873ff044933e1b5d33c46a636e2fdc4f2d108f0dd36252aba4c2e0f71a8e9ed2027839a6ea46a3e3a5f8e0d205046966c3bd1eac8b78e5ba3a5d9015eea2e0d83629d19c47e0b2311966aa7d3ac2fb8b592276484fea27cd90e5e85e65c11abd483a3d938b738efb02d290e94c9d249844f157667be667ed018f0d0e7702f141ef713c8cc2b472e25922d70cb75955a4182b","isRememberEnabled":true,"rememberDurationInDays":0,"staticryptSaltUniqueVariableName":"b93bbaf35459951c47721d1f3eaeb5b9"};
|
||||
|
||||
// you can edit these values to customize some of the behavior of StatiCrypt
|
||||
const templateConfig = {
|
||||
|
|
16
index.html
16
index.html
|
@ -1044,10 +1044,10 @@ const decode = codec.init(cryptoEngine).decode;
|
|||
* Initialize the staticrypt module, that exposes functions callbable by the password_template.
|
||||
*
|
||||
* @param {{
|
||||
* encryptedMsg: string,
|
||||
* staticryptEncryptedMsgUniqueVariableName: string,
|
||||
* isRememberEnabled: boolean,
|
||||
* rememberDurationInDays: number,
|
||||
* salt: string,
|
||||
* staticryptSaltUniqueVariableName: string,
|
||||
* }} staticryptConfig - object of data that is stored on the password_template at encryption time.
|
||||
*
|
||||
* @param {{
|
||||
|
@ -1067,10 +1067,14 @@ function init(staticryptConfig, templateConfig) {
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function decryptAndReplaceHtml(hashedPassword) {
|
||||
const { encryptedMsg, salt } = staticryptConfig;
|
||||
const { staticryptEncryptedMsgUniqueVariableName, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { replaceHtmlCallback } = templateConfig;
|
||||
|
||||
const result = await decode(encryptedMsg, hashedPassword, salt);
|
||||
const result = await decode(
|
||||
staticryptEncryptedMsgUniqueVariableName,
|
||||
hashedPassword,
|
||||
staticryptSaltUniqueVariableName
|
||||
);
|
||||
if (!result.success) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1097,11 +1101,11 @@ function init(staticryptConfig, templateConfig) {
|
|||
* expose more information in the future we can do it without breaking the password_template
|
||||
*/
|
||||
async function handleDecryptionOfPage(password, isRememberChecked) {
|
||||
const { isRememberEnabled, rememberDurationInDays, salt } = staticryptConfig;
|
||||
const { isRememberEnabled, rememberDurationInDays, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
|
||||
|
||||
// decrypt and replace the whole page
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
|
||||
|
||||
const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ const decode = codec.init(cryptoEngine).decode;
|
|||
* Initialize the staticrypt module, that exposes functions callbable by the password_template.
|
||||
*
|
||||
* @param {{
|
||||
* encryptedMsg: string,
|
||||
* staticryptEncryptedMsgUniqueVariableName: string,
|
||||
* isRememberEnabled: boolean,
|
||||
* rememberDurationInDays: number,
|
||||
* salt: string,
|
||||
* staticryptSaltUniqueVariableName: string,
|
||||
* }} staticryptConfig - object of data that is stored on the password_template at encryption time.
|
||||
*
|
||||
* @param {{
|
||||
|
@ -29,10 +29,14 @@ function init(staticryptConfig, templateConfig) {
|
|||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function decryptAndReplaceHtml(hashedPassword) {
|
||||
const { encryptedMsg, salt } = staticryptConfig;
|
||||
const { staticryptEncryptedMsgUniqueVariableName, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { replaceHtmlCallback } = templateConfig;
|
||||
|
||||
const result = await decode(encryptedMsg, hashedPassword, salt);
|
||||
const result = await decode(
|
||||
staticryptEncryptedMsgUniqueVariableName,
|
||||
hashedPassword,
|
||||
staticryptSaltUniqueVariableName
|
||||
);
|
||||
if (!result.success) {
|
||||
return false;
|
||||
}
|
||||
|
@ -59,11 +63,11 @@ function init(staticryptConfig, templateConfig) {
|
|||
* expose more information in the future we can do it without breaking the password_template
|
||||
*/
|
||||
async function handleDecryptionOfPage(password, isRememberChecked) {
|
||||
const { isRememberEnabled, rememberDurationInDays, salt } = staticryptConfig;
|
||||
const { isRememberEnabled, rememberDurationInDays, staticryptSaltUniqueVariableName } = staticryptConfig;
|
||||
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
|
||||
|
||||
// decrypt and replace the whole page
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, salt);
|
||||
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
|
||||
|
||||
const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "staticrypt",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "staticrypt",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.3",
|
||||
|
@ -15,8 +15,15 @@
|
|||
"bin": {
|
||||
"staticrypt": "cli/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/robinmoisson/staticrypt?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
|
@ -104,6 +111,21 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.7",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
|
||||
"integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
@ -248,6 +270,12 @@
|
|||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.8.7",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
|
||||
"integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
|
||||
"dev": true
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
|
11
package.json
11
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "staticrypt",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.0",
|
||||
"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).",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
|
@ -17,6 +17,10 @@
|
|||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/robinmoisson/staticrypt?sponsor=1"
|
||||
},
|
||||
"author": "Robin Moisson (https://github.com/robinmoisson)",
|
||||
"contributors": [
|
||||
"Aaron Coplan (https://github.com/AaronCoplan)",
|
||||
|
@ -43,5 +47,8 @@
|
|||
"bugs": {
|
||||
"url": "https://github.com/robinmoisson/staticrypt/issues"
|
||||
},
|
||||
"homepage": "https://github.com/robinmoisson/staticrypt"
|
||||
"homepage": "https://github.com/robinmoisson/staticrypt",
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.7"
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue