kopia lustrzana https://github.com/robinmoisson/staticrypt
rodzic
786ca7a681
commit
ba24ae42c0
|
@ -2,3 +2,4 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
node_modules
|
node_modules
|
||||||
.staticrypt.json
|
.staticrypt.json
|
||||||
|
.env
|
||||||
|
|
11
README.md
11
README.md
|
@ -22,6 +22,13 @@ Staticrypt is available through npm as a CLI, install with `npm install -g stati
|
||||||
staticrypt test.html MY_PASSPHRASE
|
staticrypt test.html MY_PASSPHRASE
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Encrypt a file with the passphrase in an environment variable:** set your passphrase in the `STATICRYPT_PASSWORD` environment variable ([`.env` files](https://www.npmjs.com/package/dotenv#usage) are supported):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# the passphrase is in the STATICRYPT_PASSWORD env variable
|
||||||
|
staticrypt test.html
|
||||||
|
```
|
||||||
|
|
||||||
**Encrypt a file and get a shareble link containing the hashed password** - you can include your file URL or leave blank:
|
**Encrypt a file and get a shareble link containing the hashed password** - you can include your file URL or leave blank:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -43,7 +50,9 @@ find . -type f -name "*.html" -not -name "*_encrypted.html" -exec staticrypt {}
|
||||||
|
|
||||||
### CLI Reference
|
### CLI Reference
|
||||||
|
|
||||||
Usage: staticrypt <filename> <passphrase> [options]
|
The passphrase argument is optional if `STATICRYPT_PASSWORD` is set in the environment or `.env` file.
|
||||||
|
|
||||||
|
Usage: staticrypt <filename> [<passphrase>] [options]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--help Show help [boolean]
|
--help Show help [boolean]
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const cryptoEngine = require("../lib/cryptoEngine/cryptojsEngine");
|
||||||
|
const { generateRandomSalt } = cryptoEngine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
function exitEarly(message) {
|
function exitEarly(message) {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -12,7 +20,7 @@ exports.exitEarly = exitEarly;
|
||||||
*
|
*
|
||||||
* From https://github.com/yargs/yargs/issues/513#issuecomment-221412008
|
* From https://github.com/yargs/yargs/issues/513#issuecomment-221412008
|
||||||
*
|
*
|
||||||
* @param option
|
* @param {string} option
|
||||||
* @param yargs
|
* @param yargs
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
|
@ -36,3 +44,58 @@ function isOptionSetByUser(option, yargs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
exports.isOptionSetByUser = isOptionSetByUser;
|
exports.isOptionSetByUser = isOptionSetByUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the password from the command arguments
|
||||||
|
*
|
||||||
|
* @param {string[]} positionalArguments
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getPassword(positionalArguments) {
|
||||||
|
let password = process.env.STATICRYPT_PASSWORD;
|
||||||
|
const hasEnvPassword = password !== undefined && password !== "";
|
||||||
|
|
||||||
|
if (hasEnvPassword) {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positionalArguments.length < 2) {
|
||||||
|
exitEarly("Missing password: please provide an argument or set the STATICRYPT_PASSWORD environment variable in the environment or .env file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return positionalArguments[1];
|
||||||
|
}
|
||||||
|
exports.getPassword = getPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} filepath
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getFileContent(filepath) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filepath, "utf8");
|
||||||
|
} catch (e) {
|
||||||
|
exitEarly("Failure: input file does not exist!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.getFileContent = getFileContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} namedArgs
|
||||||
|
* @param {object} config
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getSalt(namedArgs, config) {
|
||||||
|
// either a salt was provided by the user through the flag --salt
|
||||||
|
if (!!namedArgs.salt) {
|
||||||
|
return String(namedArgs.salt).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// or try to read the salt from config file
|
||||||
|
if (config.salt) {
|
||||||
|
return config.salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateRandomSalt();
|
||||||
|
}
|
||||||
|
exports.getSalt = getSalt;
|
||||||
|
|
50
cli/index.js
50
cli/index.js
|
@ -5,10 +5,14 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const Yargs = require("yargs");
|
const Yargs = require("yargs");
|
||||||
|
|
||||||
|
// parse .env file into process.env
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
const cryptoEngine = require("../lib/cryptoEngine/cryptojsEngine");
|
const cryptoEngine = require("../lib/cryptoEngine/cryptojsEngine");
|
||||||
const codec = require("../lib/codec");
|
const codec = require("../lib/codec");
|
||||||
const { convertCommonJSToBrowserJS, genFile} = require("../lib/formater");
|
const { convertCommonJSToBrowserJS, genFile} = require("../lib/formater");
|
||||||
const { exitEarly, isOptionSetByUser } = require("./helpers");
|
const { exitEarly, isOptionSetByUser, getPassword, getFileContent, getSalt} = require("./helpers");
|
||||||
const { generateRandomSalt } = cryptoEngine;
|
const { generateRandomSalt } = cryptoEngine;
|
||||||
const { encode } = codec.init(cryptoEngine);
|
const { encode } = codec.init(cryptoEngine);
|
||||||
|
|
||||||
|
@ -19,7 +23,7 @@ const SCRIPT_TAG =
|
||||||
SCRIPT_URL +
|
SCRIPT_URL +
|
||||||
'" integrity="sha384-lp4k1VRKPU9eBnPePjnJ9M2RF3i7PC30gXs70+elCVfgwLwx1tv5+ctxdtwxqZa7" crossorigin="anonymous"></script>';
|
'" integrity="sha384-lp4k1VRKPU9eBnPePjnJ9M2RF3i7PC30gXs70+elCVfgwLwx1tv5+ctxdtwxqZa7" crossorigin="anonymous"></script>';
|
||||||
|
|
||||||
const yargs = Yargs.usage("Usage: staticrypt <filename> <passphrase> [options]")
|
const yargs = Yargs.usage("Usage: staticrypt <filename> [<passphrase>] [options]")
|
||||||
.option("c", {
|
.option("c", {
|
||||||
alias: "config",
|
alias: "config",
|
||||||
type: "string",
|
type: "string",
|
||||||
|
@ -117,11 +121,16 @@ if (isOptionSetByUser("s", yargs) && !namedArgs.salt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the number of arguments
|
// validate the number of arguments
|
||||||
if (namedArgs._.length !== 2) {
|
const positionalArguments = namedArgs._;
|
||||||
|
if (positionalArguments.length > 2 || positionalArguments.length === 0) {
|
||||||
Yargs.showHelp();
|
Yargs.showHelp();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse input
|
||||||
|
const inputFilepath = positionalArguments[0].toString(),
|
||||||
|
password = getPassword(positionalArguments);
|
||||||
|
|
||||||
// get config file
|
// get config file
|
||||||
const isUsingconfigFile = namedArgs.config.toLowerCase() !== "false";
|
const isUsingconfigFile = namedArgs.config.toLowerCase() !== "false";
|
||||||
const configPath = "./" + namedArgs.config;
|
const configPath = "./" + namedArgs.config;
|
||||||
|
@ -130,22 +139,8 @@ if (isUsingconfigFile && fs.existsSync(configPath)) {
|
||||||
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// get the salt
|
||||||
* Get the salt to use
|
const salt = getSalt(namedArgs, config);
|
||||||
*/
|
|
||||||
let salt;
|
|
||||||
// either a salt was provided by the user through the flag --salt
|
|
||||||
if (!!namedArgs.salt) {
|
|
||||||
salt = String(namedArgs.salt).toLowerCase();
|
|
||||||
}
|
|
||||||
// or we try to read the salt from config file
|
|
||||||
else if (!!config.salt) {
|
|
||||||
salt = config.salt;
|
|
||||||
}
|
|
||||||
// or we generate a salt
|
|
||||||
else {
|
|
||||||
salt = generateRandomSalt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the salt
|
// validate the salt
|
||||||
if (salt.length !== 32 || /[^a-f0-9]/.test(salt)) {
|
if (salt.length !== 32 || /[^a-f0-9]/.test(salt)) {
|
||||||
|
@ -161,28 +156,19 @@ if (isUsingconfigFile && config.salt !== salt) {
|
||||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse input
|
|
||||||
const input = namedArgs._[0].toString(),
|
|
||||||
passphrase = namedArgs._[1].toString();
|
|
||||||
|
|
||||||
// display the share link with the hashed password if the --share flag is set
|
// display the share link with the hashed password if the --share flag is set
|
||||||
if (isOptionSetByUser("share", yargs)) {
|
if (isOptionSetByUser("share", yargs)) {
|
||||||
const url = namedArgs.share || "";
|
const url = namedArgs.share || "";
|
||||||
const hashedPassphrase = cryptoEngine.hashPassphrase(passphrase, salt);
|
const hashedPassphrase = cryptoEngine.hashPassphrase(password, salt);
|
||||||
|
|
||||||
console.log(url + "?staticrypt_pwd=" + hashedPassphrase);
|
console.log(url + "?staticrypt_pwd=" + hashedPassphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the file content
|
// get the file content
|
||||||
let contents;
|
const contents = getFileContent(inputFilepath);
|
||||||
try {
|
|
||||||
contents = fs.readFileSync(input, "utf8");
|
|
||||||
} catch (e) {
|
|
||||||
exitEarly("Failure: input file does not exist!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// encrypt input
|
// encrypt input
|
||||||
const encryptedMessage = encode(contents, passphrase, salt);
|
const encryptedMessage = encode(contents, password, salt);
|
||||||
|
|
||||||
// create crypto-js tag (embedded or not)
|
// create crypto-js tag (embedded or not)
|
||||||
let cryptoTag = SCRIPT_TAG;
|
let cryptoTag = SCRIPT_TAG;
|
||||||
|
@ -218,6 +204,6 @@ const data = {
|
||||||
|
|
||||||
const outputFilePath = namedArgs.output !== null
|
const outputFilePath = namedArgs.output !== null
|
||||||
? namedArgs.output
|
? namedArgs.output
|
||||||
: input.replace(/\.html$/, "") + "_encrypted.html";
|
: inputFilepath.replace(/\.html$/, "") + "_encrypted.html";
|
||||||
|
|
||||||
genFile(data, outputFilePath, namedArgs.f);
|
genFile(data, outputFilePath, namedArgs.f);
|
||||||
|
|
|
@ -349,7 +349,7 @@ exports.init = init;
|
||||||
var decode = codec.init(cryptoEngine).decode;
|
var decode = codec.init(cryptoEngine).decode;
|
||||||
|
|
||||||
// variables to be filled when generating the file
|
// variables to be filled when generating the file
|
||||||
var encryptedMsg = '56dea7d61318f40686a20af181fb5d14ce025164d56770ddc61e4078def3d7fa69239fbb3c84b1fe941343cf41100ba6U2FsdGVkX1+4r6JJlpkeR9aAipKLcWURUBxGgPpqDEAR7vAJu1wnAztHaNch1IemKHPOJ+Oy9Mi30xuAfl14RUbSn/nIpReEzVNWVdTQsetFPs+uSDdlayJF1I9CwSkmp0MnQB+d85QWh3xDQpdZ/+fWaRdXPIhhvavpkThFAeJatSezVbA2Xx4CNJWfzc2ekin7uoEAizHk+qUAefRCbA==',
|
var encryptedMsg = '30d59eebfa6443549af9f78e49525e458bd5d4ee783cb2fc5a61882f62769d8ec467ba45c6c10554321b4ff338b9baacU2FsdGVkX1/M666zWrcMkpw3mxNzMVp8DMjVCvC7R6wGFtZMgA17LV7KuFWo9vqiCoqz52rvljIuZ65Uq5xFJxKGZAAhXfiKrfNnlhcoEsqrdLH/RVRqC2VKPwlM+6OyMd2GB5FV79kWJW9xlnrUjpokIbq7OqIfKooQ8hSKsJFqHNJFYzLNuGMtvERC23jgSFXSKoCACBPXsSgqCdrxbQ==',
|
||||||
salt = 'b93bbaf35459951c47721d1f3eaeb5b9',
|
salt = 'b93bbaf35459951c47721d1f3eaeb5b9',
|
||||||
labelError = 'Bad password!',
|
labelError = 'Bad password!',
|
||||||
isRememberEnabled = true,
|
isRememberEnabled = true,
|
||||||
|
@ -461,6 +461,7 @@ exports.init = init;
|
||||||
if (!hasDecrypted) {
|
if (!hasDecrypted) {
|
||||||
document.getElementById("staticrypt_loading").classList.add("hidden");
|
document.getElementById("staticrypt_loading").classList.add("hidden");
|
||||||
document.getElementById("staticrypt_content").classList.remove("hidden");
|
document.getElementById("staticrypt_content").classList.remove("hidden");
|
||||||
|
document.getElementById("staticrypt-password").focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,7 @@
|
||||||
if (!hasDecrypted) {
|
if (!hasDecrypted) {
|
||||||
document.getElementById("staticrypt_loading").classList.add("hidden");
|
document.getElementById("staticrypt_loading").classList.add("hidden");
|
||||||
document.getElementById("staticrypt_content").classList.remove("hidden");
|
document.getElementById("staticrypt_content").classList.remove("hidden");
|
||||||
|
document.getElementById("staticrypt-password").focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
{
|
{
|
||||||
"name": "staticrypt",
|
"name": "staticrypt",
|
||||||
"version": "2.1.1",
|
"version": "2.3.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "staticrypt",
|
"name": "staticrypt",
|
||||||
"version": "2.1.1",
|
"version": "2.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-js": "3.1.9-1",
|
"crypto-js": "3.1.9-1",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
"yargs": ">=10.0.3"
|
"yargs": ">=10.0.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"staticrypt": "cli/index.js"
|
"staticrypt": "cli/index.js"
|
||||||
},
|
}
|
||||||
"devDependencies": {}
|
|
||||||
},
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
|
@ -70,6 +70,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
|
||||||
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
|
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "16.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||||
|
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
@ -223,6 +231,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
|
||||||
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
|
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
|
||||||
},
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "16.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||||
|
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
|
||||||
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "staticrypt",
|
"name": "staticrypt",
|
||||||
"version": "2.2.1",
|
"version": "2.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 passphrase and put it in a HTML file with a password prompt that can decrypted in-browser (client side).",
|
"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",
|
"main": "index.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-js": "3.1.9-1",
|
"crypto-js": "3.1.9-1",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
"yargs": ">=10.0.3"
|
"yargs": ">=10.0.3"
|
||||||
},
|
},
|
||||||
"author": "Robin Moisson (https://github.com/robinmoisson)",
|
"author": "Robin Moisson (https://github.com/robinmoisson)",
|
||||||
|
@ -19,7 +20,6 @@
|
||||||
"Aaron Coplan (https://github.com/AaronCoplan)"
|
"Aaron Coplan (https://github.com/AaronCoplan)"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bash ./scripts/build.sh",
|
"build": "bash ./scripts/build.sh",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
Ładowanie…
Reference in New Issue