mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-04 13:45:42 -04:00
326 lines
11 KiB
JavaScript
326 lines
11 KiB
JavaScript
/* encryptcontent/decrypt-contents.tpl.js */
|
|
|
|
function base64url_decode(input) {
|
|
try {
|
|
const binString = atob(input.replace(/-/g, '+').replace(/_/g, '/'));
|
|
const binArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
return new TextDecoder().decode(binArray);
|
|
}
|
|
catch (err) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
|
|
try {
|
|
let keystore = JSON.parse(key.toString(CryptoJS.enc.Utf8));
|
|
if (encryptcontent_id in keystore) {
|
|
return keystore;
|
|
} else {
|
|
//id not found in keystore
|
|
return false;
|
|
}
|
|
} catch (err) {
|
|
// encoding failed; wrong password
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/* Split key bundle and try to decrypt it */
|
|
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);
|
|
}
|
|
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]);
|
|
if (keys) {
|
|
|
|
return keys;
|
|
}
|
|
} else if (parts.length == 4 && username) {
|
|
if (parts[3] == userhash) {
|
|
keys = decrypt_key(pass, parts[0], parts[1], parts[2]);
|
|
if (keys) {
|
|
|
|
return keys;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/* 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
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/* Split cyphertext bundle and try to decrypt it */
|
|
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 false;
|
|
};
|
|
|
|
/* Save decrypted keystore to sessionStorage */
|
|
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) {
|
|
sessionStorage.removeItem(key);
|
|
};
|
|
|
|
function getItemName(key) {
|
|
return sessionStorage.getItem(key);
|
|
};
|
|
|
|
/* Reload scripts src after decryption process */
|
|
function reload_js(src) {
|
|
let script_src, script_tag, new_script_tag;
|
|
let head = document.getElementsByTagName('head')[0];
|
|
|
|
if (src.startsWith('#')) {
|
|
script_tag = document.getElementById(src.substr(1));
|
|
if (script_tag) {
|
|
script_tag.remove();
|
|
new_script_tag = document.createElement('script');
|
|
if (script_tag.innerHTML) {
|
|
new_script_tag.innerHTML = script_tag.innerHTML;
|
|
}
|
|
if (script_tag.src) {
|
|
new_script_tag.src = script_tag.src;
|
|
}
|
|
if (script_tag.type) {
|
|
new_script_tag.type = script_tag.type;
|
|
}
|
|
head.appendChild(new_script_tag);
|
|
}
|
|
} else {
|
|
if (base_url == '.') {
|
|
script_src = src;
|
|
} else {
|
|
script_src = base_url + '/' + src;
|
|
}
|
|
|
|
script_tag = document.querySelector('script[src="' + script_src + '"]');
|
|
if (script_tag) {
|
|
script_tag.remove();
|
|
new_script_tag = document.createElement('script');
|
|
new_script_tag.src = script_src;
|
|
head.appendChild(new_script_tag);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/* Decrypt speficique html entry from mkdocs configuration */
|
|
function decrypt_somethings(key, encrypted_something) {
|
|
var html_item = '';
|
|
for (const [name, tag] of Object.entries(encrypted_something)) {
|
|
if (tag[1] == 'id') {
|
|
html_item = [document.getElementById(name)];
|
|
} else if (tag[1] == 'class') {
|
|
html_item = document.getElementsByClassName(name);
|
|
} else {
|
|
console.log('WARNING: Unknow tag html found, check "encrypted_something" configuration.');
|
|
}
|
|
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 (content !== false) {
|
|
// success; display the decrypted content
|
|
html_item[i].innerHTML = content;
|
|
html_item[i].style.display = null;
|
|
// any post processing on the decrypted content should be done here
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return html_item[0];
|
|
};
|
|
|
|
/* Decrypt content of a page */
|
|
function decrypt_action(username_input, password_input, encrypted_content, decrypted_content, key_from_storage=false) {
|
|
let key=false;
|
|
let keys_from_keystore=false;
|
|
|
|
let user=false;
|
|
if (username_input) {
|
|
user = username_input.value;
|
|
}
|
|
|
|
if (key_from_storage !== false) {
|
|
key = key_from_storage;
|
|
} else {
|
|
keys_from_keystore = decrypt_key_from_bundle(password_input.value, encryptcontent_keystore, user);
|
|
if (keys_from_keystore) {
|
|
key = keys_from_keystore[encryptcontent_id];
|
|
}
|
|
}
|
|
|
|
let content = false;
|
|
if (key) {
|
|
content = decrypt_content_from_bundle(key, encrypted_content.innerHTML);
|
|
}
|
|
if (content !== false) {
|
|
// success; display the decrypted content
|
|
decrypted_content.innerHTML = content;
|
|
encrypted_content.parentNode.removeChild(encrypted_content);
|
|
|
|
if (keys_from_keystore !== false) {
|
|
return keys_from_keystore
|
|
} else {
|
|
return key
|
|
}
|
|
} else {
|
|
return false
|
|
}
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
// continue to decrypt others parts
|
|
|
|
if (typeof inject_something !== 'undefined') {
|
|
decrypted_content = decrypt_somethings(key, inject_something);
|
|
}
|
|
if (typeof delete_something !== 'undefined') {
|
|
let el = document.getElementById(delete_something)
|
|
if (el) {
|
|
el.remove();
|
|
}
|
|
}
|
|
// any post processing on the decrypted content should be done here
|
|
document$.next(document);
|
|
|
|
if (typeof theme_run_after_decryption !== 'undefined') {
|
|
theme_run_after_decryption();
|
|
}
|
|
if (window.location.hash) { //jump to anchor if hash given after decryption
|
|
window.location.href = window.location.hash;
|
|
}
|
|
} else {
|
|
// remove item on sessionStorage if decryption process fail (Invalid item)
|
|
if (!fallback_used) {
|
|
if (!encryptcontent_obfuscate) {
|
|
// create HTML element for the inform message
|
|
let mkdocs_decrypt_msg = document.getElementById('mkdocs-decrypt-msg');
|
|
mkdocs_decrypt_msg.textContent = decryption_failure_message;
|
|
password_input.value = '';
|
|
password_input.focus();
|
|
}
|
|
}
|
|
delItemName(encryptcontent_id);
|
|
}
|
|
}
|
|
|
|
/* Trigger decryption process */
|
|
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
|
|
//if (password_input.hasAttribute('placeholder')) {
|
|
// password_input.setAttribute('size', password_input.getAttribute('placeholder').length);
|
|
//}
|
|
let encrypted_content = document.getElementById('mkdocs-encrypted-content');
|
|
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);
|
|
if (key_from_storage) {
|
|
content_decrypted = decrypt_action(
|
|
username_input, password_input, encrypted_content, decrypted_content, key_from_storage
|
|
);
|
|
|
|
decryptor_reaction(content_decrypted, password_input, decrypted_content, true);
|
|
}
|
|
|
|
/* 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) {
|
|
event.preventDefault();
|
|
content_decrypted = 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) {
|
|
if (event.key === "Enter") {
|
|
event.preventDefault();
|
|
content_decrypted = decrypt_action(
|
|
username_input, password_input, encrypted_content, decrypted_content
|
|
);
|
|
decryptor_reaction(content_decrypted, password_input, decrypted_content);
|
|
}
|
|
});
|
|
}
|
|
if (typeof base_url === 'undefined') {
|
|
var base_url = JSON.parse(document.getElementById('__config').textContent).base;
|
|
}
|
|
if (document.readyState === "loading") {
|
|
// Loading hasn't finished yet
|
|
document.addEventListener("DOMContentLoaded", init_decryptor);
|
|
} else {
|
|
// `DOMContentLoaded` has already fired
|
|
init_decryptor();
|
|
}
|
|
window["init_decryptor"] = init_decryptor; |