mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-04 08:55:41 -04:00
deploy: d4abc705a0
This commit is contained in:
@@ -1,4 +1,20 @@
|
||||
/* encryptcontent/decrypt-contents.tpl.js */
|
||||
// https://stackoverflow.com/a/50868276
|
||||
function fromHex(hexString) {
|
||||
return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
||||
}
|
||||
// https://stackoverflow.com/a/41106346
|
||||
function fromBase64(base64String) {
|
||||
return Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
async function digestSHA256toBase64(message) {
|
||||
const data = new TextEncoder().encode(message);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||
const hashArray = new Uint8Array(hashBuffer);
|
||||
const hashString = String.fromCharCode.apply(null, hashArray);
|
||||
return btoa(hashString);
|
||||
};
|
||||
|
||||
function base64url_decode(input) {
|
||||
try {
|
||||
@@ -12,52 +28,75 @@ function base64url_decode(input) {
|
||||
}
|
||||
|
||||
/* Decrypts the key from the key bundle. */
|
||||
function decrypt_key(pass, iv_b64, ciphertext_b64, salt_b64) {
|
||||
let salt = CryptoJS.enc.Base64.parse(salt_b64),
|
||||
kdfcfg = {keySize: 256 / 32,hasher: CryptoJS.algo.SHA256,iterations: encryptcontent_obfuscate ? 1 : 10000};
|
||||
let kdfkey = CryptoJS.PBKDF2(pass, salt,kdfcfg);
|
||||
let iv = CryptoJS.enc.Base64.parse(iv_b64),
|
||||
ciphertext = CryptoJS.enc.Base64.parse(ciphertext_b64);
|
||||
let encrypted = {ciphertext: ciphertext},
|
||||
cfg = {iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7};
|
||||
let key = CryptoJS.AES.decrypt(encrypted, kdfkey, cfg);
|
||||
|
||||
async function decrypt_key(pass, iv_b64, ciphertext_b64, salt_b64) {
|
||||
const salt = fromBase64(salt_b64);
|
||||
const encPassword = new TextEncoder().encode(pass);
|
||||
const kdfkey = await window.crypto.subtle.importKey(
|
||||
"raw",
|
||||
encPassword,
|
||||
"PBKDF2",
|
||||
false,
|
||||
["deriveKey"],
|
||||
);
|
||||
const wckey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: "PBKDF2",
|
||||
salt,
|
||||
iterations: encryptcontent_obfuscate ? 1 : 100000,
|
||||
hash: "SHA-256",
|
||||
},
|
||||
kdfkey,
|
||||
{ name: "AES-CBC", length: 256 },
|
||||
true,
|
||||
["decrypt"],
|
||||
);
|
||||
const ciphertext = fromBase64(ciphertext_b64);
|
||||
const iv = fromBase64(iv_b64);
|
||||
try {
|
||||
let keystore = JSON.parse(key.toString(CryptoJS.enc.Utf8));
|
||||
const decrypted = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: iv
|
||||
},
|
||||
wckey,
|
||||
ciphertext
|
||||
);
|
||||
const keystore = JSON.parse(new TextDecoder().decode(decrypted));
|
||||
if (encryptcontent_id in keystore) {
|
||||
return keystore;
|
||||
} else {
|
||||
//id not found in keystore
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
// encoding failed; wrong password
|
||||
}
|
||||
catch (err) {
|
||||
// encoding failed; wrong key
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* Split key bundle and try to decrypt it */
|
||||
function decrypt_key_from_bundle(password, ciphertext_bundle, username) {
|
||||
async function decrypt_key_from_bundle(password, ciphertext_bundle, username) {
|
||||
// grab the ciphertext bundle and try to decrypt it
|
||||
let user, pass;
|
||||
let parts, keys, userhash;
|
||||
if (ciphertext_bundle) {
|
||||
if (username) {
|
||||
user = encodeURIComponent(username.toLowerCase());
|
||||
userhash = CryptoJS.SHA256(user).toString(CryptoJS.enc.Base64);
|
||||
userhash = await digestSHA256toBase64(user);
|
||||
}
|
||||
for (let i = 0; i < ciphertext_bundle.length; i++) {
|
||||
pass = encodeURIComponent(password);
|
||||
parts = ciphertext_bundle[i].split(';');
|
||||
if (parts.length == 3) {
|
||||
keys = decrypt_key(pass, parts[0], parts[1], parts[2]);
|
||||
keys = await decrypt_key(pass, parts[0], parts[1], parts[2]);
|
||||
if (keys) {
|
||||
|
||||
return keys;
|
||||
}
|
||||
} else if (parts.length == 4 && username) {
|
||||
if (parts[3] == userhash) {
|
||||
keys = decrypt_key(pass, parts[0], parts[1], parts[2]);
|
||||
keys = await decrypt_key(pass, parts[0], parts[1], parts[2]);
|
||||
if (keys) {
|
||||
|
||||
return keys;
|
||||
@@ -70,55 +109,65 @@ function decrypt_key_from_bundle(password, ciphertext_bundle, username) {
|
||||
};
|
||||
|
||||
/* Decrypts the content from the ciphertext bundle. */
|
||||
function decrypt_content(key, iv_b64, ciphertext_b64) {
|
||||
let iv = CryptoJS.enc.Base64.parse(iv_b64),
|
||||
ciphertext = CryptoJS.enc.Base64.parse(ciphertext_b64);
|
||||
let encrypted = {ciphertext: ciphertext},
|
||||
cfg = {iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7};
|
||||
let plaintext = CryptoJS.AES.decrypt(encrypted, CryptoJS.enc.Hex.parse(key), cfg);
|
||||
if(plaintext.sigBytes >= 0) {
|
||||
try {
|
||||
return plaintext.toString(CryptoJS.enc.Utf8)
|
||||
} catch (err) {
|
||||
// encoding failed; wrong key
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// negative sigBytes; wrong key
|
||||
async function decrypt_content(key, iv_b64, ciphertext_b64) {
|
||||
const rawKey = fromHex(key);
|
||||
const iv = fromBase64(iv_b64);
|
||||
const ciphertext = fromBase64(ciphertext_b64);
|
||||
try {
|
||||
const wckey = await window.crypto.subtle.importKey(
|
||||
"raw",
|
||||
rawKey,
|
||||
"AES-CBC",
|
||||
true,
|
||||
["decrypt"]
|
||||
);
|
||||
const decrypted = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: iv
|
||||
},
|
||||
wckey,
|
||||
ciphertext
|
||||
);
|
||||
const decoder = new TextDecoder();
|
||||
return decoder.decode(decrypted);
|
||||
}
|
||||
catch (err) {
|
||||
// encoding failed; wrong key
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* Split cyphertext bundle and try to decrypt it */
|
||||
function decrypt_content_from_bundle(key, ciphertext_bundle) {
|
||||
async function decrypt_content_from_bundle(key, ciphertext_bundle) {
|
||||
// grab the ciphertext bundle and try to decrypt it
|
||||
if (ciphertext_bundle) {
|
||||
let parts = ciphertext_bundle.split(';');
|
||||
if (parts.length == 2) {
|
||||
return decrypt_content(key, parts[0], parts[1]);
|
||||
return await decrypt_content(key, parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/* Save decrypted keystore to sessionStorage */
|
||||
function setKeys(keys_from_keystore) {
|
||||
async function setKeys(keys_from_keystore) {
|
||||
for (const id in keys_from_keystore) {
|
||||
sessionStorage.setItem(id, keys_from_keystore[id]);
|
||||
}
|
||||
};
|
||||
|
||||
/* Delete key with specific name in sessionStorage */
|
||||
function delItemName(key) {
|
||||
async function delItemName(key) {
|
||||
sessionStorage.removeItem(key);
|
||||
};
|
||||
|
||||
function getItemName(key) {
|
||||
async function getItemName(key) {
|
||||
return sessionStorage.getItem(key);
|
||||
};
|
||||
|
||||
/* Reload scripts src after decryption process */
|
||||
function reload_js(src) {
|
||||
async function reload_js(src) {
|
||||
let script_src, script_tag, new_script_tag;
|
||||
let head = document.getElementsByTagName('head')[0];
|
||||
|
||||
@@ -155,10 +204,8 @@ function reload_js(src) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Decrypt speficique html entry from mkdocs configuration */
|
||||
function decrypt_somethings(key, encrypted_something) {
|
||||
async function decrypt_somethings(key, encrypted_something) {
|
||||
var html_item = '';
|
||||
for (const [name, tag] of Object.entries(encrypted_something)) {
|
||||
if (tag[1] == 'id') {
|
||||
@@ -171,8 +218,8 @@ function decrypt_somethings(key, encrypted_something) {
|
||||
if (html_item[0]) {
|
||||
for (let i = 0; i < html_item.length; i++) {
|
||||
// grab the cipher bundle if something exist
|
||||
if (html_item[i].style.display == "none") {
|
||||
let content = decrypt_content_from_bundle(key, html_item[i].innerHTML);
|
||||
if (String(html_item[i].style.display).startsWith("none")) {
|
||||
let content = await decrypt_content_from_bundle(key, html_item[i].innerHTML);
|
||||
if (content !== false) {
|
||||
// success; display the decrypted content
|
||||
html_item[i].innerHTML = content;
|
||||
@@ -187,7 +234,7 @@ function decrypt_somethings(key, encrypted_something) {
|
||||
};
|
||||
|
||||
/* Decrypt content of a page */
|
||||
function decrypt_action(username_input, password_input, encrypted_content, decrypted_content, key_from_storage=false) {
|
||||
async function decrypt_action(username_input, password_input, encrypted_content, decrypted_content, key_from_storage=false) {
|
||||
let key=false;
|
||||
let keys_from_keystore=false;
|
||||
|
||||
@@ -199,7 +246,7 @@ function decrypt_action(username_input, password_input, encrypted_content, decry
|
||||
if (key_from_storage !== false) {
|
||||
key = key_from_storage;
|
||||
} else {
|
||||
keys_from_keystore = decrypt_key_from_bundle(password_input.value, encryptcontent_keystore, user);
|
||||
keys_from_keystore = await decrypt_key_from_bundle(password_input.value, encryptcontent_keystore, user);
|
||||
if (keys_from_keystore) {
|
||||
key = keys_from_keystore[encryptcontent_id];
|
||||
}
|
||||
@@ -207,7 +254,7 @@ function decrypt_action(username_input, password_input, encrypted_content, decry
|
||||
|
||||
let content = false;
|
||||
if (key) {
|
||||
content = decrypt_content_from_bundle(key, encrypted_content.innerHTML);
|
||||
content = await decrypt_content_from_bundle(key, encrypted_content.innerHTML);
|
||||
}
|
||||
if (content !== false) {
|
||||
// success; display the decrypted content
|
||||
@@ -224,13 +271,12 @@ function decrypt_action(username_input, password_input, encrypted_content, decry
|
||||
}
|
||||
};
|
||||
|
||||
function decryptor_reaction(key_or_keys, password_input, decrypted_content, fallback_used=false) {
|
||||
async function decryptor_reaction(key_or_keys, password_input, decrypted_content, fallback_used=false) {
|
||||
if (key_or_keys) {
|
||||
let key;
|
||||
if (typeof key_or_keys === "object") {
|
||||
key = key_or_keys[encryptcontent_id];
|
||||
setKeys(key_or_keys);
|
||||
|
||||
} else {
|
||||
key = key_or_keys;
|
||||
}
|
||||
@@ -238,7 +284,7 @@ function decryptor_reaction(key_or_keys, password_input, decrypted_content, fall
|
||||
// continue to decrypt others parts
|
||||
|
||||
if (typeof inject_something !== 'undefined') {
|
||||
decrypted_content = decrypt_somethings(key, inject_something);
|
||||
decrypted_content = await decrypt_somethings(key, inject_something);
|
||||
}
|
||||
if (typeof delete_something !== 'undefined') {
|
||||
let el = document.getElementById(delete_something)
|
||||
@@ -255,6 +301,9 @@ function decryptor_reaction(key_or_keys, password_input, decrypted_content, fall
|
||||
if (window.location.hash) { //jump to anchor if hash given after decryption
|
||||
window.location.href = window.location.hash;
|
||||
}
|
||||
//If we got keys then dispatch encryptcontent_event
|
||||
encryptcontent_done = true;
|
||||
window.dispatchEvent(encryptcontent_event);
|
||||
} else {
|
||||
// remove item on sessionStorage if decryption process fail (Invalid item)
|
||||
if (!fallback_used) {
|
||||
@@ -271,7 +320,7 @@ function decryptor_reaction(key_or_keys, password_input, decrypted_content, fall
|
||||
}
|
||||
|
||||
/* Trigger decryption process */
|
||||
function init_decryptor() {
|
||||
async function init_decryptor() {
|
||||
let username_input = document.getElementById('mkdocs-content-user');
|
||||
let password_input = document.getElementById('mkdocs-content-password');
|
||||
// adjust password field width to placeholder length
|
||||
@@ -282,31 +331,36 @@ function init_decryptor() {
|
||||
let decrypted_content = document.getElementById('mkdocs-decrypted-content');
|
||||
let content_decrypted;
|
||||
/* If remember_keys is set, try to use sessionStorage item to decrypt content when page is loaded */
|
||||
let key_from_storage = getItemName(encryptcontent_id);
|
||||
let key_from_storage = await getItemName(encryptcontent_id);
|
||||
if (key_from_storage) {
|
||||
content_decrypted = decrypt_action(
|
||||
content_decrypted = await decrypt_action(
|
||||
username_input, password_input, encrypted_content, decrypted_content, key_from_storage
|
||||
);
|
||||
|
||||
decryptor_reaction(content_decrypted, password_input, decrypted_content, true);
|
||||
}
|
||||
|
||||
|
||||
if (!content_decrypted) {
|
||||
//If nothing got decrypted, still dispatch encryptcontent_event
|
||||
encryptcontent_done = true;
|
||||
window.dispatchEvent(encryptcontent_event);
|
||||
}
|
||||
/* If password_button is set, try decrypt content when button is press */
|
||||
let decrypt_button = document.getElementById("mkdocs-decrypt-button");
|
||||
if (decrypt_button) {
|
||||
decrypt_button.onclick = function(event) {
|
||||
decrypt_button.onclick = async function(event) {
|
||||
event.preventDefault();
|
||||
content_decrypted = decrypt_action(
|
||||
content_decrypted = await decrypt_action(
|
||||
username_input, password_input, encrypted_content, decrypted_content
|
||||
);
|
||||
decryptor_reaction(content_decrypted, password_input, decrypted_content);
|
||||
};
|
||||
}
|
||||
/* Default, try decrypt content when key enter is press */
|
||||
password_input.addEventListener('keypress', function(event) {
|
||||
password_input.addEventListener('keypress', async function(event) {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
content_decrypted = decrypt_action(
|
||||
content_decrypted = await decrypt_action(
|
||||
username_input, password_input, encrypted_content, decrypted_content
|
||||
);
|
||||
decryptor_reaction(content_decrypted, password_input, decrypted_content);
|
||||
|
||||
Reference in New Issue
Block a user