From cf1b6702152e1de1715ea6dab11a3f67a81814e6 Mon Sep 17 00:00:00 2001
From: Kcchouette <Kcchouette@users.noreply.github.com>
Date: Wed, 20 Sep 2017 11:46:05 +0200
Subject: [PATCH 01/20] Update fr.json

---
 i18n/fr.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/i18n/fr.json b/i18n/fr.json
index 5ac3424..00ca25a 100644
--- a/i18n/fr.json
+++ b/i18n/fr.json
@@ -83,7 +83,7 @@
     "Could not decrypt data (Wrong key?)":
         "Impossible de déchiffrer les données (mauvaise clé ?)",
     "Could not delete the paste, it was not stored in burn after reading mode.":
-        "Impossible de supprimer le paste, car il n'a pas été stoclé en mode \"Effacer après lecture\".",
+        "Impossible de supprimer le paste, car il n'a pas été stocké en mode \"Effacer après lecture\".",
     "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
         "POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce paste ne pourra plus être affiché.",
     "Could not decrypt comment; Wrong key?":
@@ -93,7 +93,7 @@
     "Anonymous":
         "Anonyme",
     "Avatar generated from IP address":
-        "Avatar anonyme (Vizhash de l'adresse IP)",
+        "Avatar généré à partir de l'adresse IP)",
     "Add comment":
         "Ajouter un commentaire",
     "Optional nickname…":
@@ -139,7 +139,7 @@
     "Markdown": "Markdown",
     "Download attachment": "Télécharger la pièce jointe",
     "Cloned: '%s'": "Cloner '%s'",
-    "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
+    "The cloned file '%s' was attached to this paste.": "Le fichier cloné '%s' a été attaché à ce paste.",
     "Attach a file": "Attacher un fichier ",
     "Remove attachment": "Enlever l'attachement",
     "Your browser does not support uploading encrypted files. Please use a newer browser.":
@@ -160,5 +160,5 @@
     "Preparing new paste…": "Préparation du paste…",
     "In case this message never disappears please have a look at <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">this FAQ for information to troubleshoot</a>.":
         "Si ce message ne disparaîssait pas, jetez un oeil à <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">cette FAQ pour des idées de résolution</a> (en Anglais).",
-    "+++ no paste text +++": "+++ no paste text +++"
+    "+++ no paste text +++": "+++ pas de paste-text +++"
 }

From 78f9f5279ac7c88569fe6a8626c272ee69f916e5 Mon Sep 17 00:00:00 2001
From: Kcchouette <Kcchouette@users.noreply.github.com>
Date: Thu, 21 Sep 2017 10:02:25 +0200
Subject: [PATCH 02/20] Remove the last ")"

---
 i18n/fr.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/i18n/fr.json b/i18n/fr.json
index 00ca25a..da9d373 100644
--- a/i18n/fr.json
+++ b/i18n/fr.json
@@ -93,7 +93,7 @@
     "Anonymous":
         "Anonyme",
     "Avatar generated from IP address":
-        "Avatar généré à partir de l'adresse IP)",
+        "Avatar généré à partir de l'adresse IP",
     "Add comment":
         "Ajouter un commentaire",
     "Optional nickname…":

From 7197705d5c91237e1f269b6cee5b649956b0ded1 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Tue, 3 Oct 2017 19:45:47 +0200
Subject: [PATCH 03/20] updating unit test in preparation for planned file name
 change, currently failing

---
 cfg/{conf.ini.sample => conf.sample.php} | 1 +
 tst/Bootstrap.php                        | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)
 rename cfg/{conf.ini.sample => conf.sample.php} (99%)

diff --git a/cfg/conf.ini.sample b/cfg/conf.sample.php
similarity index 99%
rename from cfg/conf.ini.sample
rename to cfg/conf.sample.php
index d457b89..a28cdfb 100644
--- a/cfg/conf.ini.sample
+++ b/cfg/conf.sample.php
@@ -1,3 +1,4 @@
+;<?php
 ; config file for PrivateBin
 ;
 ; An explanation of each setting can be find online at https://github.com/PrivateBin/PrivateBin/wiki/Configuration.
