kopia lustrzana https://github.com/robinmoisson/staticrypt
Organize source files into more directories (#137)
* organize into directories * address comments from PR#137pull/138/head
rodzic
9bac93c011
commit
bdc831d91f
|
@ -1,6 +1,4 @@
|
|||
.idea
|
||||
.vscode/
|
||||
node_modules
|
||||
.staticrypt.json
|
||||
/cli/README.md
|
||||
/cli/LICENSE
|
||||
/cli/password_template.html
|
||||
|
|
11
README.md
11
README.md
|
@ -133,19 +133,26 @@ The salt isn't secret, so you don't need to worry about hiding the config file.
|
|||
|
||||
## Contributing
|
||||
|
||||
### Source Directories
|
||||
|
||||
- `cli/` - The command-line interface published to NPM.
|
||||
- `example/` - This file is encrypted as part of the build. The encrypted file is committed both to make this library easy to explore and as a review-time sanity check.
|
||||
- `lib/` - Files shared across www and cli.
|
||||
- `scripts/` - Build, test, deploy, CI, etc. See `npm run-script`.
|
||||
- `index.html` - The root of the in-browser encryption site hosted at https://robinmoisson.github.io/staticrypt. Kept in the root of the repo for easy deploys to GitHub Pages.
|
||||
|
||||
### Build
|
||||
Built assets are committed to main. Run build before submitting a PR or publishing to npm.
|
||||
|
||||
```
|
||||
# From staticrypt/
|
||||
$ cd cli
|
||||
$ npm install
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
### Test
|
||||
Testing is currently manual to keep dependencies low.
|
||||
[Build](#build), then open `example_encypted.html`.
|
||||
[Build](#build), then open `example/example_encypted.html`.
|
||||
|
||||
## 🙏 Contribution
|
||||
|
||||
|
|
351
cli/index.js
351
cli/index.js
|
@ -1,31 +1,35 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const CryptoJS = require("crypto-js");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const Yargs = require('yargs');
|
||||
const Yargs = require("yargs");
|
||||
|
||||
const SCRIPT_URL = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js';
|
||||
const SCRIPT_TAG = '<script src="' + SCRIPT_URL + '" integrity="sha384-lp4k1VRKPU9eBnPePjnJ9M2RF3i7PC30gXs70+elCVfgwLwx1tv5+ctxdtwxqZa7" crossorigin="anonymous"></script>';
|
||||
const SCRIPT_URL =
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js";
|
||||
const SCRIPT_TAG =
|
||||
'<script src="' +
|
||||
SCRIPT_URL +
|
||||
'" integrity="sha384-lp4k1VRKPU9eBnPePjnJ9M2RF3i7PC30gXs70+elCVfgwLwx1tv5+ctxdtwxqZa7" crossorigin="anonymous"></script>';
|
||||
|
||||
/**
|
||||
* Salt and encrypt a msg with a password.
|
||||
* Inspired by https://github.com/adonespitogo
|
||||
*/
|
||||
function encrypt(msg, hashedPassphrase) {
|
||||
var iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
var iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
|
||||
var encrypted = CryptoJS.AES.encrypt(msg, hashedPassphrase, {
|
||||
iv: iv,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
mode: CryptoJS.mode.CBC
|
||||
});
|
||||
var encrypted = CryptoJS.AES.encrypt(msg, hashedPassphrase, {
|
||||
iv: iv,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
});
|
||||
|
||||
// iv will be hex 16 in length (32 characters)
|
||||
// we prepend it to the ciphertext for use in decryption
|
||||
return iv.toString() + encrypted.toString();
|
||||
// iv will be hex 16 in length (32 characters)
|
||||
// we prepend it to the ciphertext for use in decryption
|
||||
return iv.toString() + encrypted.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,16 +40,16 @@ function encrypt(msg, hashedPassphrase) {
|
|||
* @returns string
|
||||
*/
|
||||
function hashPassphrase(passphrase, salt) {
|
||||
var hashedPassphrase = CryptoJS.PBKDF2(passphrase, salt, {
|
||||
keySize: 256 / 32,
|
||||
iterations: 1000
|
||||
});
|
||||
var hashedPassphrase = CryptoJS.PBKDF2(passphrase, salt, {
|
||||
keySize: 256 / 32,
|
||||
iterations: 1000,
|
||||
});
|
||||
|
||||
return hashedPassphrase.toString();
|
||||
return hashedPassphrase.toString();
|
||||
}
|
||||
|
||||
function generateRandomSalt() {
|
||||
return CryptoJS.lib.WordArray.random(128 / 8).toString();
|
||||
return CryptoJS.lib.WordArray.random(128 / 8).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,120 +65,121 @@ function generateRandomSalt() {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
function isOptionSetByUser(option, yargs) {
|
||||
function searchForOption(option) {
|
||||
return process.argv.indexOf(option) > -1;
|
||||
}
|
||||
function searchForOption(option) {
|
||||
return process.argv.indexOf(option) > -1;
|
||||
}
|
||||
|
||||
if (searchForOption(`-${option}`) || searchForOption(`--${option}`)) {
|
||||
return true;
|
||||
}
|
||||
if (searchForOption(`-${option}`) || searchForOption(`--${option}`)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle aliases for same option
|
||||
for (let aliasIndex in yargs.parsed.aliases[option]) {
|
||||
const alias = yargs.parsed.aliases[option][aliasIndex];
|
||||
// Handle aliases for same option
|
||||
for (let aliasIndex in yargs.parsed.aliases[option]) {
|
||||
const alias = yargs.parsed.aliases[option][aliasIndex];
|
||||
|
||||
if (searchForOption(`-${alias}`) || searchForOption(`--${alias}`))
|
||||
return true;
|
||||
}
|
||||
if (searchForOption(`-${alias}`) || searchForOption(`--${alias}`))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const yargs = Yargs
|
||||
.usage('Usage: staticrypt <filename> <passphrase> [options]')
|
||||
.option('c', {
|
||||
alias: 'config',
|
||||
type: 'string',
|
||||
describe: 'Path to the config file. Set to "false" to disable.',
|
||||
default: '.staticrypt.json',
|
||||
})
|
||||
.option('decrypt-button', {
|
||||
type: 'string',
|
||||
describe: 'Label to use for the decrypt button. Default: "DECRYPT".',
|
||||
default: 'DECRYPT'
|
||||
})
|
||||
.option('e', {
|
||||
alias: 'embed',
|
||||
type: 'boolean',
|
||||
describe: 'Whether or not to embed crypto-js in the page (or use an external CDN).',
|
||||
default: true
|
||||
})
|
||||
.option('f', {
|
||||
alias: 'file-template',
|
||||
type: 'string',
|
||||
describe: 'Path to custom HTML template with passphrase prompt.',
|
||||
default: path.join(__dirname, 'password_template.html')
|
||||
})
|
||||
.option('i', {
|
||||
alias: 'instructions',
|
||||
type: 'string',
|
||||
describe: 'Special instructions to display to the user.',
|
||||
default: ''
|
||||
})
|
||||
.option('noremember', {
|
||||
type: 'boolean',
|
||||
describe: 'Set this flag to remove the "Remember me" checkbox.',
|
||||
default: false,
|
||||
})
|
||||
.option('o', {
|
||||
alias: 'output',
|
||||
type: 'string',
|
||||
describe: 'File name / path for generated encrypted file.',
|
||||
default: null
|
||||
})
|
||||
.option('passphrase-placeholder', {
|
||||
type: 'string',
|
||||
describe: 'Placeholder to use for the passphrase input.',
|
||||
default: 'Passphrase'
|
||||
})
|
||||
.option('r', {
|
||||
alias: 'remember',
|
||||
type: 'number',
|
||||
describe: 'Expiration in days of the "Remember me" checkbox that will save the (salted + hashed) passphrase ' +
|
||||
'in localStorage when entered by the user. Default: "0", no expiration.',
|
||||
default: 0,
|
||||
})
|
||||
.option('remember-label', {
|
||||
type: 'string',
|
||||
describe: 'Label to use for the "Remember me" checkbox.',
|
||||
default: 'Remember me'
|
||||
})
|
||||
// do not give a default option to this 'remember' parameter - we want to see when the flag is included with no
|
||||
// value and when it's not included at all
|
||||
.option('s', {
|
||||
alias: 'salt',
|
||||
describe: 'Set the salt manually. It should be set if you want use "Remember me" through multiple pages. It ' +
|
||||
'needs to be a 32 character long hexadecimal string.\nInclude the empty flag to generate a random salt you ' +
|
||||
'can use: "statycrypt -s".',
|
||||
type: 'string',
|
||||
})
|
||||
.option('t', {
|
||||
alias: 'title',
|
||||
type: 'string',
|
||||
describe: "Title for output HTML page.",
|
||||
default: 'Protected Page'
|
||||
});
|
||||
const yargs = Yargs.usage("Usage: staticrypt <filename> <passphrase> [options]")
|
||||
.option("c", {
|
||||
alias: "config",
|
||||
type: "string",
|
||||
describe: 'Path to the config file. Set to "false" to disable.',
|
||||
default: ".staticrypt.json",
|
||||
})
|
||||
.option("decrypt-button", {
|
||||
type: "string",
|
||||
describe: 'Label to use for the decrypt button. Default: "DECRYPT".',
|
||||
default: "DECRYPT",
|
||||
})
|
||||
.option("e", {
|
||||
alias: "embed",
|
||||
type: "boolean",
|
||||
describe:
|
||||
"Whether or not to embed crypto-js in the page (or use an external CDN).",
|
||||
default: true,
|
||||
})
|
||||
.option("f", {
|
||||
alias: "file-template",
|
||||
type: "string",
|
||||
describe: "Path to custom HTML template with passphrase prompt.",
|
||||
default: path.join(__dirname, "..", "lib", "password_template.html"),
|
||||
})
|
||||
.option("i", {
|
||||
alias: "instructions",
|
||||
type: "string",
|
||||
describe: "Special instructions to display to the user.",
|
||||
default: "",
|
||||
})
|
||||
.option("noremember", {
|
||||
type: "boolean",
|
||||
describe: 'Set this flag to remove the "Remember me" checkbox.',
|
||||
default: false,
|
||||
})
|
||||
.option("o", {
|
||||
alias: "output",
|
||||
type: "string",
|
||||
describe: "File name / path for generated encrypted file.",
|
||||
default: null,
|
||||
})
|
||||
.option("passphrase-placeholder", {
|
||||
type: "string",
|
||||
describe: "Placeholder to use for the passphrase input.",
|
||||
default: "Passphrase",
|
||||
})
|
||||
.option("r", {
|
||||
alias: "remember",
|
||||
type: "number",
|
||||
describe:
|
||||
'Expiration in days of the "Remember me" checkbox that will save the (salted + hashed) passphrase ' +
|
||||
'in localStorage when entered by the user. Default: "0", no expiration.',
|
||||
default: 0,
|
||||
})
|
||||
.option("remember-label", {
|
||||
type: "string",
|
||||
describe: 'Label to use for the "Remember me" checkbox.',
|
||||
default: "Remember me",
|
||||
})
|
||||
// do not give a default option to this 'remember' parameter - we want to see when the flag is included with no
|
||||
// value and when it's not included at all
|
||||
.option("s", {
|
||||
alias: "salt",
|
||||
describe:
|
||||
'Set the salt manually. It should be set if you want use "Remember me" through multiple pages. It ' +
|
||||
"needs to be a 32 character long hexadecimal string.\nInclude the empty flag to generate a random salt you " +
|
||||
'can use: "statycrypt -s".',
|
||||
type: "string",
|
||||
})
|
||||
.option("t", {
|
||||
alias: "title",
|
||||
type: "string",
|
||||
describe: "Title for output HTML page.",
|
||||
default: "Protected Page",
|
||||
});
|
||||
const namedArgs = yargs.argv;
|
||||
|
||||
|
||||
// if the 's' flag is passed without parameter, generate a salt, display & exit
|
||||
if (isOptionSetByUser('s', yargs) && !namedArgs.salt) {
|
||||
console.log(generateRandomSalt());
|
||||
process.exit(0);
|
||||
if (isOptionSetByUser("s", yargs) && !namedArgs.salt) {
|
||||
console.log(generateRandomSalt());
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// validate the number of arguments
|
||||
if (namedArgs._.length !== 2) {
|
||||
Yargs.showHelp();
|
||||
process.exit(1);
|
||||
Yargs.showHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// get config file
|
||||
const isUsingconfigFile = namedArgs.config.toLowerCase() !== 'false';
|
||||
const configPath = './' + namedArgs.config;
|
||||
const isUsingconfigFile = namedArgs.config.toLowerCase() !== "false";
|
||||
const configPath = "./" + namedArgs.config;
|
||||
let config = {};
|
||||
if (isUsingconfigFile && fs.existsSync(configPath)) {
|
||||
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,41 +188,43 @@ if (isUsingconfigFile && fs.existsSync(configPath)) {
|
|||
let salt;
|
||||
// either a salt was provided by the user through the flag --salt
|
||||
if (!!namedArgs.salt) {
|
||||
salt = String(namedArgs.salt).toLowerCase();
|
||||
salt = String(namedArgs.salt).toLowerCase();
|
||||
}
|
||||
// or we try to read the salt from config file
|
||||
else if (!!config.salt) {
|
||||
salt = config.salt;
|
||||
salt = config.salt;
|
||||
}
|
||||
// or we generate a salt
|
||||
else {
|
||||
salt = generateRandomSalt();
|
||||
salt = generateRandomSalt();
|
||||
}
|
||||
|
||||
// validate the salt
|
||||
if (salt.length !== 32 || /[^a-f0-9]/.test(salt)) {
|
||||
console.log("The salt should be a 32 character long hexadecimal string (only [0-9a-f] characters allowed)");
|
||||
console.log("Detected salt: " + salt);
|
||||
process.exit(1);
|
||||
console.log(
|
||||
"The salt should be a 32 character long hexadecimal string (only [0-9a-f] characters allowed)"
|
||||
);
|
||||
console.log("Detected salt: " + salt);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// write salt to config file
|
||||
if (isUsingconfigFile && config.salt !== salt) {
|
||||
config.salt = salt;
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
|
||||
config.salt = salt;
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
|
||||
}
|
||||
|
||||
// parse input
|
||||
const input = namedArgs._[0].toString(),
|
||||
passphrase = namedArgs._[1].toString();
|
||||
passphrase = namedArgs._[1].toString();
|
||||
|
||||
// get the file content
|
||||
let contents;
|
||||
try {
|
||||
contents = fs.readFileSync(input, 'utf8');
|
||||
contents = fs.readFileSync(input, "utf8");
|
||||
} catch (e) {
|
||||
console.log("Failure: input file does not exist!");
|
||||
process.exit(1);
|
||||
console.log("Failure: input file does not exist!");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// encrypt input
|
||||
|
@ -225,63 +232,71 @@ const hashedPassphrase = hashPassphrase(passphrase, salt);
|
|||
const encrypted = encrypt(contents, hashedPassphrase);
|
||||
// we use the hashed passphrase in the HMAC because this is effectively what will be used a passphrase (so we can store
|
||||
// it in localStorage safely, we don't use the clear text passphrase)
|
||||
const hmac = CryptoJS.HmacSHA256(encrypted, CryptoJS.SHA256(hashedPassphrase).toString()).toString();
|
||||
const hmac = CryptoJS.HmacSHA256(
|
||||
encrypted,
|
||||
CryptoJS.SHA256(hashedPassphrase).toString()
|
||||
).toString();
|
||||
const encryptedMessage = hmac + encrypted;
|
||||
|
||||
// create crypto-js tag (embedded or not)
|
||||
let cryptoTag = SCRIPT_TAG;
|
||||
if (namedArgs.embed) {
|
||||
try {
|
||||
const embedContents = fs.readFileSync(path.join(__dirname, 'crypto-js.min.js'), 'utf8');
|
||||
try {
|
||||
const embedContents = fs.readFileSync(
|
||||
path.join(__dirname, "..", "kryptojs-3.1.9-1.min"),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
cryptoTag = '<script>' + embedContents + '</script>';
|
||||
} catch (e) {
|
||||
console.log("Failure: embed file does not exist!");
|
||||
process.exit(1);
|
||||
}
|
||||
cryptoTag = "<script>" + embedContents + "</script>";
|
||||
} catch (e) {
|
||||
console.log("Failure: embed file does not exist!");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
crypto_tag: cryptoTag,
|
||||
decrypt_button: namedArgs.decryptButton,
|
||||
embed: namedArgs.embed,
|
||||
encrypted: encryptedMessage,
|
||||
instructions: namedArgs.instructions,
|
||||
is_remember_enabled: namedArgs.noremember ? 'false' : 'true',
|
||||
output_file_path: namedArgs.output !== null ? namedArgs.output : input.replace(/\.html$/, '') + "_encrypted.html",
|
||||
passphrase_placeholder: namedArgs.passphrasePlaceholder,
|
||||
remember_duration_in_days: namedArgs.remember,
|
||||
remember_me: namedArgs.rememberLabel,
|
||||
salt: salt,
|
||||
title: namedArgs.title,
|
||||
crypto_tag: cryptoTag,
|
||||
decrypt_button: namedArgs.decryptButton,
|
||||
embed: namedArgs.embed,
|
||||
encrypted: encryptedMessage,
|
||||
instructions: namedArgs.instructions,
|
||||
is_remember_enabled: namedArgs.noremember ? "false" : "true",
|
||||
output_file_path:
|
||||
namedArgs.output !== null
|
||||
? namedArgs.output
|
||||
: input.replace(/\.html$/, "") + "_encrypted.html",
|
||||
passphrase_placeholder: namedArgs.passphrasePlaceholder,
|
||||
remember_duration_in_days: namedArgs.remember,
|
||||
remember_me: namedArgs.rememberLabel,
|
||||
salt: salt,
|
||||
title: namedArgs.title,
|
||||
};
|
||||
|
||||
genFile(data);
|
||||
|
||||
|
||||
/**
|
||||
* Fill the template with provided data and writes it to output file.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
function genFile(data) {
|
||||
let templateContents;
|
||||
let templateContents;
|
||||
|
||||
try {
|
||||
templateContents = fs.readFileSync(namedArgs.f, 'utf8');
|
||||
} catch (e) {
|
||||
console.log("Failure: could not read template!");
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
templateContents = fs.readFileSync(namedArgs.f, "utf8");
|
||||
} catch (e) {
|
||||
console.log("Failure: could not read template!");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const renderedTemplate = render(templateContents, data);
|
||||
const renderedTemplate = render(templateContents, data);
|
||||
|
||||
try {
|
||||
fs.writeFileSync(data.output_file_path, renderedTemplate);
|
||||
} catch (e) {
|
||||
console.log("Failure: could not generate output file!");
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
fs.writeFileSync(data.output_file_path, renderedTemplate);
|
||||
} catch (e) {
|
||||
console.log("Failure: could not generate output file!");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,11 +307,11 @@ function genFile(data) {
|
|||
* @returns string
|
||||
*/
|
||||
function render(tpl, data) {
|
||||
return tpl.replace(/{(.*?)}/g, function (_, key) {
|
||||
if (data && data[key] !== undefined) {
|
||||
return data[key];
|
||||
}
|
||||
return tpl.replace(/{(.*?)}/g, function (_, key) {
|
||||
if (data && data[key] !== undefined) {
|
||||
return data[key];
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
|
||||
<script>
|
||||
// variables to be filled when generating the file
|
||||
var encryptedMsg = 'e70f668363afe4238c1e68d5c1481f6c2e7cab002412e7c7f721c74ebb80127355925315930ceca9be53a5f2bde4f7a8U2FsdGVkX1+SR7cHNx6YjSbLrCQdv2s20Gw6tPy68pjlUVh+UCqNGdJ3+Nh0DJVpy00/7ACSjp/noo2VlzPPJWMN6Oiks/ZO3H3TgA3Snfjzv22CDmOkmpIDaWgkias5Iw1RlQRufAoPJMqrLNwcLMAfifat0Ra31oZMpPYq1KIdXoqYsQkY8uR6IRdiA947UxenEo6qUg2VJuCIsg13kQ==',
|
||||
var encryptedMsg = '65a0577162396cc1bddae60b8f435291ff7a69644825b98bfc636a29089a28efbc9417689b983f2048bb776ca66eb25fU2FsdGVkX19n36H4ocM7GbaeFVganWX86ZTHEZk2w12z3z7rqWDW8OESK8MmGtbnPJetgyWi3jpz3iI+rE/gSilJkhQ2YR/4yCBintGLeh1hCgX+XPBEDT0w+ri4uqUWCxDUIvzyUhbnf1ZD2WsK9wmDHwRwF9YcucHXuyS7/GlUcVsYERzxxDd9frN6DbubNNbdY/QtG+vtmLSwHGZtwQ==',
|
||||
salt = 'b93bbaf35459951c47721d1f3eaeb5b9',
|
||||
isRememberEnabled = true,
|
||||
rememberDurationInDays = 0; // 0 means forever
|
10
index.html
10
index.html
|
@ -65,7 +65,7 @@
|
|||
</p>
|
||||
<p>
|
||||
Download your encrypted string in a HTML page with a password prompt you can upload anywhere (see <a
|
||||
target="_blank" href="example_encrypted.html">example</a>).
|
||||
target="_blank" href="example/example_encrypted.html">example</a>).
|
||||
</p>
|
||||
<p>
|
||||
The tool is also available as <a href="https://npmjs.com/package/staticrypt">a CLI on NPM</a> and is <a
|
||||
|
@ -208,11 +208,9 @@ Your encrypted string</pre>
|
|||
</div>
|
||||
|
||||
<!--
|
||||
Crypto JS 3.1.9-1
|
||||
Copied as is from https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js
|
||||
Filename changed to circumvent adblockers that mistake it for a crypto miner (see https://github.com/robinmoisson/staticrypt/issues/107)
|
||||
-->
|
||||
<script src="kryptojs-3.1.9-1-lib.js"></script>
|
||||
<script src="lib/kryptojs-3.1.9-1.min.js"></script>
|
||||
|
||||
<script src="https://cdn.ckeditor.com/4.7.0/standard/ckeditor.js"></script>
|
||||
|
||||
|
@ -238,7 +236,7 @@ Filename changed to circumvent adblockers that mistake it for a crypto miner (se
|
|||
*/
|
||||
var setFileToDownload = function (data) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', 'password_template.html', true);
|
||||
request.open('GET', 'lib/password_template.html', true);
|
||||
request.onload = function () {
|
||||
var renderedTmpl = renderTemplate(request.responseText, data);
|
||||
|
||||
|
@ -257,7 +255,7 @@ Filename changed to circumvent adblockers that mistake it for a crypto miner (se
|
|||
*/
|
||||
var setFileToDownloadWithEmbeddedCrypto = function (data) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', 'kryptojs-3.1.9-1-lib.js', true);
|
||||
request.open('GET', 'lib/kryptojs-3.1.9-1.min.js', true);
|
||||
request.onload = function () {
|
||||
data['crypto_tag'] = '<script>' + request.responseText + '</scr' + 'ipt>';
|
||||
setFileToDownload(data);
|
||||
|
|
Plik diff jest za duży
Load Diff
File diff suppressed because one or more lines are too long
|
@ -13,7 +13,7 @@
|
|||
"yargs": ">=10.0.3"
|
||||
},
|
||||
"bin": {
|
||||
"staticrypt": "index.js"
|
||||
"staticrypt": "cli/index.js"
|
||||
},
|
||||
"devDependencies": {}
|
||||
},
|
|
@ -4,12 +4,11 @@
|
|||
"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": [
|
||||
"index.js",
|
||||
"password_template.html",
|
||||
"crypto-js.min.js"
|
||||
"/cli",
|
||||
"/lib"
|
||||
],
|
||||
"bin": {
|
||||
"staticrypt": "./index.js"
|
||||
"staticrypt": "./cli/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"crypto-js": ">=3.1.9-1",
|
|
@ -1,11 +1,8 @@
|
|||
# Usage: `npm run build`
|
||||
# NPM establishes a reliable working directory
|
||||
|
||||
cd ..
|
||||
# Copy files that should be included in `npm publish`
|
||||
cp README.md LICENSE password_template.html cli/
|
||||
# Encrypt the example file
|
||||
npx ./cli example.html test \
|
||||
npx . example/example.html test \
|
||||
--no-embed \
|
||||
--salt b93bbaf35459951c47721d1f3eaeb5b9 \
|
||||
--instructions "Enter \"test\" to unlock the page"
|
Ładowanie…
Reference in New Issue