From 6fcd82fb85f277f9e974a62763024d7958ff218d Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 27 Aug 2019 07:38:27 +0200 Subject: [PATCH 01/24] making the feature detection more robust, let users with no WASM create uncompressed pastes, remove dead & duplicate code --- i18n/bg.json | 4 +- i18n/cs.json | 4 +- i18n/de.json | 4 +- i18n/es.json | 4 +- i18n/fr.json | 4 +- i18n/hu.json | 4 +- i18n/it.json | 4 +- i18n/nl.json | 4 +- i18n/no.json | 4 +- i18n/oc.json | 4 +- i18n/pl.json | 4 +- i18n/pt.json | 4 +- i18n/ru.json | 4 +- i18n/sl.json | 4 +- i18n/zh.json | 4 +- js/privatebin.js | 107 ++++++++++++++++++++++++------------------- js/test/CryptTool.js | 3 ++ tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 19 files changed, 110 insertions(+), 64 deletions(-) diff --git a/i18n/bg.json b/i18n/bg.json index c51ab0f4b..07a929c1e 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "Вижте тази страница за повече информация.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Браузъра ви може да се нуждае от HTTPS връзка за да използва WebCrypto API. Пробвай да минеш на HTTPS." + "Браузъра ви може да се нуждае от HTTPS връзка за да използва WebCrypto API. Пробвай да минеш на HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/cs.json b/i18n/cs.json index a36ef8baf..365d61100 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/de.json b/i18n/de.json index 3f99404f9..a89f82080 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "Besuche diesen FAQ Eintrag für weitere Informationen dazu.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Dein Browser benötigt möglicherweise eine HTTPS Verbindung um das WebCrypto API nutzen zu können. Versuche auf HTTPS zu wechseln." + "Dein Browser benötigt möglicherweise eine HTTPS Verbindung um das WebCrypto API nutzen zu können. Versuche auf HTTPS zu wechseln.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Dein Browser unterstützt WebAssembly nicht, welches für zlib Komprimierung benötigt wird. Du kannst unkomprimierte Dokumente erzeugen, aber keine komprimierten lesen." } diff --git a/i18n/es.json b/i18n/es.json index 6dd9e9125..de6fa543e 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/fr.json b/i18n/fr.json index fabb1d297..bebd18573 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -170,5 +170,7 @@ "For more information see this FAQ entry.": "Pour plus d'informations consultez cette rubrique de la FAQ.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Votre navigateur peut nécessiter une connexion HTTPS pour prendre en charge l’API WebCrypto. Essayez de passer en HTTPS." + "Votre navigateur peut nécessiter une connexion HTTPS pour prendre en charge l’API WebCrypto. Essayez de passer en HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/hu.json b/i18n/hu.json index da2dd5253..cf1fe02be 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/it.json b/i18n/it.json index 125812fa9..22f6838a6 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/nl.json b/i18n/nl.json index 4c93d7841..00aea3b72 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/no.json b/i18n/no.json index 108ce8d3a..9f9fa62e5 100644 --- a/i18n/no.json +++ b/i18n/no.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/oc.json b/i18n/oc.json index ec81c89bb..6cd33cabf 100644 --- a/i18n/oc.json +++ b/i18n/oc.json @@ -170,5 +170,7 @@ "For more information see this FAQ entry.": "Per mai d’informacions vejatz aqueste article de FAQ.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Se pòt que vòstre navigator faga besonh d’una connexion HTTPS per èsser compatible amb l’API WebCrypto. Ensajatz de passar al HTTPS." + "Se pòt que vòstre navigator faga besonh d’una connexion HTTPS per èsser compatible amb l’API WebCrypto. Ensajatz de passar al HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/pl.json b/i18n/pl.json index f1ae43f08..3be5baa0c 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/pt.json b/i18n/pt.json index f7b7e0bb6..3ff603e08 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/ru.json b/i18n/ru.json index d25b3465e..66d413c77 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -171,5 +171,7 @@ "For more information see this FAQ entry.": "Для продробностей прочтите информацию в FAQ.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Ваш браузер требует использования HTTPS подключения для поддержки WebCrypto API. Попробуйте переключиться на HTTPS." + "Ваш браузер требует использования HTTPS подключения для поддержки WebCrypto API. Попробуйте переключиться на HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/sl.json b/i18n/sl.json index e88961d04..5e61d1977 100644 --- a/i18n/sl.json +++ b/i18n/sl.json @@ -170,5 +170,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/i18n/zh.json b/i18n/zh.json index 2e2c7de98..2577b55a9 100644 --- a/i18n/zh.json +++ b/i18n/zh.json @@ -161,5 +161,7 @@ "For more information see this FAQ entry.": "For more information see this FAQ entry.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS." + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones." } diff --git a/js/privatebin.js b/js/privatebin.js index b141779be..c990c3590 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -789,7 +789,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { utf16To8(message) ); if (mode === 'zlib') { - return z.deflate(message).buffer; + let zlib = (await z); + return zlib.deflate(message).buffer; } return message; } @@ -809,7 +810,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { { if (mode === 'zlib' || mode === 'none') { if (mode === 'zlib') { - data = z.inflate( + let zlib = (await z); + if (typeof zlib === 'undefined') { + Alert.showError('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.') + return ''; + } + data = zlib.inflate( new Uint8Array(data) ).buffer; } @@ -883,7 +889,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { stringToArraybuffer( utf16To8(password) ) - ); + ).catch(Alert.showError); password = Array.prototype.map.call( new Uint8Array(passwordBuffer), x => ('00' + x.toString(16)).slice(-2) @@ -903,7 +909,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { {name: 'PBKDF2'}, // we use PBKDF2 for key derivation false, // the key may not be exported ['deriveKey'] // we may only use it for key derivation - ); + ).catch(Alert.showError); // derive a stronger key for use with AES return window.crypto.subtle.deriveKey( @@ -920,7 +926,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }, false, // the key may not be exported ['encrypt', 'decrypt'] // we may only use it for en- and decryption - ); + ).catch(Alert.showError); } /** @@ -959,16 +965,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { { // AES in Galois Counter Mode, keysize 256 bit, // authentication tag 128 bit, 10000 iterations in key derivation - const spec = [ - getRandomBytes(16), // initialization vector - getRandomBytes(8), // salt - 100000, // iterations - 256, // key size - 128, // tag size - 'aes', // algorithm - 'gcm', // algorithm mode - $('body').data('compression') || 'zlib' // compression - ], encodedSpec = []; + const compression = ( + typeof (await z) === 'undefined' ? + 'none' : // client lacks support for WASM + $('body').data('compression') || 'zlib' + ), + spec = [ + getRandomBytes(16), // initialization vector + getRandomBytes(8), // salt + 100000, // iterations + 256, // key size + 128, // tag size + 'aes', // algorithm + 'gcm', // algorithm mode + compression // compression + ], encodedSpec = []; for (let i = 0; i < spec.length; ++i) { encodedSpec[i] = i < 2 ? btoa(spec[i]) : spec[i]; } @@ -987,8 +998,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { await window.crypto.subtle.encrypt( cryptoSettings(JSON.stringify(adata), spec), await deriveKey(key, password, spec), - await compress(message, spec[7]) - ) + await compress(message, compression) + ).catch(Alert.showError) ) ), adata @@ -1043,7 +1054,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { stringToArraybuffer( atob(cipherMessage) ) - ), + ).catch(Alert.showError), spec[7] ); } catch(err) { @@ -1194,7 +1205,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.getPasteId = function() { const idRegEx = /^[a-z0-9]{16}$/; - const idRegExFind = /[a-z0-9]{16}/; // return cached value if (id !== null) { @@ -1573,6 +1583,22 @@ jQuery.PrivateBin = (function($, RawDeflate) { handleNotification(1, $statusMessage, message, icon); }; + /** + * display a warning message + * + * This automatically passes the text to I18n for translation. + * + * @name Alert.showWarning + * @function + * @param {string|array} message string, use an array for %s/%d options + * @param {string|null} icon optional, the icon to show, default: + * leave previous icon + */ + me.showWarning = function(message, icon) + { + handleNotification(2, $errorMessage, message, icon); + }; + /** * display an error message * @@ -1699,7 +1725,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { currentIcon = [ 'glyphicon-time', // loading icon 'glyphicon-info-sign', // status icon - '', // reserved for warning, not used yet + 'glyphicon-warning-sign', // warning icon 'glyphicon-alert' // error icon ]; }; @@ -1768,14 +1794,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { return; } } - Alert.showError( - I18n._('Cannot parse response from URL shortener.') - ); + Alert.showError('Cannot parse response from URL shortener.'); } }) .fail(function(data, textStatus, errorThrown) { console.error(textStatus, errorThrown); - // we don't know why it failed, could be CORS of the external server not setup properly, in which case we follow old behavior to open it in new tab + // we don't know why it failed, could be CORS of the external + // server not setup properly, in which case we follow old + // behavior to open it in new tab window.open( `${$shortenButton.data('shortener')}${encodeURIComponent($pasteUrl.attr('href'))}`, '_blank', @@ -2731,9 +2757,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // revert loading status… me.hideAttachment(); me.hideAttachmentPreview(); - Alert.showError( - I18n._('Your browser does not support uploading encrypted files. Please use a newer browser.') - ); + Alert.showWarning('Your browser does not support uploading encrypted files. Please use a newer browser.'); return; } @@ -4194,8 +4218,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { const PasteEncrypter = (function () { const me = {}; - let requirementsChecked = false; - /** * called after successful paste upload * @@ -4428,16 +4450,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { }); cipherMessage['attachment'] = await fileReading; } else { - Alert.showError( - I18n._('Cannot process attachment data.') - ); - throw new TypeError('Cannot process attachment data.'); + const error = 'Cannot process attachment data.'; + Alert.showError(error); + throw new TypeError(error); } } catch (error) { console.error(error); - Alert.showError( - I18n._('Cannot retrieve attachment.') - ); + Alert.showError('Cannot retrieve attachment.'); throw error; } } @@ -4528,8 +4547,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { } } - let format = '', - text = ''; if (paste.v > 1) { // version 2 paste const pasteMessage = JSON.parse(pastePlain); @@ -4630,9 +4647,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // log detailed error, but display generic translation console.error(message); - Alert.showError( - I18n._('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.') - ); + Alert.showError('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.'); // reset password, so it can be re-entered Prompt.reset(); @@ -4702,8 +4717,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { * initial (security) check * * @name InitialCheck - * @param {object} window - * @param {object} document * @class */ const InitialCheck = (function () { @@ -4848,6 +4861,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { $('#httpnotice').removeClass('hidden'); } + z = zlib.catch(function () { + Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.'); + }); return true; } @@ -4926,9 +4942,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // missing decryption key (or paste ID) in URL? if (window.location.hash.length === 0) { - Alert.showError( - I18n._('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)') - ); + Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)'); return; } } @@ -5054,7 +5068,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { Prompt.init(); TopNav.init(); UiHelper.init(); - z = (await zlib); if (!InitialCheck.init()) { // something major is wrong, stop right away return; diff --git a/js/test/CryptTool.js b/js/test/CryptTool.js index 80ea5ecbc..9589ef977 100644 --- a/js/test/CryptTool.js +++ b/js/test/CryptTool.js @@ -8,6 +8,9 @@ describe('CryptTool', function () { await new Promise(resolve => setTimeout(resolve, 1900)); }); + // ensure zlib is getting loaded + $.PrivateBin.InitialCheck.init(); + this.timeout(30000); it('can en- and decrypt any message', function () { jsc.assert(jsc.forall( diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 2d07fe228..caf4bb5fd 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index eec66ae70..9b33be46c 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ endif; ?> - + From a6aef109ccf90ef37249c5c121dfc3a8f0fa1210 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 27 Aug 2019 23:16:06 +0200 Subject: [PATCH 02/24] making feature detection work as intended in chrome --- js/privatebin.js | 18 ++++++++++++++---- js/test/Alert.js | 18 +++++++++--------- js/test/InitialCheck.js | 16 +++++----------- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index c990c3590..6b16e7f83 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -566,10 +566,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { // if $element is given, apply text to element if ($element !== null) { - // get last text node of element + // set the last text node of element let content = $element.contents(); if (content.length > 1) { - content[content.length - 1].nodeValue = ' ' + output; + $element.html(' ' + output).prepend(content[0]); } else { $element.text(output); } @@ -4803,11 +4803,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function isOldBrowser() { // webcrypto support - if (typeof window.crypto !== 'object') { + if (!( + 'crypto' in window && + 'getRandomValues' in window.crypto && + 'subtle' in window.crypto && + 'encrypt' in window.crypto.subtle && + 'decrypt' in window.crypto.subtle && + 'Uint32Array' in window + )) { return true; } - if (typeof WebAssembly !== 'object' && typeof WebAssembly.instantiate !== 'function') { + if (!( + 'WebAssembly' in window && + 'instantiate' in window.WebAssembly + )) { return true; } try { diff --git a/js/test/Alert.js b/js/test/Alert.js index dfaf35356..9d0095568 100644 --- a/js/test/Alert.js +++ b/js/test/Alert.js @@ -10,7 +10,7 @@ describe('Alert', function () { function (icon, message) { icon = icon.join(''); message = message.join(''); - var expected = ''; @@ -21,7 +21,7 @@ describe('Alert', function () { ); $.PrivateBin.Alert.init(); $.PrivateBin.Alert.showStatus(message, icon); - var result = $('body').html(); + const result = $('body').html(); return expected === result; } ); @@ -39,7 +39,7 @@ describe('Alert', function () { function (icon, message) { icon = icon.join(''); message = message.join(''); - var expected = ''; @@ -50,7 +50,7 @@ describe('Alert', function () { ); $.PrivateBin.Alert.init(); $.PrivateBin.Alert.showError(message, icon); - var result = $('body').html(); + const result = $('body').html(); return expected === result; } ); @@ -69,7 +69,7 @@ describe('Alert', function () { function (message, string, number) { message = message.join(''); string = string.join(''); - var expected = ''; @@ -80,7 +80,7 @@ describe('Alert', function () { ); $.PrivateBin.Alert.init(); $.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]); - var result = $('body').html(); + const result = $('body').html(); return expected === result; } ); @@ -98,7 +98,7 @@ describe('Alert', function () { function (message, icon) { message = message.join(''); icon = icon.join(''); - var defaultMessage = 'Loading…'; + const defaultMessage = 'Loading…'; if (message.length === 0) { message = defaultMessage; } @@ -114,7 +114,7 @@ describe('Alert', function () { ); $.PrivateBin.Alert.init(); $.PrivateBin.Alert.showLoading(message, icon); - var result = $('body').html(); + const result = $('body').html(); return expected === result; } ); @@ -182,7 +182,7 @@ describe('Alert', function () { jsc.array(common.jscAlnumString()), function (trigger, message) { message = message.join(''); - var handlerCalled = false, + let handlerCalled = false, defaultMessage = 'Loading…', functions = [ $.PrivateBin.Alert.showStatus, diff --git a/js/test/InitialCheck.js b/js/test/InitialCheck.js index 5b0778cc7..50c6dfb56 100644 --- a/js/test/InitialCheck.js +++ b/js/test/InitialCheck.js @@ -22,7 +22,6 @@ describe('InitialCheck', function () { '' ); $.PrivateBin.Alert.init(); - window.crypto = null; const result1 = !$.PrivateBin.InitialCheck.init(), result2 = !$('#errormessage').hasClass('hidden'); clean(); @@ -61,24 +60,19 @@ describe('InitialCheck', function () { jsc.property( 'shows error, if HTTP only site is detected', 'bool', - jsc.elements(['localhost', '127.0.0.1', '[::1]', '']), jsc.nearray(common.jscA2zString()), - jsc.elements(['.onion', '.i2p', '']), - function (secureProtocol, localhost, domain, tld) { - const isDomain = localhost === '', - isSecureContext = secureProtocol || !isDomain || tld.length > 0, - clean = jsdom('', { - 'url': (secureProtocol ? 'https' : 'http' ) + '://' + - (isDomain ? domain.join('') + tld : localhost) + '/' + function (secureProtocol, domain) { + const clean = jsdom('', { + 'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/' }); $('body').html( ''+ '' ); $.PrivateBin.Alert.init(); - window.crypto = null; + window.crypto = new WebCrypto(); const result1 = $.PrivateBin.InitialCheck.init(), - result2 = isSecureContext === $('#httpnotice').hasClass('hidden'); + result2 = secureProtocol === $('#httpnotice').hasClass('hidden'); clean(); return result1 && result2; } diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index caf4bb5fd..07e86d96d 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index 9b33be46c..51f466126 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ endif; ?> - + From ad570c391a506b460d5c441696ae04ba11721656 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 28 Aug 2019 19:23:58 +0200 Subject: [PATCH 03/24] extend Alert class unit testing --- js/test/Alert.js | 134 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/js/test/Alert.js b/js/test/Alert.js index 9d0095568..8e3787d31 100644 --- a/js/test/Alert.js +++ b/js/test/Alert.js @@ -4,7 +4,25 @@ var common = require('../common'); describe('Alert', function () { describe('showStatus', function () { jsc.property( - 'shows a status message', + 'shows a status message (basic)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + const expected = '
' + message + '
'; + $('body').html( + '
' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showStatus(message, icon); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows a status message (bootstrap)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { @@ -33,7 +51,25 @@ describe('Alert', function () { }); jsc.property( - 'shows an error message', + 'shows an error message (basic)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + const expected = '
' + message + '
'; + $('body').html( + '
' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showError(message, icon); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows an error message (bootstrap)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { @@ -56,13 +92,79 @@ describe('Alert', function () { ); }); + describe('showWarning', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows a warning message (basic)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + const expected = '
' + message + '
'; + $('body').html( + '
' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showWarning(message, icon); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows a warning message (bootstrap)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + const expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showWarning(message, icon); + const result = $('body').html(); + return expected === result; + } + ); + }); + describe('showRemaining', function () { before(function () { cleanup(); }); jsc.property( - 'shows remaining time', + 'shows remaining time (basic)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + 'integer', + function (message, string, number) { + message = message.join(''); + string = string.join(''); + const expected = '
' + string + message + number + '
'; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows remaining time (bootstrap)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), 'integer', @@ -92,7 +194,29 @@ describe('Alert', function () { }); jsc.property( - 'shows a loading message', + 'shows a loading message (basic)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (message, icon) { + message = message.join(''); + icon = icon.join(''); + const defaultMessage = 'Loading…'; + if (message.length === 0) { + message = defaultMessage; + } + const expected = '
' + message + '
'; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showLoading(message, icon); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows a loading message (bootstrap)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (message, icon) { @@ -102,7 +226,7 @@ describe('Alert', function () { if (message.length === 0) { message = defaultMessage; } - var expected = ''; From 7f65fe92188ed03db9d4fe82f494a5cc4f4cc655 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 28 Aug 2019 19:25:11 +0200 Subject: [PATCH 04/24] fixing conflicting icons when using error message div for warnings in bootstrap template --- js/privatebin.js | 1 + tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 6b16e7f83..c7d638d9f 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1596,6 +1596,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.showWarning = function(message, icon) { + $errorMessage.find(':first').removeClass(currentIcon[3]); handleNotification(2, $errorMessage, message, icon); }; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 07e86d96d..af9a3e29b 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index 51f466126..afd58b30e 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ endif; ?> - + From c56d777c11efa70c6468092b6e6193fe037db8e9 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 28 Aug 2019 20:29:23 +0200 Subject: [PATCH 05/24] fixing logic when there are no icons and warning icons, add more test cases --- js/privatebin.js | 47 +++++++++++++---------- js/test/Alert.js | 95 +++++++++++++++++++++++++++++++++++++++-------- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index c7d638d9f..acaaf65c3 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1493,7 +1493,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { const alertType = [ 'loading', // not in bootstrap CSS, but using a plausible value here 'info', // status icon - 'warning', // not used yet + 'warning', // warning icon 'danger' // error icon ]; @@ -1537,28 +1537,35 @@ jQuery.PrivateBin = (function($, RawDeflate) { icon = null; // icons not supported in this case } } + let $translationTarget = $element; - // handle icon - if (icon !== null && // icon was passed - icon !== currentIcon[id] // and it differs from current icon - ) { - let $glyphIcon = $element.find(':first'); - - // remove (previous) icon - $glyphIcon.removeClass(currentIcon[id]); + // handle icon, if template uses one + const $glyphIcon = $element.find(':first'); + if ($glyphIcon.length) { + // if there is an icon, we need to provide an inner element + // to translate the message into, instead of the parent + $translationTarget = $(''); + $element.html(' ').prepend($glyphIcon).append($translationTarget); - // any other thing as a string (e.g. 'null') (only) removes the icon - if (typeof icon === 'string') { - // set new icon - currentIcon[id] = 'glyphicon-' + icon; - $glyphIcon.addClass(currentIcon[id]); + if (icon !== null && // icon was passed + icon !== currentIcon[id] // and it differs from current icon + ) { + // remove (previous) icon + $glyphIcon.removeClass(currentIcon[id]); + + // any other thing as a string (e.g. 'null') (only) removes the icon + if (typeof icon === 'string') { + // set new icon + currentIcon[id] = 'glyphicon-' + icon; + $glyphIcon.addClass(currentIcon[id]); + } } } // show text if (args !== null) { // add jQuery object to it as first parameter - args.unshift($element); + args.unshift($translationTarget); // pass it to I18n I18n._.apply(this, args); } @@ -1596,7 +1603,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.showWarning = function(message, icon) { - $errorMessage.find(':first').removeClass(currentIcon[3]); + $errorMessage.find(':first') + .removeClass(currentIcon[3]) + .addClass(currentIcon[2]); handleNotification(2, $errorMessage, message, icon); }; @@ -2990,11 +2999,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.init = function() { $attachment = $('#attachment'); - if($attachment.length){ + $dragAndDropFileName = $('#dragAndDropFileName'); + $dropzone = $('#dropzone'); + if($attachment.length) { $attachmentLink = $('#attachment a'); $attachmentPreview = $('#attachmentPreview'); - $dragAndDropFileName = $('#dragAndDropFileName'); - $dropzone = $('#dropzone'); $fileInput = $('#file'); addDragDropHandler(); diff --git a/js/test/Alert.js b/js/test/Alert.js index 8e3787d31..d59f38c1a 100644 --- a/js/test/Alert.js +++ b/js/test/Alert.js @@ -24,6 +24,27 @@ describe('Alert', function () { jsc.property( 'shows a status message (bootstrap)', jsc.array(common.jscAlnumString()), + function (message) { + message = message.join(''); + const expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showStatus(message); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows a status message (bootstrap, custom icon)', + jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { icon = icon.join(''); @@ -31,7 +52,7 @@ describe('Alert', function () { const expected = ''; + '" aria-hidden="true"> ' + message + ''; $('body').html( '' ); $.PrivateBin.Alert.init(); - $.PrivateBin.Alert.showError(message, icon); + $.PrivateBin.Alert.showWarning(message, icon); const result = $('body').html(); return expected === result; } ); jsc.property( - 'shows an error message (bootstrap)', + 'shows a warning message (bootstrap)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (message) { + message = message.join(''); + const expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showWarning(message); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows a warning message (bootstrap, custom icon)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { @@ -78,27 +121,27 @@ describe('Alert', function () { const expected = ''; + '" aria-hidden="true"> ' + message + ''; $('body').html( '' ); $.PrivateBin.Alert.init(); - $.PrivateBin.Alert.showError(message, icon); + $.PrivateBin.Alert.showWarning(message, icon); const result = $('body').html(); return expected === result; } ); }); - describe('showWarning', function () { + describe('showError', function () { before(function () { cleanup(); }); jsc.property( - 'shows a warning message (basic)', + 'shows an error message (basic)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { @@ -109,14 +152,36 @@ describe('Alert', function () { '
' ); $.PrivateBin.Alert.init(); - $.PrivateBin.Alert.showWarning(message, icon); + $.PrivateBin.Alert.showError(message, icon); const result = $('body').html(); return expected === result; } ); jsc.property( - 'shows a warning message (bootstrap)', + 'shows an error message (bootstrap)', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + message = message.join(''); + const expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showError(message); + const result = $('body').html(); + return expected === result; + } + ); + + jsc.property( + 'shows an error message (bootstrap, custom icon)', jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()), function (icon, message) { @@ -125,14 +190,14 @@ describe('Alert', function () { const expected = ''; + '" aria-hidden="true"> ' + message + ''; $('body').html( '' ); $.PrivateBin.Alert.init(); - $.PrivateBin.Alert.showWarning(message, icon); + $.PrivateBin.Alert.showError(message, icon); const result = $('body').html(); return expected === result; } @@ -174,7 +239,7 @@ describe('Alert', function () { const expected = ''; + ' ' + string + message + number + ''; $('body').html( '