diff --git a/CHANGELOG.md b/CHANGELOG.md index 608716f9..ae237250 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,21 @@ # PrivateBin version history * **1.4 (not yet released)** + * **1.3.4 (2020-03-22)** + * CHANGED: Minimum required PHP version is 5.6, due to a change in the identicon library and to use php's native hash_equals() + * CHANGED: Upgrading libraries to: identicon 2.0.0 + * FIXED: Support custom expiration options in email function (#586) + * FIXED: Regression with encoding of HTML entities (#588) + * FIXED: Unable to paste password on paste with attachment (#565 & #595) + * **1.3.3 (2020-02-16)** * CHANGED: Upgrading libraries to: DOMpurify 2.0.8 * CHANGED: Several translations got updated with missing messages * CHANGED: Introduce HTML entity encoding on server side (#581) * FIXED: HTML entity double encoding issues introduced in 1.3.2 (#560) + * **1.2.3 (2020-02-16)** + * CHANGED: Upgrading libraries to: DOMpurify 2.0.8 + * CHANGED: Introduce HTML entity encoding on server side (#581) + * FIXED: HTML entity double encoding issues introduced in 1.3.2 (#560) * **1.3.2 (2020-01-11)** * ADDED: Translation for Ukrainian (#533) * ADDED: Option to send a mail with the link, when creating a paste (#398) diff --git a/INSTALL.md b/INSTALL.md index 2f3900c6..93a12843 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -187,7 +187,7 @@ CREATE INDEX parent ON prefix_comment(pasteid); CREATE TABLE prefix_config ( id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) ); -INSERT INTO prefix_config VALUES('VERSION', '1.3.3'); +INSERT INTO prefix_config VALUES('VERSION', '1.3.4'); ``` In **PostgreSQL**, the data, attachment, nickname and vizhash columns needs to be TEXT and not BLOB or MEDIUMBLOB. diff --git a/README.md b/README.md index d05a8654..d35035f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/) -*Current version: 1.3.3* +*Current version: 1.3.4* **PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin) where the server has zero knowledge of pasted data. diff --git a/SECURITY.md b/SECURITY.md index f3b02da2..1a5bf963 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 1.3.3 | :heavy_check_mark: | -| < 1.3.3 | :x: | +| 1.3.4 | :heavy_check_mark: | +| < 1.3.4 | :x: | ## Reporting a Vulnerability diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index 7bd85f55..72e420ed 100644 --- a/css/bootstrap/privatebin.css +++ b/css/bootstrap/privatebin.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.3.3 + * @version 1.3.4 */ body { diff --git a/css/noscript.css b/css/noscript.css index 3679c279..e44670f0 100644 --- a/css/noscript.css +++ b/css/noscript.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.3.3 + * @version 1.3.4 */ /* When there is no script at all other */ diff --git a/css/privatebin.css b/css/privatebin.css index 350d6217..a3ab5ea6 100644 --- a/css/privatebin.css +++ b/css/privatebin.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.3.3 + * @version 1.3.4 */ /* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. diff --git a/i18n/de.json b/i18n/de.json index 31eec787..47e8adc0 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -172,9 +172,9 @@ "Notice:": "Hinweis:", "This link will expire after %s.": - "Dieser Link wird in %s ablaufen.", + "Dieser Link wird um %s ablaufen.", "This link can only be accessed once, do not use back or refresh button in your browser.": - "Dieser Link kann nur einmal geöffnet werden, verwende nicht den \"Zurück\" oder \"Neu laden\" Knopf Deines Browsers.", + "Dieser Link kann nur einmal geöffnet werden, verwende nicht den Zurück- oder Neu-laden-Knopf Deines Browsers.", "Link:": "Link:", "Recipient may become aware of your timezone, convert time to UTC?": diff --git a/index.php b/index.php index f346a598..a6d7cdf2 100644 --- a/index.php +++ b/index.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.3.3 + * @version 1.3.4 */ // change this, if your php files and data is outside of your webservers document root diff --git a/js/privatebin.js b/js/privatebin.js index e76bf98c..6ed9325b 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -6,7 +6,7 @@ * @see {@link https://github.com/PrivateBin/PrivateBin} * @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net}) * @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License} - * @version 1.3.3 + * @version 1.3.4 * @name PrivateBin * @namespace */ @@ -209,6 +209,64 @@ jQuery.PrivateBin = (function($, RawDeflate) { '=': '=' }; + /** + * number of seconds in a minute + * + * @name Helper.minute + * @private + * @enum {number} + * @readonly + */ + const minute = 60; + + /** + * number of seconds in an hour + * + * = 60 * 60 seconds + * + * @name Helper.minute + * @private + * @enum {number} + * @readonly + */ + const hour = 3600; + + /** + * number of seconds in a day + * + * = 60 * 60 * 24 seconds + * + * @name Helper.day + * @private + * @enum {number} + * @readonly + */ + const day = 86400; + + /** + * number of seconds in a month (30 days, an approximation) + * + * = 60 * 60 * 24 * 30 seconds + * + * @name Helper.month + * @private + * @enum {number} + * @readonly + */ + const month = 2592000; + + /** + * number of seconds in a non-leap year + * + * = 60 * 60 * 24 * 365 seconds + * + * @name Helper.year + * @private + * @enum {number} + * @readonly + */ + const year = 31536000; + /** * cache for script location * @@ -229,31 +287,67 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.secondsToHuman = function(seconds) { let v; - if (seconds < 60) + if (seconds < minute) { v = Math.floor(seconds); return [v, 'second']; } - if (seconds < 60 * 60) + if (seconds < hour) { - v = Math.floor(seconds / 60); + v = Math.floor(seconds / minute); return [v, 'minute']; } - if (seconds < 60 * 60 * 24) + if (seconds < day) { - v = Math.floor(seconds / (60 * 60)); + v = Math.floor(seconds / hour); return [v, 'hour']; } // If less than 2 months, display in days: - if (seconds < 60 * 60 * 24 * 60) + if (seconds < (2 * month)) { - v = Math.floor(seconds / (60 * 60 * 24)); + v = Math.floor(seconds / day); return [v, 'day']; } - v = Math.floor(seconds / (60 * 60 * 24 * 30)); + v = Math.floor(seconds / month); return [v, 'month']; }; + /** + * converts a duration string into seconds + * + * The string is expected to be optional digits, followed by a time. + * Supported times are: min, hour, day, month, year, never + * Examples: 5min, 13hour, never + * + * @name Helper.durationToSeconds + * @function + * @param {String} duration + * @return {number} + */ + me.durationToSeconds = function(duration) + { + let pieces = duration.split(/\d+/), + factor = pieces[0] || 0, + timespan = pieces[1] || pieces[0]; + switch (timespan) + { + case 'min': + return factor * minute; + case 'hour': + return factor * hour; + case 'day': + return factor * day; + case 'month': + return factor * month; + case 'year': + return factor * year; + case 'never': + return 0; + default: + return factor; + } + }; + /** * text range selection * @@ -281,7 +375,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * convert URLs to clickable links. + * convert URLs to clickable links in the provided element. * * URLs to handle: *
@@ -292,14 +386,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
          *
          * @name   Helper.urls2links
          * @function