diff --git a/tst/Bootstrap.php b/tst/Bootstrap.php
index dfae0ed..2998471 100644
--- a/tst/Bootstrap.php
+++ b/tst/Bootstrap.php
@@ -12,10 +12,10 @@ if (!defined('PATH')) {
     define('PATH', '..' . DIRECTORY_SEPARATOR);
 }
 if (!defined('CONF')) {
-    define('CONF', PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini');
+    define('CONF', PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php');
 }
 if (!is_file(CONF)) {
-    copy(CONF . '.sample', CONF);
+    copy(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php', CONF);
 }
 
 require PATH . 'vendor/autoload.php';

From f037967820b2df6eeb85d3f28c1a6b1240ae49ad Mon Sep 17 00:00:00 2001
From: rugk <rugk@posteo.de>
Date: Fri, 29 Sep 2017 18:59:02 +0200
Subject: [PATCH 04/20] changes the file extension to php and adds a small
 one-liner to stop PHP from presenting the file to any website visitor

Signed-off-by: El RIDO <elrido@gmx.net>
---
 lib/Configuration.php | 2 +-
 tst/JsonApiTest.php   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index b6b9f6f..d9d70bf 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -100,7 +100,7 @@ class Configuration
     public function __construct()
     {
         $config     = array();
-        $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
+        $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php';
         if (is_readable($configFile)) {
             $config = parse_ini_file($configFile, true);
             foreach (array('main', 'model', 'model_options') as $section) {
diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php
index a592889..cd27cd8 100644
--- a/tst/JsonApiTest.php
+++ b/tst/JsonApiTest.php
@@ -283,7 +283,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
         $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
-        $_GET['jsonld'] = '../cfg/conf.ini';
+        $_GET['jsonld'] = CONF;
         ob_start();
         new PrivateBin;
         $content = ob_get_contents();

From 6625a9dc59944cd47d575d8dbbeb10934595600a Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Tue, 3 Oct 2017 20:33:24 +0200
Subject: [PATCH 05/20] hiding INI contents from StyleCI

---
 cfg/conf.sample.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php
index a28cdfb..f52028c 100644
--- a/cfg/conf.sample.php
+++ b/cfg/conf.sample.php
@@ -1,4 +1,4 @@
-;<?php
+;<?php /*
 ; config file for PrivateBin
 ;
 ; An explanation of each setting can be find online at https://github.com/PrivateBin/PrivateBin/wiki/Configuration.

From 9af79467a0e62cf6b78b49221d60ec95b8500d10 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Tue, 3 Oct 2017 20:34:39 +0200
Subject: [PATCH 06/20] ask composer in TravisCI to use an oauth token to avoid
 rate limiting

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index b18d048..084a76d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,7 @@ install:
   - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install 4
 
 before_script:
+  - composer config -g github-oauth.github.com "$GITHUB_TOKEN"
   - composer install -n
   - npm install -g mocha
   - cd js

From ed04fe3b4ca905930b4994a0ae7120a3f10dddb9 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Tue, 3 Oct 2017 20:49:36 +0200
Subject: [PATCH 07/20] disabling two new options that do no match our style
 guidelines

---
 .styleci.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.styleci.yml b/.styleci.yml
index 002616b..0c7ba38 100644
--- a/.styleci.yml
+++ b/.styleci.yml
@@ -11,6 +11,8 @@ enabled:
 disabled:
   - blank_line_after_opening_tag
   - blank_line_before_return
+  - blank_line_before_throw
+  - blank_line_before_try
   - concat_without_spaces
   - declare_equal_normalize
   - heredoc_to_nowdoc

From 6fa2bfe30e1a4fffa809bce4557cebf186edec5c Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Wed, 4 Oct 2017 20:05:46 +0200
Subject: [PATCH 08/20] updated documentation, incremented version

---
 CHANGELOG.md                            |   2 +
 INSTALL.md                              | 159 +++++++++++++++++++++++-
 README.md                               |   2 +-
 css/bootstrap/privatebin.css            |   2 +-
 css/noscript.css                        |   2 +-
 css/privatebin.css                      |   2 +-
 js/privatebin.js                        |   2 +-
 lib/Configuration.php                   |   2 +-
 lib/Data/AbstractData.php               |   2 +-
 lib/Data/Database.php                   |   2 +-
 lib/Data/Filesystem.php                 |   2 +-
 lib/Filter.php                          |   2 +-
 lib/I18n.php                            |   2 +-
 lib/Json.php                            |   2 +-
 lib/Model.php                           |   2 +-
 lib/Model/AbstractModel.php             |   2 +-
 lib/Model/Comment.php                   |   2 +-
 lib/Model/Paste.php                     |   2 +-
 lib/Persistence/AbstractPersistence.php |   2 +-
 lib/Persistence/PurgeLimiter.php        |   2 +-
 lib/Persistence/ServerSalt.php          |   2 +-
 lib/Persistence/TrafficLimiter.php      |   2 +-
 lib/PrivateBin.php                      |   4 +-
 lib/Request.php                         |   2 +-
 lib/Sjcl.php                            |   2 +-
 lib/View.php                            |   2 +-
 lib/Vizhash16x16.php                    |   2 +-
 tpl/bootstrap.php                       |   2 +-
 tpl/page.php                            |   2 +-
 29 files changed, 188 insertions(+), 29 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 964d4ee..8e77d86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
     * CHANGED: Minimum required PHP version is 5.4 (#186)
     * CHANGED: Shipped .htaccess files were updated for Apache 2.4 (#192)
     * CHANGED: Cleanup of bootstrap template variants and moved icons to `img` directory
+  * **1.1.1 (2017-10-06)**
+    * CHANGED: Switched to `.php` file extension for configuration file, to avoid leaking configuration data in unprotected installation.
   * **1.1 (2016-12-26)**
     * ADDED: Translations for Italian and Russian
     * ADDED: Loading message displayed until decryption succeeded for slower (in terms of CPU or network) systems
diff --git a/INSTALL.md b/INSTALL.md
index 7e5fa31..6eebfe9 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1 +1,158 @@
-For installation instructions, see [our wiki](https://github.com/PrivateBin/PrivateBin/wiki/Installation).
+# Installation
+
+**TL;DR:** Download the
+[latest release archive](https://github.com/PrivateBin/PrivateBin/releases/latest)
+and extract it in your web hosts folder where you want to install your PrivateBin
+instance. We try to provide a mostly safe default configuration, but we urge you to
+check the [security section](#hardening-and-security) below and the [configuration
+options](#configuration) to adjust as you see fit.
+
+**NOTE:** See [our FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-can-i-securely-clonedownload-your-project) for information how to securely download the PrivateBin release files.
+
+### Minimal requirements
+
+- PHP version 5.4 or above
+- _one_ of the following sources of cryptographically safe randomness is required:
+  - PHP 7 or higher
+  - [Libsodium](https://download.libsodium.org/libsodium/content/installation/) and it's [PHP extension](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium)
+  - open_basedir access to `/dev/urandom`
+  - mcrypt extension
+  - com_dotnet extension
+  
+  Mcrypt needs to be able to access `/dev/urandom`. This means if `open_basedir` is set, it must include this file.
+- GD extension
+- some disk space or (optionally) a database supported by [PDO](https://secure.php.net/manual/book.pdo.php)
+- ability to create files and folders in the installation directory and the PATH defined in index.php
+- A web browser with javascript support
+
+## Hardening and security
+
+### Changing the path
+
+In the index.php you can define a different `PATH`. This is useful to secure your
+installation. You can move the configuration, data files, templates and PHP
+libraries (directories cfg, doc, data, lib, tpl, tst and vendor) outside of your
+document root. This new location must still be accessible to your webserver / PHP
+process (see also
+[open_basedir setting](https://secure.php.net/manual/en/ini.core.php#ini.open-basedir)).
+
+> #### PATH Example
+> Your PrivateBin installation lives in a subfolder called "paste" inside of
+> your document root. The URL looks like this:
+> http://example.com/paste/
+>
+> The full path of PrivateBin on your webserver is:
+> /home/example.com/htdocs/paste
+> 
+> When setting the path like this:
+> define('PATH', '../../secret/privatebin/');
+>
+> PrivateBin will look for your includes / data here:
+> /home/example.com/secret/privatebin
+
+### Transport security
+
+When setting up PrivateBin, also set up HTTPS, if you haven't already. Without HTTPS
+PrivateBin is not secure, as the javascript files could be manipulated during transmission.
+For more information on this, see our [FAQ entry on HTTPS setup](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-should-i-setup-https).
+
+## Configuration
+
+In the file `cfg/conf.php` you can configure PrivateBin. A `cfg/conf.sample.php`
+is provided containing all options and default values. You can copy it to
+`cfg/conf.php` and adapt it as needed. The config file is divided into multiple
+sections, which are enclosed in square brackets.
+
+In the `[main]` section you can enable or disable the discussion feature, set
+the limit of stored pastes and comments in bytes. The `[traffic]` section lets
+you set a time limit in seconds. Users may not post more often then this limit
+to your PrivateBin installation.
+
+More details can be found in the
+[configuration documentation](https://github.com/PrivateBin/PrivateBin/wiki/Configuration).
+
+## Advanced installation
+
+### Web server configuration
+
+A `robots.txt` file is provided in the root dir of PrivateBin. It disallows all
+robots from accessing your pastes. It is recommend to place it into the root of
+your web directory if you have installed PrivateBin in a subdirectory. Make sure
+to adjust it, so that the file paths match your installation. Of course also
+adjust the file if you already use a `robots.txt`.
+
+A `.htaccess.disabled` file is provided in the root dir of PrivateBin. It blocks
+some known robots and link-scanning bots. If you use Apache, you can rename the
+file to `.htaccess` to enable this feature. If you use another webserver, you
+have to configure it manually to do the same.
+
+### On using Cloudflare
+
+If you want to use PrivateBin behind Cloudflare, make sure you have disabled the Rocket
+loader and unchecked "Javascript" for Auto Minify, found in your domain settings,
+under "Speed". (More information
+[in this FAQ entry](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#user-content-how-to-make-privatebin-work-when-using-cloudflare-for-ddos-protection))
+
+### Using a database instead of flat files
+
+In the configuration file the `[model]` and `[model_options]` sections let you
+configure your favourite way of storing the pastes and discussions on your
+server.
+
+`Filesystem` is the default model, which stores everything in files in the
+data folder. This is the recommended setup for most sites.
+
+Under high load, in distributed setups or if you are not allowed to store files
+locally, you might want to switch to the `Database` model. This lets you
+store your data in a database. Basically all databases that are supported by
+[PDO](https://secure.php.net/manual/en/book.pdo.php) may be used. Automatic table
+creation is provided for `pdo_ibm`, `pdo_informix`, `pdo_mssql`, `pdo_mysql`,
+`pdo_oci`, `pdo_pgsql` and `pdo_sqlite`. You may want to provide a table prefix,
+if you have to share the PrivateBin database with another application or you want
+to use a prefix for
+[security reasons](https://security.stackexchange.com/questions/119510/is-using-a-db-prefix-for-tables-more-secure).
+The table prefix option is called `tbl`.
+
+> #### Note
+> The `Database` model has only been tested with SQLite, MySQL and PostgreSQL,
+> although it would not be recommended to use SQLite in a production environment.
+> If you gain any experience running PrivateBin on other RDBMS, please let us
+> know.
+
+For reference or if you want to create the table schema for yourself (replace
+`prefix_` with your own table prefix and create the table schema with phpMyAdmin
+or the MYSQL console):
+
+```sql
+CREATE TABLE prefix_paste (
+    dataid CHAR(16) NOT NULL,
+    data BLOB,
+    postdate INT,
+    expiredate INT,
+    opendiscussion INT,
+    burnafterreading INT,
+    meta TEXT,
+    attachment MEDIUMBLOB,
+    attachmentname BLOB,
+    PRIMARY KEY (dataid)
+);
+
+CREATE TABLE prefix_comment (
+    dataid CHAR(16),
+    pasteid CHAR(16),
+    parentid CHAR(16),
+    data BLOB,
+    nickname BLOB,
+    vizhash BLOB,
+    postdate INT,
+    PRIMARY KEY (dataid)
+);
+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.1');
+```
+
+In PostgreSQL, the attachment column needs to be TEXT and not BLOB or MEDIUMBLOB.
diff --git a/README.md b/README.md
index 802942c..483f081 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin)
 [![Test Coverage](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/coverage.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin/coverage) [![Code Coverage](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
 
-*Current version: 1.1*
+*Current version: 1.1.1*
 
 **PrivateBin** is a minimalist, open source online pastebin where the server has
 zero knowledge of pasted data.
diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css
index ded8259..d2ba47c 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.1
+ * @version   1.1.1
  */
 
 body {
diff --git a/css/noscript.css b/css/noscript.css
index 97ef60d..26c6bad 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.0
+ * @version   1.1.1
  */
 
 /* When there is no script at all other */
diff --git a/css/privatebin.css b/css/privatebin.css
index d3c79b4..077e8ba 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.1
+ * @version   1.1.1
  */
 
 /*  CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
diff --git a/js/privatebin.js b/js/privatebin.js
index 8cf7683..9e626e9 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.1
+ * @version   1.1.1
  * @name      PrivateBin
  * @namespace
  */
diff --git a/lib/Configuration.php b/lib/Configuration.php
index d9d70bf..a9c8a75 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Data/AbstractData.php b/lib/Data/AbstractData.php
index 41260f8..f4960f9 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Data/Database.php b/lib/Data/Database.php
index c35df3b..2c844ef 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php
index 4100e29..53508e0 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Data;
diff --git a/lib/Filter.php b/lib/Filter.php
index 951e265..4c0a22e 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/I18n.php b/lib/I18n.php
index 2bee73e..5ae9bad 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Json.php b/lib/Json.php
index 27993f9..ad96333 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Model.php b/lib/Model.php
index d1011f1..b4f084f 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Model/AbstractModel.php b/lib/Model/AbstractModel.php
index 55956b7..0ac2317 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php
index b67742d..709cdee 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php
index fae808e..1bac7c8 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Model;
diff --git a/lib/Persistence/AbstractPersistence.php b/lib/Persistence/AbstractPersistence.php
index 64fb530..2e31622 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/PurgeLimiter.php b/lib/Persistence/PurgeLimiter.php
index 2eb0b52..c4affac 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/ServerSalt.php b/lib/Persistence/ServerSalt.php
index 129a099..a4d0686 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/Persistence/TrafficLimiter.php b/lib/Persistence/TrafficLimiter.php
index 914450a..9f35e5d 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin\Persistence;
diff --git a/lib/PrivateBin.php b/lib/PrivateBin.php
index c817445..7b53fa1 100644
--- a/lib/PrivateBin.php
+++ b/lib/PrivateBin.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.1.1
  */
 
 namespace PrivateBin;
@@ -28,7 +28,7 @@ class PrivateBin
      *
      * @const string
      */
-    const VERSION = '1.1';
+    const VERSION = '1.1.1';
 
     /**
      * minimal required PHP version
diff --git a/lib/Request.php b/lib/Request.php
index 37c0bca..f6daa50 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Sjcl.php b/lib/Sjcl.php
index 4ed76b4..7efc7b2 100644
--- a/lib/Sjcl.php
+++ b/lib/Sjcl.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.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/View.php b/lib/View.php
index 6c04e47..8b25395 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.1
+ * @version   1.1.1
  */
 
 namespace PrivateBin;
diff --git a/lib/Vizhash16x16.php b/lib/Vizhash16x16.php
index e9bd5d0..3baae6d 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.1
+ * @version   0.0.5 beta PrivateBin 1.1.1
  */
 
 namespace PrivateBin;
diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php
index 7993e43..103037e 100644
--- a/tpl/bootstrap.php
+++ b/tpl/bootstrap.php
@@ -69,7 +69,7 @@ if ($MARKDOWN):
 <?php
 endif;
 ?>
-		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-7WGautcQxef6PeNh1sNcdCFCNRNo2uULN7QCgjqd+fWalRubtu1mtMEz8BLQ8sKgzPRF8E6dqgBQJ5ycwt03gA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-gTAGAlxWTLH1PaXA4q9l0kME8wPPWi2iub5uU7HZ3A2bisLtjMIsaZ/Ecu4+sawFvvedAzbh9Y4rR34Ct3oF5Q==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->
diff --git a/tpl/page.php b/tpl/page.php
index 46b8df1..81d7c1a 100644
--- a/tpl/page.php
+++ b/tpl/page.php
@@ -47,7 +47,7 @@ if ($MARKDOWN):
 <?php
 endif;
 ?>
-		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-7WGautcQxef6PeNh1sNcdCFCNRNo2uULN7QCgjqd+fWalRubtu1mtMEz8BLQ8sKgzPRF8E6dqgBQJ5ycwt03gA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-gTAGAlxWTLH1PaXA4q9l0kME8wPPWi2iub5uU7HZ3A2bisLtjMIsaZ/Ecu4+sawFvvedAzbh9Y4rR34Ct3oF5Q==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->

From b60d55236e81da053d72fbe3f910315ed6e3541e Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Wed, 4 Oct 2017 20:31:37 +0200
Subject: [PATCH 09/20] adding test for INI config file conversion

---
 tst/ConfigurationTest.php | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php
index 3b9b442..b98425e 100644
--- a/tst/ConfigurationTest.php
+++ b/tst/ConfigurationTest.php
@@ -12,7 +12,7 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
     {
         /* Setup Routine */
         Helper::confBackup();
-        $this->_options                         = configuration::getDefaults();
+        $this->_options                         = Configuration::getDefaults();
         $this->_options['model_options']['dir'] = PATH . $this->_options['model_options']['dir'];
         $this->_options['traffic']['dir']       = PATH . $this->_options['traffic']['dir'];
         $this->_options['purge']['dir']         = PATH . $this->_options['purge']['dir'];
@@ -135,4 +135,26 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
         $conf = new Configuration;
         $this->assertEquals('Database', $conf->getKey('class', 'model'), 'old db class gets renamed');
     }
+
+    public function testHandleConfigFileRename()
+    {
+        $options                           = $this->_options;
+        Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample', $options);
+
+        $options['main']['opendiscussion'] = true;
+        $options['main']['fileupload']     = true;
+        $options['main']['template']       = 'darkstrap';
+        Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $options);
+
+        $conf = new Configuration;
+        $this->assertFileExists(CONF, 'old configuration file gets converted');
+        $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', 'old configuration file gets removed');
+        $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample', 'old configuration sample file gets removed');
+        $this->assertTrue(
+            $conf->getKey('opendiscussion') &&
+            $conf->getKey('fileupload') &&
+            $conf->getKey('template') === 'darkstrap',
+            'configuration values get converted'
+        );
+    }
 }

From 6e8eafe12938b3733a753dc59dd2f31c5501ac4d Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Wed, 4 Oct 2017 21:55:03 +0200
Subject: [PATCH 10/20] implemented INI cenversion functionality

---
 lib/Configuration.php     | 28 ++++++++++++++++++++++++++++
 lib/Data/Database.php     |  5 ++---
 tst/ConfigurationTest.php | 16 ++++++++++++++++
 3 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index a9c8a75..4b7d35c 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -101,6 +101,33 @@ class Configuration
     {
         $config     = array();
         $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php';
+        $configIni  = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
+
+        // rename INI files to avoid configuration leakage
+        if (is_readable($configIni)) {
+            // don't overwrite already converted file
+            if (!is_file($configFile)) {
+                $iniUpgradeError = false;
+                $context = stream_context_create();
+                $iniHandle = fopen($configIni, 'r', 1, $context);
+                $written = file_put_contents($configFile, ';<?php /*' . PHP_EOL);
+                $written = file_put_contents($configFile, $iniHandle, FILE_APPEND);
+                fclose($iniHandle);
+                unlink($configIni);
+            }
+
+            // cleanup sample, too
+            $configSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
+            $configIniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
+            if (is_readable($configIniSample)) {
+                if (is_readable($configSample)) {
+                    unlink($configIniSample);
+                } else {
+                    rename($configIniSample, $configSample);
+                }
+            }
+        }
+
         if (is_readable($configFile)) {
             $config = parse_ini_file($configFile, true);
             foreach (array('main', 'model', 'model_options') as $section) {
@@ -109,6 +136,7 @@ class Configuration
                 }
             }
         }
+
         $opts = '_options';
         foreach (self::getDefaults() as $section => $values) {
             // fill missing sections with default values
diff --git a/lib/Data/Database.php b/lib/Data/Database.php
index 2c844ef..9685edd 100644
--- a/lib/Data/Database.php
+++ b/lib/Data/Database.php
@@ -693,9 +693,8 @@ class Database extends AbstractData
                     'CREATE INDEX IF NOT EXISTS comment_parent ON ' .
                     self::_sanitizeIdentifier('comment') . '(pasteid);'
                 );
-                // no break, continue with updates for 0.22
-            case '0.22':
-            case '1.0':
+                // no break, continue with updates for 0.22 and later
+            default:
                 self::_exec(
                     'UPDATE ' . self::_sanitizeIdentifier('config') .
                     ' SET value = ? WHERE id = ?',
diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php
index b98425e..55d8288 100644
--- a/tst/ConfigurationTest.php
+++ b/tst/ConfigurationTest.php
@@ -157,4 +157,20 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
             'configuration values get converted'
         );
     }
+
+    public function testRenameIniSample()
+    {
+        $iniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
+        $phpSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
+
+        Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $this->_options);
+        if (is_file(CONF)) {
+            chmod(CONF, 0600);
+            unlink(CONF);
+        }
+        rename($phpSample, $iniSample);
+        new Configuration;
+        $this->assertFileNotExists($iniSample, 'old sample file gets removed');
+        $this->assertFileExists($phpSample, 'new sample file gets created');
+    }
 }

From 62f0b95377ae72986deef0aa994c9ee83638c3bd Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Wed, 4 Oct 2017 22:02:27 +0200
Subject: [PATCH 11/20] making StyleCI happy

---
 lib/Configuration.php | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index 4b7d35c..36ef91a 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -108,16 +108,16 @@ class Configuration
             // don't overwrite already converted file
             if (!is_file($configFile)) {
                 $iniUpgradeError = false;
-                $context = stream_context_create();
+                $context   = stream_context_create();
                 $iniHandle = fopen($configIni, 'r', 1, $context);
-                $written = file_put_contents($configFile, ';<?php /*' . PHP_EOL);
-                $written = file_put_contents($configFile, $iniHandle, FILE_APPEND);
+                $written   = file_put_contents($configFile, ';<?php /*' . PHP_EOL);
+                $written   = file_put_contents($configFile, $iniHandle, FILE_APPEND);
                 fclose($iniHandle);
                 unlink($configIni);
             }
 
             // cleanup sample, too
-            $configSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
+            $configSample    = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
             $configIniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
             if (is_readable($configIniSample)) {
                 if (is_readable($configSample)) {

From dbfb1e83bac66ae25cb84736bed261df85a75697 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Wed, 4 Oct 2017 22:06:39 +0200
Subject: [PATCH 12/20] removing dead code

---
 lib/Configuration.php | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index 36ef91a..b7590db 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -107,9 +107,7 @@ class Configuration
         if (is_readable($configIni)) {
             // don't overwrite already converted file
             if (!is_file($configFile)) {
-                $iniUpgradeError = false;
-                $context   = stream_context_create();
-                $iniHandle = fopen($configIni, 'r', 1, $context);
+                $iniHandle = fopen($configIni, 'r', false, stream_context_create());
                 $written   = file_put_contents($configFile, ';<?php /*' . PHP_EOL);
                 $written   = file_put_contents($configFile, $iniHandle, FILE_APPEND);
                 fclose($iniHandle);

From 4ded4b7f8c4a33f0f305ed949f707335a2001880 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 07:03:53 +0200
Subject: [PATCH 13/20] adding correct HTTP error to response, as per @rugk's
 recommentation

---
 cfg/conf.sample.php   | 2 +-
 lib/Configuration.php | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php
index f52028c..4db8a33 100644
--- a/cfg/conf.sample.php
+++ b/cfg/conf.sample.php
@@ -1,4 +1,4 @@
-;<?php /*
+;<?php http_response_code(403); /*
 ; config file for PrivateBin
 ;
 ; An explanation of each setting can be find online at https://github.com/PrivateBin/PrivateBin/wiki/Configuration.
diff --git a/lib/Configuration.php b/lib/Configuration.php
index b7590db..db00ecb 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -108,7 +108,7 @@ class Configuration
             // don't overwrite already converted file
             if (!is_file($configFile)) {
                 $iniHandle = fopen($configIni, 'r', false, stream_context_create());
-                $written   = file_put_contents($configFile, ';<?php /*' . PHP_EOL);
+                $written   = file_put_contents($configFile, ';<?php http_response_code(403); /*' . PHP_EOL);
                 $written   = file_put_contents($configFile, $iniHandle, FILE_APPEND);
                 fclose($iniHandle);
                 unlink($configIni);

From 577586c47f501923277e410a41d7f43eba7ae6bb Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 07:46:28 +0200
Subject: [PATCH 14/20] wrote a unit test to generate old style pastes and
 comments and check that the purge converts them to PHP files

---
 tst/Data/FilesystemTest.php | 42 +++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php
index e7e6dc8..e5b8264 100644
--- a/tst/Data/FilesystemTest.php
+++ b/tst/Data/FilesystemTest.php
@@ -130,4 +130,46 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
         $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
         $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
     }
+
+    public function testOldFilesGetConverted()
+    {
+        // generate 10 (default purge batch size) pastes in the old format
+        $paste = Helper::getPaste();
+        $comment = Helper::getComment();
+        $commentid = Helper::getCommentId();
+        $ids = array();
+        for ($i = 0, $max = 10; $i < $max; ++$i) {
+            // PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/
+            $dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) .
+                str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT);
+            $storagedir = $this->_path . DIRECTORY_SEPARATOR  . substr($dataid, 0, 2) .
+                DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR;
+            $ids[$dataid] = $storagedir;
+
+            if (!is_dir($storagedir)) {
+                mkdir($storagedir, 0700, true);
+            }
+            file_put_contents($storagedir . $dataid, json_encode($paste));
+
+            $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR;
+            if (!is_dir($storagedir)) {
+                mkdir($storagedir, 0700, true);
+            }
+            file_put_contents($storagedir . $dataid . '.' . $commentid . '.' . $dataid, json_encode($comment));
+        }
+        // check that all 10 pastes were converted after the purge
+        $this->_model->purge(10);
+        foreach ($ids as $dataid => $storagedir) {
+            $this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format");
+            $this->assertFileNotExists($storagedir . $dataid, "old format paste $dataid got removed");
+            $this->assertTrue($this->_model->exists($dataid), "paste $dataid exists");
+            $this->assertEquals($this->_model->read($dataid), $paste, "paste $dataid wasn't modified in the conversion");
+
+            $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR;
+            $this->assertFileExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php', "comment of $dataid exists in new format");
+            $this->assertFileNotExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid, "old format comment of $dataid got removed");
+            $this->assertTrue($this->_model->existsComment($dataid, $dataid, $commentid), "comment in paste $dataid exists");
+            $this->assertEquals($this->_model->readComment($dataid, $dataid, $commentid), $comment, "comment of $dataid wasn't modified in the conversion");
+        }
+    }
 }

From 4f06feef81293ba446e76138b3aedaa642e749ce Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 11:03:17 +0200
Subject: [PATCH 15/20] implemented JSON file conversion on purge and storage
 in PHP files for data leak protection

---
 lib/Configuration.php         | 26 ++++++++----
 lib/Data/Filesystem.php       | 77 +++++++++++++++++++++++++++++------
 lib/Persistence/DataStore.php |  9 +++-
 tst/Bootstrap.php             | 10 ++++-
 tst/ConfigurationTest.php     | 16 +++++---
 tst/Data/FilesystemTest.php   |  7 +++-
 tst/JsonApiTest.php           | 35 ++++------------
 tst/ModelTest.php             |  7 +---
 tst/PrivateBinTest.php        | 72 ++------------------------------
 tst/PrivateBinWithDbTest.php  |  4 --
 10 files changed, 127 insertions(+), 136 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index db00ecb..baee718 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -22,6 +22,13 @@ use PDO;
  */
 class Configuration
 {
+    /**
+     * First line in INI file, to hide contents
+     *
+     * @const string
+     */
+    const PROTECTION_LINE = ';<?php http_response_code(403); /*' . PHP_EOL;
+
     /**
      * parsed configuration
      *
@@ -105,24 +112,27 @@ class Configuration
 
         // rename INI files to avoid configuration leakage
         if (is_readable($configIni)) {
+            $context = stream_context_create();
             // don't overwrite already converted file
             if (!is_file($configFile)) {
-                $iniHandle = fopen($configIni, 'r', false, stream_context_create());
-                $written   = file_put_contents($configFile, ';<?php http_response_code(403); /*' . PHP_EOL);
-                $written   = file_put_contents($configFile, $iniHandle, FILE_APPEND);
+                $iniHandle = fopen($configIni, 'r', false, $context);
+                file_put_contents($configFile, self::PROTECTION_LINE);
+                file_put_contents($configFile, $iniHandle, FILE_APPEND);
                 fclose($iniHandle);
-                unlink($configIni);
             }
+            unlink($configIni);
 
             // cleanup sample, too
             $configSample    = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
             $configIniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
             if (is_readable($configIniSample)) {
-                if (is_readable($configSample)) {
-                    unlink($configIniSample);
-                } else {
-                    rename($configIniSample, $configSample);
+                if (!is_readable($configSample)) {
+                    $iniSampleHandle = fopen($configIniSample, 'r', false, $context);
+                    file_put_contents($configSample, self::PROTECTION_LINE);
+                    file_put_contents($configSample, $iniSampleHandle, FILE_APPEND);
+                    fclose($iniSampleHandle);
                 }
+                unlink($configIniSample);
             }
         }
 
diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php
index 53508e0..14a3a14 100644
--- a/lib/Data/Filesystem.php
+++ b/lib/Data/Filesystem.php
@@ -57,7 +57,7 @@ class Filesystem extends AbstractData
     public function create($pasteid, $paste)
     {
         $storagedir = self::_dataid2path($pasteid);
-        $file       = $storagedir . $pasteid;
+        $file       = $storagedir . $pasteid . '.php';
         if (is_file($file)) {
             return false;
         }
@@ -79,9 +79,7 @@ class Filesystem extends AbstractData
         if (!$this->exists($pasteid)) {
             return false;
         }
-        $paste = json_decode(
-            file_get_contents(self::_dataid2path($pasteid) . $pasteid)
-        );
+        $paste = self::_decodeFile(self::_dataid2path($pasteid) . $pasteid . '.php');
         if (property_exists($paste->meta, 'attachment')) {
             $paste->attachment = $paste->meta->attachment;
             unset($paste->meta->attachment);
@@ -104,8 +102,8 @@ class Filesystem extends AbstractData
         $pastedir = self::_dataid2path($pasteid);
         if (is_dir($pastedir)) {
             // Delete the paste itself.
-            if (is_file($pastedir . $pasteid)) {
-                unlink($pastedir . $pasteid);
+            if (is_file($pastedir . $pasteid . '.php')) {
+                unlink($pastedir . $pasteid . '.php');
             }
 
             // Delete discussion if it exists.
@@ -133,7 +131,41 @@ class Filesystem extends AbstractData
      */
     public function exists($pasteid)
     {
-        return is_file(self::_dataid2path($pasteid) . $pasteid);
+        $basePath  = self::_dataid2path($pasteid) . $pasteid;
+        $pastePath = $basePath . '.php';
+        // convert to PHP protected files if needed
+        if (is_readable($basePath)) {
+            $context = stream_context_create();
+            // don't overwrite already converted file
+            if (!is_file($pastePath)) {
+                $handle = fopen($basePath, 'r', false, $context);
+                file_put_contents($pastePath, DataStore::PROTECTION_LINE . PHP_EOL);
+                file_put_contents($pastePath, $handle, FILE_APPEND);
+                fclose($handle);
+            }
+            unlink($basePath);
+
+            // convert comments, too
+            $discdir  = self::_dataid2discussionpath($pasteid);
+            if (is_dir($discdir)) {
+                $dir = dir($discdir);
+                while (false !== ($filename = $dir->read())) {
+                    if (substr($filename, -4) !== '.php' && strlen($filename) >= 16) {
+                        $commentFilename = $discdir . $filename . '.php';
+                        // don't overwrite already converted file
+                        if (!is_file($commentFilename)) {
+                            $handle = fopen($discdir . $filename, 'r', false, $context);
+                            file_put_contents($commentFilename, DataStore::PROTECTION_LINE . PHP_EOL);
+                            file_put_contents($commentFilename, $handle, FILE_APPEND);
+                            fclose($handle);
+                        }
+                        unlink($discdir . $filename);
+                    }
+                }
+                $dir->close();
+            }
+        }
+        return is_readable($pastePath);
     }
 
     /**
@@ -149,7 +181,7 @@ class Filesystem extends AbstractData
     public function createComment($pasteid, $parentid, $commentid, $comment)
     {
         $storagedir = self::_dataid2discussionpath($pasteid);
-        $file       = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid;
+        $file       = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php';
         if (is_file($file)) {
             return false;
         }
@@ -171,15 +203,14 @@ class Filesystem extends AbstractData
         $comments = array();
         $discdir  = self::_dataid2discussionpath($pasteid);
         if (is_dir($discdir)) {
-            // Delete all files in discussion directory
             $dir = dir($discdir);
             while (false !== ($filename = $dir->read())) {
-                // Filename is in the form pasteid.commentid.parentid:
+                // Filename is in the form pasteid.commentid.parentid.php:
                 // - pasteid is the paste this reply belongs to.
                 // - commentid is the comment identifier itself.
                 // - parentid is the comment this comment replies to (It can be pasteid)
                 if (is_file($discdir . $filename)) {
-                    $comment = json_decode(file_get_contents($discdir . $filename));
+                    $comment = self::_decodeFile($discdir . $filename);
                     $items   = explode('.', $filename);
                     // Add some meta information not contained in file.
                     $comment->id       = $items[1];
@@ -211,7 +242,7 @@ class Filesystem extends AbstractData
     {
         return is_file(
             self::_dataid2discussionpath($pasteid) .
-            $pasteid . '.' . $commentid . '.' . $parentid
+            $pasteid . '.' . $commentid . '.' . $parentid . '.php'
         );
     }
 
@@ -253,7 +284,14 @@ class Filesystem extends AbstractData
                     continue;
                 }
                 $thirdLevel = array_filter(
-                    scandir($path),
+                    array_map(
+                        function($filename) {
+                            return strlen($filename) >= 20 ?
+                                substr($filename, 0, -4) :
+                                $filename;
+                        },
+                        scandir($path)
+                    ),
                     'PrivateBin\\Model\\Paste::isValidId'
                 );
                 if (count($thirdLevel) == 0) {
@@ -347,4 +385,17 @@ class Filesystem extends AbstractData
     {
         return (bool) preg_match('/^[a-f0-9]{2}$/', $element);
     }
+
+    /**
+     * Decodes a paste or comment file.
+     *
+     * @access private
+     * @static
+     * @param  string $file
+     * @return array
+     */
+    private static function _decodeFile($file)
+    {
+        return json_decode(substr(file_get_contents($file), strlen(DataStore::PROTECTION_LINE . PHP_EOL)));
+    }
 }
diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php
index 56dde1a..0c03f27 100644
--- a/lib/Persistence/DataStore.php
+++ b/lib/Persistence/DataStore.php
@@ -22,6 +22,13 @@ use PrivateBin\Json;
  */
 class DataStore extends AbstractPersistence
 {
+    /**
+     * First line in JSON files, to hide contents
+     *
+     * @const string
+     */
+    const PROTECTION_LINE = '<?php http_response_code(403); /*';
+
     /**
      * store the data
      *
@@ -38,7 +45,7 @@ class DataStore extends AbstractPersistence
             $filename = substr($filename, strlen($path));
         }
         try {
-            self::_store($filename, Json::encode($data));
+            self::_store($filename, self::PROTECTION_LINE . PHP_EOL . Json::encode($data));
             return true;
         } catch (Exception $e) {
             return false;
diff --git a/tst/Bootstrap.php b/tst/Bootstrap.php
index 2998471..a954c40 100644
--- a/tst/Bootstrap.php
+++ b/tst/Bootstrap.php
@@ -14,8 +14,8 @@ if (!defined('PATH')) {
 if (!defined('CONF')) {
     define('CONF', PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php');
 }
-if (!is_file(CONF)) {
-    copy(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php', CONF);
+if (!defined('CONF_SAMPLE')) {
+    define('CONF_SAMPLE', PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php');
 }
 
 require PATH . 'vendor/autoload.php';
@@ -203,6 +203,9 @@ class Helper
         if (!is_file(CONF . '.bak') && is_file(CONF)) {
             rename(CONF, CONF . '.bak');
         }
+        if (!is_file(CONF_SAMPLE . '.bak') && is_file(CONF_SAMPLE)) {
+            copy(CONF_SAMPLE, CONF_SAMPLE . '.bak');
+        }
     }
 
     /**
@@ -215,6 +218,9 @@ class Helper
         if (is_file(CONF . '.bak')) {
             rename(CONF . '.bak', CONF);
         }
+        if (is_file(CONF_SAMPLE . '.bak')) {
+            rename(CONF_SAMPLE . '.bak', CONF_SAMPLE);
+        }
     }
 
     /**
diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php
index 55d8288..66acece 100644
--- a/tst/ConfigurationTest.php
+++ b/tst/ConfigurationTest.php
@@ -22,12 +22,14 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
     public function tearDown()
     {
         /* Tear Down Routine */
+        if (is_file(CONF)) {
+            unlink(CONF);
+        }
         Helper::confRestore();
     }
 
     public function testDefaultConfigFile()
     {
-        $this->assertTrue(copy(CONF . '.bak', CONF), 'copy default configuration file');
         $conf = new Configuration;
         $this->assertEquals($this->_options, $conf->get(), 'default configuration is correct');
     }
@@ -41,7 +43,9 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
 
     public function testHandleMissingConfigFile()
     {
-        @unlink(CONF);
+        if (is_file(CONF)) {
+            unlink(CONF);
+        }
         $conf = new Configuration;
         $this->assertEquals($this->_options, $conf->get(), 'returns correct defaults on missing file');
     }
@@ -161,16 +165,16 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
     public function testRenameIniSample()
     {
         $iniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
-        $phpSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
 
         Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $this->_options);
         if (is_file(CONF)) {
-            chmod(CONF, 0600);
             unlink(CONF);
         }
-        rename($phpSample, $iniSample);
+        rename(CONF_SAMPLE, $iniSample);
         new Configuration;
         $this->assertFileNotExists($iniSample, 'old sample file gets removed');
-        $this->assertFileExists($phpSample, 'new sample file gets created');
+        $this->assertFileExists(CONF_SAMPLE, 'new sample file gets created');
+        $this->assertFileExists(CONF, 'old configuration file gets converted');
+        $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', 'old configuration file gets removed');
     }
 }
diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php
index e5b8264..8b04928 100644
--- a/tst/Data/FilesystemTest.php
+++ b/tst/Data/FilesystemTest.php
@@ -163,13 +163,16 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
             $this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format");
             $this->assertFileNotExists($storagedir . $dataid, "old format paste $dataid got removed");
             $this->assertTrue($this->_model->exists($dataid), "paste $dataid exists");
-            $this->assertEquals($this->_model->read($dataid), $paste, "paste $dataid wasn't modified in the conversion");
+            $this->assertEquals($this->_model->read($dataid), json_decode(json_encode($paste)), "paste $dataid wasn't modified in the conversion");
 
             $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR;
             $this->assertFileExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php', "comment of $dataid exists in new format");
             $this->assertFileNotExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid, "old format comment of $dataid got removed");
             $this->assertTrue($this->_model->existsComment($dataid, $dataid, $commentid), "comment in paste $dataid exists");
-            $this->assertEquals($this->_model->readComment($dataid, $dataid, $commentid), $comment, "comment of $dataid wasn't modified in the conversion");
+            $comment           = json_decode(json_encode($comment));
+            $comment->id       = $commentid;
+            $comment->parentid = $dataid;
+            $this->assertEquals($this->_model->readComments($dataid), array($comment->meta->postdate => $comment), "comment of $dataid wasn't modified in the conversion");
         }
     }
 }
diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php
index cd27cd8..8588aca 100644
--- a/tst/JsonApiTest.php
+++ b/tst/JsonApiTest.php
@@ -14,30 +14,17 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
     public function setUp()
     {
         /* Setup Routine */
-        Helper::confBackup();
         $this->_path  = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
         ServerSalt::setPath($this->_path);
-        $this->reset();
-    }
 
-    public function tearDown()
-    {
-        /* Tear Down Routine */
-        Helper::confRestore();
-        Helper::rmDir($this->_path);
-    }
-
-    public function reset()
-    {
         $_POST   = array();
         $_GET    = array();
         $_SERVER = array();
         if ($this->_model->exists(Helper::getPasteId())) {
             $this->_model->delete(Helper::getPasteId());
         }
-        Helper::confRestore();
-        $options                         = parse_ini_file(CONF, true);
+        $options                         = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['dir']         = $this->_path;
         $options['traffic']['dir']       = $this->_path;
         $options['model_options']['dir'] = $this->_path;
@@ -45,15 +32,21 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
         Helper::createIniFile(CONF, $options);
     }
 
+    public function tearDown()
+    {
+        /* Tear Down Routine */
+        unlink(CONF);
+        Helper::confRestore();
+        Helper::rmDir($this->_path);
+    }
+
     /**
      * @runInSeparateProcess
      */
     public function testCreate()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
