diff options
-rw-r--r-- | include/bbcode.php | 40 | ||||
-rw-r--r-- | view/js/crypto.js | 38 |
2 files changed, 48 insertions, 30 deletions
diff --git a/include/bbcode.php b/include/bbcode.php index b39822b05..20a866073 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -246,38 +246,45 @@ function bb_replace_images($body, $images) { function bb_parse_crypt($match) { $matches = []; - $attributes = $match[1]; $hint = ''; $algorithm = ''; + $payload = $match[1]; + + if (isset($match[2])) { + // backwards compatibility - preg_match("/alg='(.*?)'/ism", $attributes, $matches); - $algorithm = $matches[1] ?? ''; + $attributes = $match[1]; + $payload = $match[2]; - if (!$algorithm) { - preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches); + preg_match("/alg='(.*?)'/ism", $attributes, $matches); $algorithm = $matches[1] ?? ''; - } - preg_match("/hint='(.*?)'/ism", $attributes, $matches); - $hint = $matches[1] ?? ''; + if (!$algorithm) { + preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches); + $algorithm = $matches[1] ?? ''; + } - if (!$hint) { - preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches); + preg_match("/hint='(.*?)'/ism", $attributes, $matches); $hint = $matches[1] ?? ''; + + if (!$hint) { + preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches); + $hint = $matches[1] ?? ''; + } } - $x = random_string(); + $x = random_string(32); - $f = 'sodium_decrypt'; + $onclick = 'onclick="sodium_decrypt(\'' . $payload . '\',\'#' . $x . '\');"'; if (in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) { - $f = 'hz_decrypt'; // deprecated + // backwards compatibility + $onclick = 'onclick="hz_decrypt(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $payload . '\',\'#' . $x . '\');"'; } - $onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"'; $label = t('Encrypted content'); - $text = '<br /><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br />'; + $text = '<div id="' . $x . '" class="encrypted-content"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div>'; return $text; } @@ -1627,8 +1634,7 @@ function bbcode($text, $options = []) { // crypt if (strpos($text,'[/crypt]') !== false) { - $x = random_string(); - $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'<br /><div id="' . $x . '"><img class="cursor-pointer" src="' .z_root() . '/images/lock_icon.svg" onclick="red_decrypt(\'rot13\',\'\',\'$1\',\'#' . $x . '\');" alt="' . t('Encrypted content') . '" title="' . t('Encrypted content') . '" /><br /></div>', $text); + $text = preg_replace_callback("/\[crypt\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $text); $text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $text); } diff --git a/view/js/crypto.js b/view/js/crypto.js index 55b9aea11..bc399caa3 100644 --- a/view/js/crypto.js +++ b/view/js/crypto.js @@ -25,6 +25,11 @@ async function sodium_encrypt(element) { } let message = $(element).val(); + + if (!message) { + return false; + } + let password = prompt(aStr['passphrase']); if (!password) { @@ -35,6 +40,7 @@ async function sodium_encrypt(element) { let salt = await sodium.randombytes_buf(16); let nonce = await sodium.randombytes_buf(24); + let key = await sodium.crypto_pwhash( 32, password, @@ -47,31 +53,37 @@ async function sodium_encrypt(element) { let ciphertext = await sodium.crypto_secretbox(message, nonce, key); delete message, password, key; - let s = await sodium.sodium_bin2hex(salt); - let n = await sodium.sodium_bin2hex(nonce); - let c = await sodium.sodium_bin2hex(ciphertext); - let encrypted = window.btoa(s + '.' + n + '.' + c); - let val = "[crypt alg='XSalsa20' hint='" + hint + "']" + encrypted + '[/crypt]'; + let payload = { + hint: hint, + alg: 'XSalsa20', + salt: await sodium.sodium_bin2hex(salt), + nonce: await sodium.sodium_bin2hex(nonce), + ciphertext: await sodium.sodium_bin2hex(ciphertext) + }; + + let val = "[crypt]" + window.btoa(JSON.stringify(payload)) + '[/crypt]'; $(element).val(val); } -async function sodium_decrypt(alg, hint, encrypted, element) { - if (alg !== 'XSalsa20') { +async function sodium_decrypt(payload, element) { + let arr = JSON.parse(window.atob(payload)); + + if (arr.alg !== 'XSalsa20') { alert('Unsupported algorithm'); return false; } - let arr = window.atob(encrypted).split('.'); - let salt = await sodium.sodium_hex2bin(arr[0]); - let nonce = await sodium.sodium_hex2bin(arr[1]); - let ciphertext = await sodium.sodium_hex2bin(arr[2]); - let password = prompt((hint.length) ? hex2bin(hint) : aStr['passphrase']); + let password = prompt((arr.hint.length) ? hex2bin(arr.hint) : aStr['passphrase']); if (!password) { return false; } + let salt = await sodium.sodium_hex2bin(arr.salt); + let nonce = await sodium.sodium_hex2bin(arr.nonce); + let ciphertext = await sodium.sodium_hex2bin(arr.ciphertext); + let key = await sodium.crypto_pwhash( 32, password, @@ -84,7 +96,7 @@ async function sodium_decrypt(alg, hint, encrypted, element) { delete password, key; if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) { - tinyMCE.activeEditor.setContent(newdiv); + tinyMCE.activeEditor.setContent(decrypted.toString('utf-8')); } else { $(element).html(decrypted.toString('utf-8')); |