-         * @param  {string} html
-         * @return {string}
+         * @param  {HTMLElement} element
          */
-        me.urls2links = function(html)
+        me.urls2links = function(element)
         {
-            return html.replace(
-                /(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]*>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
-                '$1'
+            element.html(
+                element.html().replace(
+                    /(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
+                    '$1'
+                )
             );
         };
 
@@ -432,22 +527,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
          * @return {Date}
          */
         me.calculateExpirationDate = function(initialDate, expirationDisplayStringOrSecondsToExpire) {
-            let expirationDate = new Date(initialDate);
-
-            const expirationDisplayStringToSecondsDict = {
-                '5min': 300,
-                '10min': 600,
-                '1hour': 3500,
-                '1day': 86400,
-                '1week': 604800,
-                '1month': 2592000,
-                '1year': 31536000,
-                'never': 0
-            };
-
-            let secondsToExpiration = expirationDisplayStringOrSecondsToExpire;
+            let expirationDate      = new Date(initialDate),
+                secondsToExpiration = expirationDisplayStringOrSecondsToExpire;
             if (typeof expirationDisplayStringOrSecondsToExpire === 'string') {
-                secondsToExpiration = expirationDisplayStringToSecondsDict[expirationDisplayStringOrSecondsToExpire];
+                secondsToExpiration = me.durationToSeconds(expirationDisplayStringOrSecondsToExpire);
             }
             
             if (typeof secondsToExpiration !== 'number') {
@@ -2422,36 +2505,24 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 return;
             }
 
-            // escape HTML entities, link URLs, sanitize
-            const escapedLinkedText = Helper.urls2links(text),
-                  sanitizedLinkedText = DOMPurify.sanitize(
-                    escapedLinkedText, {
-                        ALLOWED_TAGS: ['a'],
-                        ALLOWED_ATTR: ['href', 'rel']
-                    }
-                  );
-            $plainText.html(sanitizedLinkedText);
-            $prettyPrint.html(sanitizedLinkedText);
-
-            switch (format) {
-                case 'markdown':
-                    const converter = new showdown.Converter({
-                        strikethrough: true,
-                        tables: true,
-                        tablesHeaderId: true,
-                        simplifiedAutoLink: true,
-                        excludeTrailingPunctuationFromURLs: true
-                    });
-                    // let showdown convert the HTML and sanitize HTML *afterwards*!
-                    $plainText.html(
-                        DOMPurify.sanitize(
-                            converter.makeHtml(text)
-                        )
-                    );
-                    // add table classes from bootstrap css
-                    $plainText.find('table').addClass('table-condensed table-bordered');
-                    break;
-                case 'syntaxhighlighting':
+            if (format === 'markdown') {
+                const converter = new showdown.Converter({
+                    strikethrough: true,
+                    tables: true,
+                    tablesHeaderId: true,
+                    simplifiedAutoLink: true,
+                    excludeTrailingPunctuationFromURLs: true
+                });
+                // let showdown convert the HTML and sanitize HTML *afterwards*!
+                $plainText.html(
+                    DOMPurify.sanitize(
+                        converter.makeHtml(text)
+                    )
+                );
+                // add table classes from bootstrap css
+                $plainText.find('table').addClass('table-condensed table-bordered');
+            } else {
+                if (format === 'syntaxhighlighting') {
                     // yes, this is really needed to initialize the environment
                     if (typeof prettyPrint === 'function')
                     {
@@ -2459,15 +2530,18 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                     }
 
                     $prettyPrint.html(
-                        DOMPurify.sanitize(
-                            prettyPrintOne(escapedLinkedText, null, true)
+                        prettyPrintOne(
+                            Helper.htmlEntities(text), null, true
                         )
                     );
-                    // fall through, as the rest is the same
-                default: // = 'plaintext'
-                    $prettyPrint.css('white-space', 'pre-wrap');
-                    $prettyPrint.css('word-break', 'normal');
-                    $prettyPrint.removeClass('prettyprint');
+                } else {
+                    // = 'plaintext'
+                    $prettyPrint.text(text);
+                }
+                Helper.urls2links($prettyPrint);
+                $prettyPrint.css('white-space', 'pre-wrap');
+                $prettyPrint.css('word-break', 'normal');
+                $prettyPrint.removeClass('prettyprint');
             }
         }
 
@@ -3241,14 +3315,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             const $commentEntryData = $commentEntry.find('div.commentdata');
 
             // set & parse text
-            $commentEntryData.html(
-                DOMPurify.sanitize(
-                    Helper.urls2links(commentText), {
-                        ALLOWED_TAGS: ['a'],
-                        ALLOWED_ATTR: ['href', 'rel']
-                    }
-                )
-            );
+            $commentEntryData.text(commentText);
+            Helper.urls2links($commentEntryData);
 
             // set nickname
             if (nickname.length > 0) {
@@ -3379,6 +3447,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 if (fadeOut === true) {
                     setTimeout(function () {
                         $comment.removeClass('highlight');
+
                     }, 300);
                 }
             };
@@ -4181,7 +4250,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
          */
         me.isAttachmentReadonly = function()
         {
-            return $attach.hasClass('hidden');
+            return createButtonsDisplayed && $attach.hasClass('hidden');
         }
 
         /**
diff --git a/lib/Configuration.php b/lib/Configuration.php
index d7877e21..06edf68b 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/Controller.php b/lib/Controller.php
index a10ffb47..21a27b27 100644
--- a/lib/Controller.php
+++ b/lib/Controller.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
@@ -28,14 +28,14 @@ class Controller
      *
      * @const string
      */
-    const VERSION = '1.3.3';
+    const VERSION = '1.3.4';
 
     /**
      * minimal required PHP version
      *
      * @const string
      */
-    const MIN_PHP_VERSION = '5.5.0';
+    const MIN_PHP_VERSION = '5.6.0';
 
     /**
      * show the same error message if the paste expired or does not exist
@@ -276,9 +276,7 @@ class Controller
                 // accessing this method ensures that the paste would be
                 // deleted if it has already expired
                 $paste->get();
-                if (
-                    Filter::slowEquals($deletetoken, $paste->getDeleteToken())
-                ) {
+                if (hash_equals($paste->getDeleteToken(), $deletetoken)) {
                     // Paste exists and deletion token is valid: Delete the paste.
                     $paste->delete();
                     $this->_status = 'Paste was properly deleted.';
diff --git a/lib/Data/AbstractData.php b/lib/Data/AbstractData.php
index f0572ac0..9c925838 100644
--- a/lib/Data/AbstractData.php
+++ b/lib/Data/AbstractData.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Data/Database.php b/lib/Data/Database.php
index ed52a63a..aa05e95a 100644
--- a/lib/Data/Database.php
+++ b/lib/Data/Database.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php
index 1fe0319c..c8d497a6 100644
--- a/lib/Data/Filesystem.php
+++ b/lib/Data/Filesystem.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Filter.php b/lib/Filter.php
index fd0e11ec..547e2395 100644
--- a/lib/Filter.php
+++ b/lib/Filter.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
@@ -68,23 +68,4 @@ class Filter
         }
         return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . I18n::_($iec[$i]);
     }
-
-    /**
-     * fixed time string comparison operation to prevent timing attacks
-     * https://crackstation.net/hashing-security.htm?=rd#slowequals
-     *
-     * @access public
-     * @static
-     * @param  string $a
-     * @param  string $b
-     * @return bool
-     */
-    public static function slowEquals($a, $b)
-    {
-        $diff = strlen($a) ^ strlen($b);
-        for ($i = 0; $i < strlen($a) && $i < strlen($b); ++$i) {
-            $diff |= ord($a[$i]) ^ ord($b[$i]);
-        }
-        return $diff === 0;
-    }
 }
diff --git a/lib/FormatV2.php b/lib/FormatV2.php
index 127b6a88..31cc5b84 100644
--- a/lib/FormatV2.php
+++ b/lib/FormatV2.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/I18n.php b/lib/I18n.php
index ffb781f1..a5ddaeaf 100644
--- a/lib/I18n.php
+++ b/lib/I18n.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/Json.php b/lib/Json.php
index b00d2c58..6916d27f 100644
--- a/lib/Json.php
+++ b/lib/Json.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/Model.php b/lib/Model.php
index b3c66a30..f5dd5577 100644
--- a/lib/Model.php
+++ b/lib/Model.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/Model/AbstractModel.php b/lib/Model/AbstractModel.php
index 9e1ac61e..b7273399 100644
--- a/lib/Model/AbstractModel.php
+++ b/lib/Model/AbstractModel.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php
index 2e45a034..68045aa9 100644
--- a/lib/Model/Comment.php
+++ b/lib/Model/Comment.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php
index 263a06f3..0aa2a967 100644
--- a/lib/Model/Paste.php
+++ b/lib/Model/Paste.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Persistence/AbstractPersistence.php b/lib/Persistence/AbstractPersistence.php
index 7d5a4b22..a4011d2d 100644
--- a/lib/Persistence/AbstractPersistence.php
+++ b/lib/Persistence/AbstractPersistence.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php
index 27ebd9cd..f60fc972 100644
--- a/lib/Persistence/DataStore.php
+++ b/lib/Persistence/DataStore.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.1
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/PurgeLimiter.php b/lib/Persistence/PurgeLimiter.php
index 22e2e1ad..0e987953 100644
--- a/lib/Persistence/PurgeLimiter.php
+++ b/lib/Persistence/PurgeLimiter.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/ServerSalt.php b/lib/Persistence/ServerSalt.php
index 3e8a290b..7764129f 100644
--- a/lib/Persistence/ServerSalt.php
+++ b/lib/Persistence/ServerSalt.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/TrafficLimiter.php b/lib/Persistence/TrafficLimiter.php
index b5c0de6c..0e6a34b0 100644
--- a/lib/Persistence/TrafficLimiter.php
+++ b/lib/Persistence/TrafficLimiter.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Request.php b/lib/Request.php
index 636a0f01..785f0f45 100644
--- a/lib/Request.php
+++ b/lib/Request.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/View.php b/lib/View.php
index d0993dd5..b154ed86 100644
--- a/lib/View.php
+++ b/lib/View.php
@@ -7,7 +7,7 @@
  * @link      https://github.com/PrivateBin/PrivateBin
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   1.3.3
+ * @version   1.3.4
  */
 
 namespace PrivateBin;
diff --git a/lib/Vizhash16x16.php b/lib/Vizhash16x16.php
index 14d8d49e..0292de3c 100644
--- a/lib/Vizhash16x16.php
+++ b/lib/Vizhash16x16.php
@@ -8,7 +8,7 @@
  * @link      http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
  * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- * @version   0.0.5 beta PrivateBin 1.3.3
+ * @version   0.0.5 beta PrivateBin 1.3.4
  */
 
 namespace PrivateBin;
diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php
index faaa9779..87faa556 100644
--- a/tpl/bootstrap.php
+++ b/tpl/bootstrap.php
@@ -72,7 +72,7 @@ endif;
 ?>
 		
 		
-		
+		
 		
 		
 		
diff --git a/tpl/page.php b/tpl/page.php
index 8dc9c0d9..a2cac4f3 100644
--- a/tpl/page.php
+++ b/tpl/page.php
@@ -50,7 +50,7 @@ endif;
 ?>
 		
 		
-		
+		
 		
 		
 		
diff --git a/vendor/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php b/vendor/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php
index d654a951..7e753e81 100644
--- a/vendor/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php
+++ b/vendor/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php
@@ -46,25 +46,28 @@ class SvgGenerator extends BaseGenerator implements GeneratorInterface
         // prepare image
         $w = $this->getPixelRatio() * 5;
         $h = $this->getPixelRatio() * 5;
-        $svg = '';
+        $svg = '';
 
-        $backgroundColor = '#FFFFFF';
+        $backgroundColor = '#FFF';
         $rgbBackgroundColor = $this->getBackgroundColor();
         if (!is_null($rgbBackgroundColor)) {
             $backgroundColor = $this->_toUnderstandableColor($rgbBackgroundColor);
         }
-        $svg .= '';
 
-        $rgbColor = $this->_toUnderstandableColor($this->getColor());
+        $svg .= '';
+
+        $rects = [];
         // draw content
         foreach ($this->getArrayOfSquare() as $lineKey => $lineValue) {
             foreach ($lineValue as $colKey => $colValue) {
                 if (true === $colValue) {
-                    $svg .= '';
+                    $rects[] = 'M'.$colKey.','.$lineKey.'h1v1h-1v-1';
                 }
             }
         }
 
+        $rgbColor = $this->_toUnderstandableColor($this->getColor());
+        $svg .= '';
         $svg .= '';
 
         $this->generatedImage = $svg;
@@ -80,7 +83,7 @@ class SvgGenerator extends BaseGenerator implements GeneratorInterface
     protected function _toUnderstandableColor($color)
     {
         if (is_array($color)) {
-            return 'rgb('.implode(', ', $color).')';
+            return sprintf('#%X%X%X', $color[0], $color[1], $color[2]);
         }
 
         return $color;
diff --git a/vendor/yzalis/identicon/src/Identicon/Identicon.php b/vendor/yzalis/identicon/src/Identicon/Identicon.php
index 08d32f5e..7a8e0887 100644
--- a/vendor/yzalis/identicon/src/Identicon/Identicon.php
+++ b/vendor/yzalis/identicon/src/Identicon/Identicon.php
@@ -46,10 +46,10 @@ class Identicon
     /**
      * Display an Identicon image.
      *
-     * @param string $string
-     * @param int    $size
-     * @param string $color
-     * @param string $backgroundColor
+     * @param string       $string
+     * @param int          $size
+     * @param string|array $color
+     * @param string       $backgroundColor
      */
     public function displayImage($string, $size = 64, $color = null, $backgroundColor = null)
     {
@@ -60,10 +60,10 @@ class Identicon
     /**
      * Get an Identicon PNG image data.
      *
-     * @param string $string
-     * @param int    $size
-     * @param string $color
-     * @param string $backgroundColor
+     * @param string       $string
+     * @param int          $size
+     * @param string|array $color
+     * @param string       $backgroundColor
      *
      * @return string
      */
@@ -75,10 +75,10 @@ class Identicon
     /**
      * Get an Identicon PNG image resource.
      *
-     * @param string $string
-     * @param int    $size
-     * @param string $color
-     * @param string $backgroundColor
+     * @param string       $string
+     * @param int          $size
+     * @param string|array $color
+     * @param string       $backgroundColor
      *
      * @return string
      */
@@ -90,10 +90,10 @@ class Identicon
     /**
      * Get an Identicon PNG image data as base 64 encoded.
      *
-     * @param string $string
-     * @param int    $size
-     * @param string $color
-     * @param string $backgroundColor
+     * @param string       $string
+     * @param int          $size
+     * @param string|array $color
+     * @param string       $backgroundColor
      *
      * @return string
      */
@@ -101,13 +101,13 @@ class Identicon
     {
         return sprintf('data:%s;base64,%s', $this->generator->getMimeType(), base64_encode($this->getImageData($string, $size, $color, $backgroundColor)));
     }
-	
+
 	/**
 	 * Get the color of the Identicon
      *
      * Returns an array with RGB values of the Identicon's color. Colors may be NULL if no image has been generated
      * so far (e.g., when calling the method on a new Identicon()).
-	 * 
+	 *
 	 * @return array
 	 */
 	public function getColor()