Skip to content

Commit

Permalink
add --share-remember to remember the password in shared links
Browse files Browse the repository at this point in the history
closes #183, closes #184. Thank you @uzadude!
  • Loading branch information
robinmoisson committed Feb 13, 2024
1 parent 2a44c59 commit 1e5e6cf
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 28 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ staticrypt dir_to_encrypt/* -r -d dir_to_encrypt
# you can also pass '--share' without specifying the URL to get the `#staticrypt_pwd=...`
staticrypt test.html --share https://example.com/encrypted.html
# => https://example.com/encrypted.html#staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f

# add --share-remember to auto-enable "Remember-me" - useful if you want send one link to autodecrypt multiple pages
# (you can also just append '&remember_me')
staticrypt test.html --share --share-remember
# => #staticrypt_pwd=5bfbf1343c7257cd7be23ecd74bb37fa2c76d041042654f358b6255baeab898f&remember_me
```

**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:
Expand Down Expand Up @@ -152,6 +157,8 @@ The password argument is optional if `STATICRYPT_PASSWORD` is set in the environ
as a value to append
"#staticrypt_pwd=<hashed_pwd>", or leave empty
to display the hash to append. [string]
--share-remember Whether the share link should auto-enable
'Remember-me'. [boolean] [default: false]
--short Hide the "short password" warning.
[boolean] [default: false]
-t, --template Path to custom HTML template with password
Expand Down
5 changes: 5 additions & 0 deletions cli/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,11 @@ function parseCommandLineArguments() {
'"#staticrypt_pwd=<hashed_pwd>", or leave empty to display the hash to append.',
type: "string",
})
.option("share-remember", {
type: "boolean",
describe: "Whether the share link should auto-enable 'Remember-me'.",
default: false,
})
.option("short", {
describe: 'Hide the "short password" warning.',
type: "boolean",
Expand Down
9 changes: 7 additions & 2 deletions cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,14 @@ async function runStatiCrypt() {
if (hasShareFlag) {
await validatePassword(password, namedArgs.short);

const url = namedArgs.share || "";
let url = namedArgs.share || "";
url += "#staticrypt_pwd=" + hashedPassword;

console.log(url + "#staticrypt_pwd=" + hashedPassword);
if (namedArgs.shareRemember) {
url += `&remember_me`;
}

console.log(url);
return;
}

Expand Down
30 changes: 21 additions & 9 deletions example/encrypted/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -610,11 +610,17 @@
* expose more information in the future we can do it without breaking the password_template
*/
async function handleDecryptionOfPage(password, isRememberChecked) {
const { isRememberEnabled, rememberDurationInDays, staticryptSaltUniqueVariableName } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
const { staticryptSaltUniqueVariableName } = staticryptConfig;

// decrypt and replace the whole page
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
return handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked);
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;

async function handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked) {
const { isRememberEnabled, rememberDurationInDays } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;

const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);

Expand Down Expand Up @@ -643,7 +649,7 @@
hashedPassword,
};
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;
exports.handleDecryptionOfPageFromHash = handleDecryptionOfPageFromHash;

