diff --git a/LICENSE.md b/LICENSE.md index 8492fc3..5ffdba0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -377,36 +377,6 @@ any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. -## BSD 3-Clause License for base64.js version 2.1.9 - -Copyright © 2014, Dan Kogai -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of base64.js nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ## MIT License for base64.js version 1.7 Copyright © 2012 Dan Kogai diff --git a/js/base64-2.4.5.js b/js/base64-2.4.5.js deleted file mode 100644 index 447964c..0000000 --- a/js/base64-2.4.5.js +++ /dev/null @@ -1 +0,0 @@ -(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory(global):typeof define==="function"&&define.amd?define(factory):factory(global)})(typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:this,function(global){"use strict";var _Base64=global.Base64;var version="2.4.5";var buffer;if(typeof module!=="undefined"&&module.exports){try{buffer=require("buffer").Buffer}catch(err){}}var b64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64tab=function(bin){var t={};for(var i=0,l=bin.length;i>>6)+fromCharCode(128|cc&63):fromCharCode(224|cc>>>12&15)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}else{var cc=65536+(c.charCodeAt(0)-55296)*1024+(c.charCodeAt(1)-56320);return fromCharCode(240|cc>>>18&7)+fromCharCode(128|cc>>>12&63)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}};var re_utob=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;var utob=function(u){return u.replace(re_utob,cb_utob)};var cb_encode=function(ccc){var padlen=[0,2,1][ccc.length%3],ord=ccc.charCodeAt(0)<<16|(ccc.length>1?ccc.charCodeAt(1):0)<<8|(ccc.length>2?ccc.charCodeAt(2):0),chars=[b64chars.charAt(ord>>>18),b64chars.charAt(ord>>>12&63),padlen>=2?"=":b64chars.charAt(ord>>>6&63),padlen>=1?"=":b64chars.charAt(ord&63)];return chars.join("")};var btoa=global.btoa?function(b){return global.btoa(b)}:function(b){return b.replace(/[\s\S]{1,3}/g,cb_encode)};var _encode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(u){return(u.constructor===buffer.constructor?u:buffer.from(u)).toString("base64")}:function(u){return(u.constructor===buffer.constructor?u:new buffer(u)).toString("base64")}:function(u){return btoa(utob(u))};var encode=function(u,urisafe){return!urisafe?_encode(String(u)):_encode(String(u)).replace(/[+\/]/g,function(m0){return m0=="+"?"-":"_"}).replace(/=/g,"")};var encodeURI=function(u){return encode(u,true)};var re_btou=new RegExp(["[À-ß][€-¿]","[à-ï][€-¿]{2}","[ð-÷][€-¿]{3}"].join("|"),"g");var cb_btou=function(cccc){switch(cccc.length){case 4:var cp=(7&cccc.charCodeAt(0))<<18|(63&cccc.charCodeAt(1))<<12|(63&cccc.charCodeAt(2))<<6|63&cccc.charCodeAt(3),offset=cp-65536;return fromCharCode((offset>>>10)+55296)+fromCharCode((offset&1023)+56320);case 3:return fromCharCode((15&cccc.charCodeAt(0))<<12|(63&cccc.charCodeAt(1))<<6|63&cccc.charCodeAt(2));default:return fromCharCode((31&cccc.charCodeAt(0))<<6|63&cccc.charCodeAt(1))}};var btou=function(b){return b.replace(re_btou,cb_btou)};var cb_decode=function(cccc){var len=cccc.length,padlen=len%4,n=(len>0?b64tab[cccc.charAt(0)]<<18:0)|(len>1?b64tab[cccc.charAt(1)]<<12:0)|(len>2?b64tab[cccc.charAt(2)]<<6:0)|(len>3?b64tab[cccc.charAt(3)]:0),chars=[fromCharCode(n>>>16),fromCharCode(n>>>8&255),fromCharCode(n&255)];chars.length-=[0,0,2,1][padlen];return chars.join("")};var atob=global.atob?function(a){return global.atob(a)}:function(a){return a.replace(/[\s\S]{1,4}/g,cb_decode)};var _decode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(a){return(a.constructor===buffer.constructor?a:buffer.from(a,"base64")).toString()}:function(a){return(a.constructor===buffer.constructor?a:new buffer(a,"base64")).toString()}:function(a){return btou(atob(a))};var decode=function(a){return _decode(String(a).replace(/[-_]/g,function(m0){return m0=="-"?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))};var noConflict=function(){var Base64=global.Base64;global.Base64=_Base64;return Base64};global.Base64={VERSION:version,atob:atob,btoa:btoa,fromBase64:decode,toBase64:encode,utob:utob,encode:encode,encodeURI:encodeURI,btou:btou,decode:decode,noConflict:noConflict};if(typeof Object.defineProperty==="function"){var noEnum=function(v){return{value:v,enumerable:false,writable:true,configurable:true}};global.Base64.extendString=function(){Object.defineProperty(String.prototype,"fromBase64",noEnum(function(){return decode(this)}));Object.defineProperty(String.prototype,"toBase64",noEnum(function(urisafe){return encode(this,urisafe)}));Object.defineProperty(String.prototype,"toBase64URI",noEnum(function(){return encode(this,true)}))}}if(global["Meteor"]){Base64=global.Base64}if(typeof module!=="undefined"&&module.exports){module.exports.Base64=global.Base64}else if(typeof define==="function"&&define.amd){define([],function(){return global.Base64})}return{Base64:global.Base64}}); diff --git a/js/common.js b/js/common.js index e4884d5..44ff7c1 100644 --- a/js/common.js +++ b/js/common.js @@ -10,7 +10,6 @@ global.fs = require('fs'); // application libraries to test global.$ = global.jQuery = require('./jquery-3.3.1'); global.sjcl = require('./sjcl-1.0.7'); -global.Base64 = require('./base64-2.4.5').Base64; global.RawDeflate = require('./rawdeflate-0.5').RawDeflate; global.RawDeflate.inflate = require('./rawinflate-0.3').RawDeflate.inflate; require('./prettify'); diff --git a/js/privatebin.js b/js/privatebin.js index 06e24bf..dbd0af0 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -30,7 +30,7 @@ jQuery(document).ready(function() { $.PrivateBin.Controller.init(); }); -jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) { +jQuery.PrivateBin = (function($, sjcl, RawDeflate) { 'use strict'; /** @@ -527,7 +527,54 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) { var me = {}; /** - * compress a message (deflate compression), returns base64 encoded data + * convert DOMString (UTF-16) to a UTF-8 string stored in a DOMString + * + * URI encodes the message, then finds the percent encoded characters + * and transforms these hexadecimal representation back into bytes + * + * @name CryptTool.utob + * @function + * @private + * @param {string} message UTF-16 string + * @return {string} UTF-8 string + */ + function utob(message) + { + return encodeURIComponent(message).replace( + /%([0-9A-F]{2})/g, + function (match, hexCharacter) + { + return String.fromCharCode('0x' + hexCharacter); + } + ); + } + + /** + * convert UTF-8 string stored in a DOMString to a standard UTF-16 DOMString + * + * Iterates over the bytes of the message, converting them all hexadecimal + * percent encoded representations, then URI decodes them all + * + * @name CryptTool.btou + * @function + * @private + * @param {string} message UTF-8 string + * @return {string} UTF-16 string + */ + function btou(message) + { + return decodeURIComponent( + message.split('').map( + function(character) + { + return '%' + ('00' + character.charCodeAt(0).toString(16)).slice(-2); + } + ).join('') + ); + } + + /** + * compress a string, returns base64 encoded data (deflate compression) * * @name CryptTool.compress * @function @@ -537,21 +584,31 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) { */ function compress(message) { - return Base64.toBase64( RawDeflate.deflate( Base64.utob(message) ) ); + // detect presence of Base64.js, indicating legacy ZeroBin paste + if (typeof Base64 === 'undefined') { + return btoa( utob( RawDeflate.deflate( utob( message ) ) ) ); + } else { + return Base64.toBase64( RawDeflate.deflate( Base64.utob( message ) ) ); + } } /** - * decompress a message compressed with cryptToolcompress() + * decompress a base64 encoded data (deflate compression), returns string * * @name CryptTool.decompress * @function * @private - * @param {string} data - base64 data + * @param {string} data base64 data * @return {string} message */ function decompress(data) { - return Base64.btou( RawDeflate.inflate( Base64.fromBase64(data) ) ); + // detect presence of Base64.js, indicating legacy ZeroBin paste + if (typeof Base64 === 'undefined') { + return btou( RawDeflate.inflate( btou( atob( data ) ) ) ); + } else { + return Base64.btou( RawDeflate.inflate( Base64.fromBase64( data ) ) ); + } } /** @@ -624,10 +681,15 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) { typeof window !== 'undefined' && typeof Uint8Array !== 'undefined' && String.fromCodePoint && - (crypto = window.crypto || window.msCrypto) + ( + typeof window.crypto !== 'undefined' || + typeof window.msCrypto !== 'undefined' + ) ) { // modern browser environment - var bytes = '', byteArray = new Uint8Array(32); + var bytes = '', + byteArray = new Uint8Array(32), + crypto = window.crypto || window.msCrypto; crypto.getRandomValues(byteArray); for (var i = 0; i < 32; ++i) { bytes += String.fromCharCode(byteArray[i]); @@ -4386,4 +4448,4 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) { PasteDecrypter: PasteDecrypter, Controller: Controller }; -})(jQuery, sjcl, Base64, RawDeflate); +})(jQuery, sjcl, RawDeflate); diff --git a/js/test/CryptTool.js b/js/test/CryptTool.js index bd9352c..6666921 100644 --- a/js/test/CryptTool.js +++ b/js/test/CryptTool.js @@ -24,8 +24,13 @@ describe('CryptTool', function () { // The below static unit tests are included to ensure deciphering of "classic" // SJCL based pastes still works it( - 'supports PrivateBin v1 ciphertext (SJCL & Base64)', + 'supports PrivateBin v1 ciphertext (SJCL & browser atob)', function () { + delete global.Base64; + // make btoa available + jsdom(); + global.btoa = window.btoa; + // Of course you can easily decipher the following texts, if you like. // Bonus points for finding their sources and hidden meanings. var paste1 = $.PrivateBin.CryptTool.decipher( @@ -97,11 +102,7 @@ describe('CryptTool', function () { it( 'supports ZeroBin ciphertext (SJCL & Base64 1.7)', function () { - var newBase64 = global.Base64; global.Base64 = require('../base64-1.7').Base64; - jsdom(); - delete require.cache[require.resolve('../privatebin')]; - require('../privatebin'); // Of course you can easily decipher the following texts, if you like. // Bonus points for finding their sources and hidden meanings. @@ -149,10 +150,7 @@ describe('CryptTool', function () { 'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}' ); - global.Base64 = newBase64; - jsdom(); - delete require.cache[require.resolve('../privatebin')]; - require('../privatebin'); + delete global.Base64; assert.ok( paste1.includes('securely packed in iron') && paste2.includes('Sol is right') @@ -177,18 +175,20 @@ describe('CryptTool', function () { ); }); - describe('Base64.js vs SJCL.js vs abab.js', function () { + describe('SJCL.js vs abab.js', function () { jsc.property( 'these all return the same base64 string', 'string', function(string) { - var base64 = Base64.toBase64(string), + // make btoa/atob available + jsdom(); + // not comparing Base64.js v1.7 encode/decode, that has known issues + var Base64 = require('../base64-1.7').Base64, sjcl = global.sjcl.codec.base64.fromBits(global.sjcl.codec.utf8String.toBits(string)), abab = window.btoa(Base64.utob(string)), - esab46 = Base64.fromBase64(sjcl), lcjs = global.sjcl.codec.utf8String.fromBits(global.sjcl.codec.base64.toBits(abab)), - baba = Base64.btou(window.atob(base64)); - return base64 === sjcl && sjcl === abab && string === esab46 && esab46 === lcjs && lcjs === baba; + baba = Base64.btou(window.atob(sjcl)); + return sjcl === abab && string === lcjs && lcjs === baba; } ); }); diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 41358cc..b10225b 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -53,10 +53,6 @@ if ($ZEROBINCOMPATIBILITY): ?> - - @@ -75,7 +71,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index bd02893..e2e1acb 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -32,10 +32,6 @@ if ($ZEROBINCOMPATIBILITY): ?> - - @@ -53,7 +49,7 @@ if ($MARKDOWN): - +