@@ -80,10 +73,8 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testPut()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $paste = Helper::getPaste();
         unset($paste['meta']);
@@ -117,7 +108,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testDelete()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $paste = $this->_model->read(Helper::getPasteId());
@@ -144,7 +134,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteWithPost()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $paste = $this->_model->read(Helper::getPasteId());
@@ -168,7 +157,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testRead()
     {
-        $this->reset();
         $paste                           = Helper::getPasteWithAttachment();
         $paste['meta']['attachment']     = $paste['attachment'];
         $paste['meta']['attachmentname'] = $paste['attachmentname'];
@@ -200,7 +188,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testJsonLdPaste()
     {
-        $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_GET['jsonld'] = 'paste';
@@ -220,7 +207,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testJsonLdComment()
     {
-        $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_GET['jsonld'] = 'comment';
@@ -240,7 +226,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testJsonLdPasteMeta()
     {
-        $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_GET['jsonld'] = 'pastemeta';
@@ -260,7 +245,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testJsonLdCommentMeta()
     {
-        $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_GET['jsonld'] = 'commentmeta';
@@ -280,7 +264,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
      */
     public function testJsonLdInvalid()
     {
-        $this->reset();
         $paste = Helper::getPasteWithAttachment();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_GET['jsonld'] = CONF;
diff --git a/tst/ModelTest.php b/tst/ModelTest.php
index 4d314f7..a41ed00 100644
--- a/tst/ModelTest.php
+++ b/tst/ModelTest.php
@@ -20,13 +20,12 @@ class ModelTest extends PHPUnit_Framework_TestCase
     public function setUp()
     {
         /* Setup Routine */
-        Helper::confRestore();
         $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         if (!is_dir($this->_path)) {
             mkdir($this->_path);
         }
         ServerSalt::setPath($this->_path);
-        $options                   = parse_ini_file(CONF, true);
+        $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['limit'] = 0;
         $options['model']          = array(
             'class' => 'Database',
@@ -47,6 +46,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
     public function tearDown()
     {
         /* Tear Down Routine */
+        unlink(CONF);
         Helper::confRestore();
         Helper::rmDir($this->_path);
     }
@@ -327,7 +327,6 @@ class ModelTest extends PHPUnit_Framework_TestCase
             'pwd' => null,
             'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
         );
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
 
@@ -382,7 +381,6 @@ class ModelTest extends PHPUnit_Framework_TestCase
             'pwd' => null,
             'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
         );
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
 
@@ -420,7 +418,6 @@ class ModelTest extends PHPUnit_Framework_TestCase
             'pwd' => null,
             'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
         );
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
 
diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php
index 44df563..e1f3113 100644
--- a/tst/PrivateBinTest.php
+++ b/tst/PrivateBinTest.php
@@ -16,13 +16,13 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
         /* Setup Routine */
         $this->_path  = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
-        ServerSalt::setPath($this->_path);
         $this->reset();
     }
 
     public function tearDown()
     {
         /* Tear Down Routine */
+        unlink(CONF);
         Helper::confRestore();
         Helper::rmDir($this->_path);
     }
@@ -35,13 +35,13 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
         if ($this->_model->exists(Helper::getPasteId())) {
             $this->_model->delete(Helper::getPasteId());
         }
-        Helper::confRestore();
-        $options                         = parse_ini_file(CONF, true);
+        $options                         = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['dir']         = $this->_path;
         $options['traffic']['dir']       = $this->_path;
         $options['model_options']['dir'] = $this->_path;
         Helper::confBackup();
         Helper::createIniFile(CONF, $options);
+        ServerSalt::setPath($this->_path);
     }
 
     /**
@@ -49,7 +49,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testView()
     {
-        $this->reset();
         ob_start();
         new PrivateBin;
         $content = ob_get_contents();
@@ -71,10 +70,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testViewLanguageSelection()
     {
-        $this->reset();
         $options                              = parse_ini_file(CONF, true);
         $options['main']['languageselection'] = true;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_COOKIE['lang'] = 'de';
         ob_start();
@@ -93,11 +90,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testViewForceLanguageDefault()
     {
-        $this->reset();
         $options                              = parse_ini_file(CONF, true);
         $options['main']['languageselection'] = false;
         $options['main']['languagedefault']   = 'fr';
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_COOKIE['lang'] = 'de';
         ob_start();
@@ -117,10 +112,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
     public function testViewUrlShortener()
     {
         $shortener = 'https://shortener.example.com/api?link=';
-        $this->reset();
         $options                         = parse_ini_file(CONF, true);
         $options['main']['urlshortener'] = $shortener;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_COOKIE['lang'] = 'de';
         ob_start();
@@ -139,7 +132,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testHtaccess()
     {
-        $this->reset();
         $file = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
         @unlink($file);
 
@@ -160,8 +152,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testConf()
     {
-        $this->reset();
-        Helper::confBackup();
         file_put_contents(CONF, '');
         new PrivateBin;
     }
@@ -171,10 +161,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreate()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
@@ -200,10 +188,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidTimelimit()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste(array('expire' => 25));
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
@@ -230,11 +216,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidSize()
     {
-        $this->reset();
         $options                      = parse_ini_file(CONF, true);
         $options['main']['sizelimit'] = 10;
         $options['traffic']['limit']  = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
@@ -254,10 +238,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateProxyHeader()
     {
-        $this->reset();
         $options                      = parse_ini_file(CONF, true);
         $options['traffic']['header'] = 'X_FORWARDED_FOR';
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_SERVER['HTTP_X_FORWARDED_FOR']  = '::2';
@@ -284,10 +266,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateDuplicateId()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $_POST                            = Helper::getPaste();
@@ -308,10 +288,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateValidExpire()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['expire']                  = '5min';
@@ -341,10 +319,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateValidExpireWithDiscussion()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['expire']                  = '5min';
@@ -375,10 +351,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidExpire()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['expire']                  = 'foo';
@@ -405,10 +379,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidBurn()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['burnafterreading']        = 'neither 1 nor 0';
@@ -429,10 +401,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidOpenDiscussion()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['opendiscussion']          = 'neither 1 nor 0';
@@ -453,11 +423,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateAttachment()
     {
-        $this->reset();
         $options                       = parse_ini_file(CONF, true);
         $options['traffic']['limit']   = 0;
         $options['main']['fileupload'] = true;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPasteWithAttachment();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
@@ -491,11 +459,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateBrokenAttachmentUpload()
     {
-        $this->reset();
         $options                       = parse_ini_file(CONF, true);
         $options['traffic']['limit']   = 0;
         $options['main']['fileupload'] = true;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST = Helper::getPasteWithAttachment();
         unset($_POST['attachment']);
@@ -517,7 +483,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateTooSoon()
     {
-        $this->reset();
         $_POST                            = Helper::getPaste();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         $_SERVER['REQUEST_METHOD']        = 'POST';
@@ -540,10 +505,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateValidNick()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getPaste();
         $_POST['nickname']                = Helper::getComment()['meta']['nickname'];
@@ -570,10 +533,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidNick()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getCommentPost();
         $_POST['pasteid']                 = Helper::getPasteId();
@@ -597,10 +558,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateComment()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getCommentPost();
         $_POST['pasteid']                 = Helper::getPasteId();
@@ -623,10 +582,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateInvalidComment()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getCommentPost();
         $_POST['pasteid']                 = Helper::getPasteId();
@@ -649,10 +606,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateCommentDiscussionDisabled()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getCommentPost();
         $_POST['pasteid']                 = Helper::getPasteId();
@@ -676,10 +631,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateCommentInvalidPaste()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $_POST                            = Helper::getCommentPost();
         $_POST['pasteid']                 = Helper::getPasteId();
@@ -701,10 +654,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testCreateDuplicateComment()
     {
-        $this->reset();
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment());
@@ -729,7 +680,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testRead()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $_SERVER['QUERY_STRING'] = Helper::getPasteId();
         ob_start();
@@ -750,7 +700,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadInvalidId()
     {
-        $this->reset();
         $_SERVER['QUERY_STRING'] = 'foo';
         ob_start();
         new PrivateBin;
@@ -768,7 +717,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadNonexisting()
     {
-        $this->reset();
         $_SERVER['QUERY_STRING'] = Helper::getPasteId();
         ob_start();
         new PrivateBin;
@@ -786,7 +734,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadExpired()
     {
-        $this->reset();
         $expiredPaste = Helper::getPaste(array('expire_date' => 1344803344));
         $this->_model->create(Helper::getPasteId(), $expiredPaste);
         $_SERVER['QUERY_STRING'] = Helper::getPasteId();
@@ -806,7 +753,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadBurn()
     {
-        $this->reset();
         $burnPaste = Helper::getPaste(array('burnafterreading' => true));
         $this->_model->create(Helper::getPasteId(), $burnPaste);
         $_SERVER['QUERY_STRING'] = Helper::getPasteId();
@@ -860,7 +806,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadJson()
     {
-        $this->reset();
         $paste = Helper::getPaste();
         $this->_model->create(Helper::getPasteId(), $paste);
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
@@ -886,7 +831,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadInvalidJson()
     {
-        $this->reset();
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         ob_start();
@@ -902,7 +846,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadOldSyntax()
     {
-        $this->reset();
         $oldPaste = Helper::getPaste();
         $meta     = array(
             'syntaxcoloring' => true,
@@ -931,7 +874,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testReadOldFormat()
     {
-        $this->reset();
         $oldPaste = Helper::getPaste();
         unset($oldPaste['meta']['formatter']);
         $this->_model->create(Helper::getPasteId(), $oldPaste);
@@ -956,7 +898,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDelete()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $paste               = $this->_model->read(Helper::getPasteId());
@@ -979,7 +920,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteInvalidId()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $_GET['pasteid']     = 'foo';
         $_GET['deletetoken'] = 'bar';
@@ -1000,7 +940,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteInexistantId()
     {
-        $this->reset();
         $_GET['pasteid']     = Helper::getPasteId();
         $_GET['deletetoken'] = 'bar';
         ob_start();
@@ -1019,7 +958,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteInvalidToken()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $_GET['pasteid']     = Helper::getPasteId();
         $_GET['deletetoken'] = 'bar';
@@ -1040,7 +978,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteBurnAfterReading()
     {
-        $this->reset();
         $burnPaste = Helper::getPaste(array('burnafterreading' => true));
         $this->_model->create(Helper::getPasteId(), $burnPaste);
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
@@ -1062,7 +999,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteInvalidBurnAfterReading()
     {
-        $this->reset();
         $this->_model->create(Helper::getPasteId(), Helper::getPaste());
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $_POST['deletetoken']             = 'burnafterreading';
@@ -1083,7 +1019,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteExpired()
     {
-        $this->reset();
         $expiredPaste = Helper::getPaste(array('expire_date' => 1000));
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exist before being created');
         $this->_model->create(Helper::getPasteId(), $expiredPaste);
@@ -1107,7 +1042,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testDeleteMissingPerPasteSalt()
     {
-        $this->reset();
         $paste = Helper::getPaste();
         unset($paste['meta']['salt']);
         $this->_model->create(Helper::getPasteId(), $paste);
diff --git a/tst/PrivateBinWithDbTest.php b/tst/PrivateBinWithDbTest.php
index 2ed3846..a6ec2e0 100644
--- a/tst/PrivateBinWithDbTest.php
+++ b/tst/PrivateBinWithDbTest.php
@@ -23,7 +23,6 @@ class PrivateBinWithDbTest extends PrivateBinTest
         if (!is_dir($this->_path)) {
             mkdir($this->_path);
         }
-        ServerSalt::setPath($this->_path);
         $this->_options['dsn'] = 'sqlite:' . $this->_path . DIRECTORY_SEPARATOR . 'tst.sq3';
         $this->_model          = Database::getInstance($this->_options);
         $this->reset();
@@ -37,10 +36,7 @@ class PrivateBinWithDbTest extends PrivateBinTest
         $options['model'] = array(
             'class' => 'Database',
         );
-        $options['purge']['dir']   = $this->_path;
-        $options['traffic']['dir'] = $this->_path;
         $options['model_options']  = $this->_options;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
     }
 }

From 9f26894b2e7a6416b26f05e049f13a5b6cc51d2e Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 11:31:41 +0200
Subject: [PATCH 16/20] PHP < 5.6 compatibility and StyleCI recommendations

---
 lib/Configuration.php         |  6 +++---
 lib/Data/Filesystem.php       | 19 +++----------------
 lib/Persistence/DataStore.php | 13 +++++++++++++
 tst/Data/FilesystemTest.php   |  8 ++++----
 tst/PrivateBinTest.php        |  2 +-
 tst/PrivateBinWithDbTest.php  |  1 -
 6 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index baee718..5b8813d 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -27,7 +27,7 @@ class Configuration
      *
      * @const string
      */
-    const PROTECTION_LINE = ';<?php http_response_code(403); /*' . PHP_EOL;
+    const PROTECTION_LINE = ';<?php http_response_code(403); /*';
 
     /**
      * parsed configuration
@@ -116,7 +116,7 @@ class Configuration
             // don't overwrite already converted file
             if (!is_file($configFile)) {
                 $iniHandle = fopen($configIni, 'r', false, $context);
-                file_put_contents($configFile, self::PROTECTION_LINE);
+                file_put_contents($configFile, self::PROTECTION_LINE . PHP_EOL);
                 file_put_contents($configFile, $iniHandle, FILE_APPEND);
                 fclose($iniHandle);
             }
@@ -128,7 +128,7 @@ class Configuration
             if (is_readable($configIniSample)) {
                 if (!is_readable($configSample)) {
                     $iniSampleHandle = fopen($configIniSample, 'r', false, $context);
-                    file_put_contents($configSample, self::PROTECTION_LINE);
+                    file_put_contents($configSample, self::PROTECTION_LINE . PHP_EOL);
                     file_put_contents($configSample, $iniSampleHandle, FILE_APPEND);
                     fclose($iniSampleHandle);
                 }
diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php
index 14a3a14..e092476 100644
--- a/lib/Data/Filesystem.php
+++ b/lib/Data/Filesystem.php
@@ -79,7 +79,7 @@ class Filesystem extends AbstractData
         if (!$this->exists($pasteid)) {
             return false;
         }
-        $paste = self::_decodeFile(self::_dataid2path($pasteid) . $pasteid . '.php');
+        $paste = DataStore::get(self::_dataid2path($pasteid) . $pasteid . '.php');
         if (property_exists($paste->meta, 'attachment')) {
             $paste->attachment = $paste->meta->attachment;
             unset($paste->meta->attachment);
@@ -210,7 +210,7 @@ class Filesystem extends AbstractData
                 // - commentid is the comment identifier itself.
                 // - parentid is the comment this comment replies to (It can be pasteid)
                 if (is_file($discdir . $filename)) {
-                    $comment = self::_decodeFile($discdir . $filename);
+                    $comment = DataStore::get($discdir . $filename);
                     $items   = explode('.', $filename);
                     // Add some meta information not contained in file.
                     $comment->id       = $items[1];
@@ -285,7 +285,7 @@ class Filesystem extends AbstractData
                 }
                 $thirdLevel = array_filter(
                     array_map(
-                        function($filename) {
+                        function ($filename) {
                             return strlen($filename) >= 20 ?
                                 substr($filename, 0, -4) :
                                 $filename;
@@ -385,17 +385,4 @@ class Filesystem extends AbstractData
     {
         return (bool) preg_match('/^[a-f0-9]{2}$/', $element);
     }
-
-    /**
-     * Decodes a paste or comment file.
-     *
-     * @access private
-     * @static
-     * @param  string $file
-     * @return array
-     */
-    private static function _decodeFile($file)
-    {
-        return json_decode(substr(file_get_contents($file), strlen(DataStore::PROTECTION_LINE . PHP_EOL)));
-    }
 }
diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php
index 0c03f27..c5f14ff 100644
--- a/lib/Persistence/DataStore.php
+++ b/lib/Persistence/DataStore.php
@@ -51,4 +51,17 @@ class DataStore extends AbstractPersistence
             return false;
         }
     }