/**
* Clear localstorage from staticrypt related values
Expand Down Expand Up @@ -740,21 +746,27 @@
return false;
}

function decryptOnLoadFromUrl() {
async function decryptOnLoadFromUrl() {
const passwordKey = "staticrypt_pwd";
const rememberMeKey = "remember_me";

// get the password from the query param
// try to get the password from the query param (for backward compatibility - we now want to avoid this method,
// since it sends the hashed password to the server which isn't needed)
const queryParams = new URLSearchParams(window.location.search);
const hashedPasswordQuery = queryParams.get(passwordKey);
const rememberMeQuery = queryParams.get(rememberMeKey);

const urlFragment = window.location.hash.substring(1);
// get the password from the url fragment
const hashRegexMatch = window.location.hash.substring(1).match(new RegExp(passwordKey + "=(.*)"));
const hashedPasswordFragment = hashRegexMatch ? hashRegexMatch[1] : null;
const hashedPasswordRegexMatch = urlFragment.match(new RegExp(passwordKey + "=([^&]*)"));
const hashedPasswordFragment = hashedPasswordRegexMatch ? hashedPasswordRegexMatch[1] : null;
const rememberMeFragment = urlFragment.includes(rememberMeKey);

const hashedPassword = hashedPasswordFragment || hashedPasswordQuery;
const rememberMe = rememberMeFragment || rememberMeQuery;

if (hashedPassword) {
return decryptAndReplaceHtml(hashedPassword);
return handleDecryptionOfPageFromHash(hashedPassword, rememberMe);
}

return false;
Expand All @@ -768,7 +780,7 @@
})());
const templateError = "Bad password!",
isRememberEnabled = true,
staticryptConfig = {"staticryptEncryptedMsgUniqueVariableName":"da67de28fb1fec9f04aaf615aa0e80a9675a43473e21b51a1dee72cb6153728dde06e9c242c6de08ab4608d18e73c9f922466a4695fe60e8f684f7d5d7b54149d7749bc2e626e39844d6757289f17696ea7992d1c87b49f76903c57d6506bb5aee0f0cdf4183bb20f71ad0f719c5a3ee338a486c70a1d433c00fd4384c2ec65471c436dc4cf0c4ba13a2189db1ee335f113652439c1feb2c02bf237ddada4ae46bd404f3f8417cc6b27d2e7960024afe2323edb19e8f38c699b9f4ce0db36d37","isRememberEnabled":true,"rememberDurationInDays":0,"staticryptSaltUniqueVariableName":"b93bbaf35459951c47721d1f3eaeb5b9"};
staticryptConfig = {"staticryptEncryptedMsgUniqueVariableName":"0aebc39457f31c757cef31f0fa9b2fb0cb4ebe9845a3690ab119002ae21ce5b7b200ded81ad6da56d0f6b98df029102c0913440135cd3f75b84f481ee32aab034c0bb3055168d6c49afd4b59e7189b539b573e6effbd29e403ef3234ab8bd1c2de1cd97a4f94e88c4d632f8648e9d99c7d988723634ce805d021d1d017c3e125e98e58914db31c4cca5a0f6b1f4464d284a48548a1eb5edad8f910aea4d2beee6b811785b556c7ec67c48112f551aa860614faf34887267c6119feda894b3ed8","isRememberEnabled":true,"rememberDurationInDays":0,"staticryptSaltUniqueVariableName":"b93bbaf35459951c47721d1f3eaeb5b9"};

// you can edit these values to customize some of the behavior of StatiCrypt
const templateConfig = {
Expand Down
28 changes: 20 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1101,11 +1101,17 @@ <h2>Encrypted HTML</h2>
* expose more information in the future we can do it without breaking the password_template
*/
async function handleDecryptionOfPage(password, isRememberChecked) {
const { isRememberEnabled, rememberDurationInDays, staticryptSaltUniqueVariableName } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
const { staticryptSaltUniqueVariableName } = staticryptConfig;

// decrypt and replace the whole page
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
return handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked);
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;

async function handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked) {
const { isRememberEnabled, rememberDurationInDays } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;

const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);

Expand Down Expand Up @@ -1134,7 +1140,7 @@ <h2>Encrypted HTML</h2>
hashedPassword,
};
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;
exports.handleDecryptionOfPageFromHash = handleDecryptionOfPageFromHash;

/**
* Clear localstorage from staticrypt related values
Expand Down Expand Up @@ -1231,21 +1237,27 @@ <h2>Encrypted HTML</h2>
return false;
}

function decryptOnLoadFromUrl() {
async function decryptOnLoadFromUrl() {
const passwordKey = "staticrypt_pwd";
const rememberMeKey = "remember_me";

// get the password from the query param
// try to get the password from the query param (for backward compatibility - we now want to avoid this method,
// since it sends the hashed password to the server which isn't needed)
const queryParams = new URLSearchParams(window.location.search);
const hashedPasswordQuery = queryParams.get(passwordKey);
const rememberMeQuery = queryParams.get(rememberMeKey);

const urlFragment = window.location.hash.substring(1);
// get the password from the url fragment
const hashRegexMatch = window.location.hash.substring(1).match(new RegExp(passwordKey + "=(.*)"));
const hashedPasswordFragment = hashRegexMatch ? hashRegexMatch[1] : null;
const hashedPasswordRegexMatch = urlFragment.match(new RegExp(passwordKey + "=([^&]*)"));
const hashedPasswordFragment = hashedPasswordRegexMatch ? hashedPasswordRegexMatch[1] : null;
const rememberMeFragment = urlFragment.includes(rememberMeKey);

const hashedPassword = hashedPasswordFragment || hashedPasswordQuery;
const rememberMe = rememberMeFragment || rememberMeQuery;

if (hashedPassword) {
return decryptAndReplaceHtml(hashedPassword);
return handleDecryptionOfPageFromHash(hashedPassword, rememberMe);
}

return false;
Expand Down
28 changes: 20 additions & 8 deletions lib/staticryptJs.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@ 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, staticryptSaltUniqueVariableName } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;
const { staticryptSaltUniqueVariableName } = staticryptConfig;

// decrypt and replace the whole page
const hashedPassword = await cryptoEngine.hashPassword(password, staticryptSaltUniqueVariableName);
return handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked);
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;

async function handleDecryptionOfPageFromHash(hashedPassword, isRememberChecked) {
const { isRememberEnabled, rememberDurationInDays } = staticryptConfig;
const { rememberExpirationKey, rememberPassphraseKey } = templateConfig;

const isDecryptionSuccessful = await decryptAndReplaceHtml(hashedPassword);

Expand Down Expand Up @@ -96,7 +102,7 @@ function init(staticryptConfig, templateConfig) {
hashedPassword,
};
}
exports.handleDecryptionOfPage = handleDecryptionOfPage;
exports.handleDecryptionOfPageFromHash = handleDecryptionOfPageFromHash;

/**
* Clear localstorage from staticrypt related values
Expand Down Expand Up @@ -193,21 +199,27 @@ function init(staticryptConfig, templateConfig) {
return false;
}

function decryptOnLoadFromUrl() {
async function decryptOnLoadFromUrl() {
const passwordKey = "staticrypt_pwd";
const rememberMeKey = "remember_me";

// get the password from the query param
// try to get the password from the query param (for backward compatibility - we now want to avoid this method,
// since it sends the hashed password to the server which isn't needed)
const queryParams = new URLSearchParams(window.location.search);
const hashedPasswordQuery = queryParams.get(passwordKey);
const rememberMeQuery = queryParams.get(rememberMeKey);

const urlFragment = window.location.hash.substring(1);
// get the password from the url fragment
const hashRegexMatch = window.location.hash.substring(1).match(new RegExp(passwordKey + "=(.*)"));
const hashedPasswordFragment = hashRegexMatch ? hashRegexMatch[1] : null;
const hashedPasswordRegexMatch = urlFragment.match(new RegExp(passwordKey + "=([^&]*)"));
const hashedPasswordFragment = hashedPasswordRegexMatch ? hashedPasswordRegexMatch[1] : null;
const rememberMeFragment = urlFragment.includes(rememberMeKey);

const hashedPassword = hashedPasswordFragment || hashedPasswordQuery;
const rememberMe = rememberMeFragment || rememberMeQuery;

if (hashedPassword) {
return decryptAndReplaceHtml(hashedPassword);
return handleDecryptionOfPageFromHash(hashedPassword, rememberMe);
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "staticrypt",
"version": "3.3.2",
"version": "3.4.0",
"description": "Baed 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": [
Expand Down

0 comments on commit 1e5e6cf

Please sign in to comment.