+
+    /**
+     * get the data
+     *
+     * @access public
+     * @static
+     * @param  string $filename
+     * @return array  $data
+     */
+    public static function get($filename)
+    {
+        return json_decode(substr(file_get_contents($filename), strlen(self::PROTECTION_LINE . PHP_EOL)));
+    }
 }
diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php
index 8b04928..0a122f0 100644
--- a/tst/Data/FilesystemTest.php
+++ b/tst/Data/FilesystemTest.php
@@ -134,15 +134,15 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
     public function testOldFilesGetConverted()
     {
         // generate 10 (default purge batch size) pastes in the old format
-        $paste = Helper::getPaste();
-        $comment = Helper::getComment();
+        $paste     = Helper::getPaste();
+        $comment   = Helper::getComment();
         $commentid = Helper::getCommentId();
-        $ids = array();
+        $ids       = array();
         for ($i = 0, $max = 10; $i < $max; ++$i) {
             // PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/
             $dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) .
                 str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT);
-            $storagedir = $this->_path . DIRECTORY_SEPARATOR  . substr($dataid, 0, 2) .
+            $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) .
                 DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR;
             $ids[$dataid] = $storagedir;
 
diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php
index e1f3113..5c5e145 100644
--- a/tst/PrivateBinTest.php
+++ b/tst/PrivateBinTest.php
@@ -111,7 +111,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
      */
     public function testViewUrlShortener()
     {
-        $shortener = 'https://shortener.example.com/api?link=';
+        $shortener                       = 'https://shortener.example.com/api?link=';
         $options                         = parse_ini_file(CONF, true);
         $options['main']['urlshortener'] = $shortener;
         Helper::createIniFile(CONF, $options);
diff --git a/tst/PrivateBinWithDbTest.php b/tst/PrivateBinWithDbTest.php
index a6ec2e0..a438d4c 100644
--- a/tst/PrivateBinWithDbTest.php
+++ b/tst/PrivateBinWithDbTest.php
@@ -1,7 +1,6 @@
 <?php
 
 use PrivateBin\Data\Database;
-use PrivateBin\Persistence\ServerSalt;
 
 require_once 'PrivateBinTest.php';
 

From cd5fded4a486fb951f697bd435bcd2924a7c7201 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 12:27:37 +0200
Subject: [PATCH 17/20] adapting configuration test generator to new INI model
 and point release support

---
 tst/ConfigurationTestGenerator.php | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/tst/ConfigurationTestGenerator.php b/tst/ConfigurationTestGenerator.php
index a011bed..aec2a73 100755
--- a/tst/ConfigurationTestGenerator.php
+++ b/tst/ConfigurationTestGenerator.php
@@ -159,7 +159,7 @@ new ConfigurationTestGenerator(array(
                 array(
                     'type' => 'RegExp',
                     'args' => array(
-                        '#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#',
+                        '#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
                         '$content',
                         'outputs "page" stylesheet correctly',
                     ),
@@ -179,7 +179,7 @@ new ConfigurationTestGenerator(array(
                 array(
                     'type' => 'NotRegExp',
                     'args' => array(
-                        '#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#',
+                        '#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
                         '$content',
                         'removes "page" stylesheet correctly',
                     ),
@@ -344,7 +344,7 @@ class ConfigurationTestGenerator
      */
     private function _writeConfigurationTest()
     {
-        $defaultOptions = parse_ini_file(CONF, true);
+        $defaultOptions = parse_ini_file(CONF_SAMPLE, true);
         $code           = $this->_getHeader();
         foreach ($this->_configurations as $key => $conf) {
             $fullOptions = array_replace_recursive($defaultOptions, $conf['options']);
@@ -425,7 +425,7 @@ class ConfigurationCombinationsTest extends PHPUnit_Framework_TestCase
     {
         /* Setup Routine */
         Helper::confBackup();
-        $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
+        $this->_path  = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_model = Filesystem::getInstance(array('dir' => $this->_path));
         ServerSalt::setPath($this->_path);
         TrafficLimiter::setPath($this->_path);
@@ -435,9 +435,10 @@ class ConfigurationCombinationsTest extends PHPUnit_Framework_TestCase
     public function tearDown()
     {
         /* Tear Down Routine */
+        unlink(CONF);
         Helper::confRestore();
         Helper::rmDir($this->_path);
-}
+    }
 
     public function reset($configuration = array())
     {

From 81ac232710a9621a27649e6893c1f33e13aed391 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 17:29:07 +0200
Subject: [PATCH 18/20] increasing timeouts for travisCI, that seems to have
 gotten slower

---
 js/test.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/js/test.js b/js/test.js
index 3f24a2e..807d29d 100644
--- a/js/test.js
+++ b/js/test.js
@@ -78,6 +78,7 @@ describe('Helper', function () {
     // this test is not yet meaningful using jsdom, as it does not contain getSelection support.
     // TODO: This needs to be tested using a browser.
     describe('selectText', function () {
+        this.timeout(30000);
         jsc.property(
             'selection contains content of given ID',
             jsc.nearray(jsc.nearray(jsc.elements(alnumString))),
@@ -271,6 +272,7 @@ describe('Helper', function () {
     });
 
     describe('getCookie', function () {
+        this.timeout(30000);
         jsc.property(
             'returns the requested cookie',
             'nearray asciinestring',
@@ -299,6 +301,7 @@ describe('Helper', function () {
     });
 
     describe('baseUri', function () {
+        this.timeout(30000);
         before(function () {
             $.PrivateBin.Helper.reset();
         });
@@ -413,6 +416,7 @@ describe('I18n', function () {
     // loading of JSON via AJAX needs to be tested in the browser, this just mocks it
     // TODO: This needs to be tested using a browser.
     describe('loadTranslations', function () {
+        this.timeout(30000);
         before(function () {
             $.PrivateBin.I18n.reset();
         });
@@ -596,6 +600,7 @@ describe('Model', function () {
     });
 
     describe('getPasteId', function () {
+        this.timeout(30000);
         before(function () {
             $.PrivateBin.Model.reset();
             cleanup();
@@ -644,6 +649,7 @@ describe('Model', function () {
     });
 
     describe('getPasteKey', function () {
+        this.timeout(30000);
         jsc.property(
             'returns the fragment of the URL',
             jsc.nearray(jsc.elements(a2zString)),

From a5d5f6066a531f631a4a9d00396abe5f403fc47e Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 19:16:09 +0200
Subject: [PATCH 19/20] refactoring as recommended by Scrutinizer

---
 lib/Configuration.php         | 29 ++++-------------------------
 lib/Data/Filesystem.php       | 21 +++------------------
 lib/Persistence/DataStore.php | 26 ++++++++++++++++++++++++--
 tst/PrivateBinTest.php        |  1 -
 4 files changed, 31 insertions(+), 46 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index 5b8813d..571ef56 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -12,6 +12,7 @@
 
 namespace PrivateBin;
 
+use PrivateBin\Persistence\DataStore;
 use Exception;
 use PDO;
 
@@ -22,13 +23,6 @@ use PDO;
  */
 class Configuration
 {
-    /**
-     * First line in INI file, to hide contents
-     *
-     * @const string
-     */
-    const PROTECTION_LINE = ';<?php http_response_code(403); /*';
-
     /**
      * parsed configuration
      *
@@ -112,27 +106,12 @@ class Configuration
 
         // rename INI files to avoid configuration leakage
         if (is_readable($configIni)) {
-            $context = stream_context_create();
-            // don't overwrite already converted file
-            if (!is_file($configFile)) {
-                $iniHandle = fopen($configIni, 'r', false, $context);
-                file_put_contents($configFile, self::PROTECTION_LINE . PHP_EOL);
-                file_put_contents($configFile, $iniHandle, FILE_APPEND);
-                fclose($iniHandle);
-            }
-            unlink($configIni);
+            DataStore::prependRename($configIni, $configFile, ';');
 
             // cleanup sample, too
-            $configSample    = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php';
-            $configIniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample';
+            $configIniSample = $configIni . '.sample';
             if (is_readable($configIniSample)) {
-                if (!is_readable($configSample)) {
-                    $iniSampleHandle = fopen($configIniSample, 'r', false, $context);
-                    file_put_contents($configSample, self::PROTECTION_LINE . PHP_EOL);
-                    file_put_contents($configSample, $iniSampleHandle, FILE_APPEND);
-                    fclose($iniSampleHandle);
-                }
-                unlink($configIniSample);
+                DataStore::prependRename($configIniSample, PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php', ';');
             }
         }
 
diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php
index e092476..10012eb 100644
--- a/lib/Data/Filesystem.php
+++ b/lib/Data/Filesystem.php
@@ -135,31 +135,16 @@ class Filesystem extends AbstractData
         $pastePath = $basePath . '.php';
         // convert to PHP protected files if needed
         if (is_readable($basePath)) {
-            $context = stream_context_create();
-            // don't overwrite already converted file
-            if (!is_file($pastePath)) {
-                $handle = fopen($basePath, 'r', false, $context);
-                file_put_contents($pastePath, DataStore::PROTECTION_LINE . PHP_EOL);
-                file_put_contents($pastePath, $handle, FILE_APPEND);
-                fclose($handle);
-            }
-            unlink($basePath);
+            DataStore::prependRename($basePath, $pastePath);
 
             // convert comments, too
-            $discdir  = self::_dataid2discussionpath($pasteid);
+            $discdir = self::_dataid2discussionpath($pasteid);
             if (is_dir($discdir)) {
                 $dir = dir($discdir);
                 while (false !== ($filename = $dir->read())) {
                     if (substr($filename, -4) !== '.php' && strlen($filename) >= 16) {
                         $commentFilename = $discdir . $filename . '.php';
-                        // don't overwrite already converted file
-                        if (!is_file($commentFilename)) {
-                            $handle = fopen($discdir . $filename, 'r', false, $context);
-                            file_put_contents($commentFilename, DataStore::PROTECTION_LINE . PHP_EOL);
-                            file_put_contents($commentFilename, $handle, FILE_APPEND);
-                            fclose($handle);
-                        }
-                        unlink($discdir . $filename);
+                        DataStore::prependRename($discdir . $filename, $commentFilename);
                     }
                 }
                 $dir->close();
diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php
index c5f14ff..d14453a 100644
--- a/lib/Persistence/DataStore.php
+++ b/lib/Persistence/DataStore.php
@@ -23,7 +23,7 @@ use PrivateBin\Json;
 class DataStore extends AbstractPersistence
 {
     /**
-     * First line in JSON files, to hide contents
+     * first line in file, to protect its contents
      *
      * @const string
      */
@@ -58,10 +58,32 @@ class DataStore extends AbstractPersistence
      * @access public
      * @static
      * @param  string $filename
-     * @return array  $data
+     * @return stdClass|false  $data
      */
     public static function get($filename)
     {
         return json_decode(substr(file_get_contents($filename), strlen(self::PROTECTION_LINE . PHP_EOL)));
     }
+
+    /**
+     * rename a file, prepending the protection line at the beginning
+     *
+     * @access public
+     * @static
+     * @param  string $srcFile
+     * @param  string $destFile
+     * @param  string $prefix (optional)
+     * @return void
+     */
+    public static function prependRename($srcFile, $destFile, $prefix = '')
+    {
+        // don't overwrite already converted file
+        if (!is_readable($destFile)) {
+            $handle = fopen($srcFile, 'r', false, stream_context_create());
+            file_put_contents($destFile, $prefix . DataStore::PROTECTION_LINE . PHP_EOL);
+            file_put_contents($destFile, $handle, FILE_APPEND);
+            fclose($handle);
+        }
+        unlink($srcFile);
+    }
 }
diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php
index 5c5e145..72ee679 100644
--- a/tst/PrivateBinTest.php
+++ b/tst/PrivateBinTest.php
@@ -39,7 +39,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
         $options['purge']['dir']         = $this->_path;
         $options['traffic']['dir']       = $this->_path;
         $options['model_options']['dir'] = $this->_path;
-        Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         ServerSalt::setPath($this->_path);
     }

From 502e96c129c2004aa30f81339797bd343c4af677 Mon Sep 17 00:00:00 2001
From: El RIDO <elrido@gmx.net>
Date: Sun, 8 Oct 2017 19:23:33 +0200
Subject: [PATCH 20/20] StyleCI recommendations

---
 lib/Configuration.php         | 2 +-
 lib/Persistence/DataStore.php | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/Configuration.php b/lib/Configuration.php
index 571ef56..274743e 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -12,9 +12,9 @@
 
 namespace PrivateBin;
 
-use PrivateBin\Persistence\DataStore;
 use Exception;
 use PDO;
+use PrivateBin\Persistence\DataStore;
 
 /**
  * Configuration
diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php
index d14453a..7ab4af5 100644
--- a/lib/Persistence/DataStore.php
+++ b/lib/Persistence/DataStore.php
@@ -80,7 +80,7 @@ class DataStore extends AbstractPersistence
         // don't overwrite already converted file
         if (!is_readable($destFile)) {
             $handle = fopen($srcFile, 'r', false, stream_context_create());
-            file_put_contents($destFile, $prefix . DataStore::PROTECTION_LINE . PHP_EOL);
+            file_put_contents($destFile, $prefix . self::PROTECTION_LINE . PHP_EOL);
             file_put_contents($destFile, $handle, FILE_APPEND);
             fclose($handle);
         }