From cf1b6702152e1de1715ea6dab11a3f67a81814e6 Mon Sep 17 00:00:00 2001 From: Kcchouette 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 5ac34244..00ca25a5 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 this FAQ for information to troubleshoot.": "Si ce message ne disparaîssait pas, jetez un oeil à cette FAQ pour des idées de résolution (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 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 00ca25a5..da9d373d 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 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 d457b890..a28cdfba 100644 --- a/cfg/conf.ini.sample +++ b/cfg/conf.sample.php @@ -1,3 +1,4 @@ +; 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 --- 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 b6b9f6f4..d9d70bff 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 a5928893..cd27cd83 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 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 a28cdfba..f52028c7 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -1,4 +1,4 @@ -; 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 b18d048e..084a76d1 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 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 002616bd..0c7ba38a 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 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 964d4ee5..8e77d866 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 7e5fa31f..6eebfe93 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 802942cc..483f0814 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 ded82590..d2ba47ca 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 97ef60d5..26c6bad2 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 d3c79b41..077e8bae 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 8cf76831..9e626e9c 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 d9d70bff..a9c8a753 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 41260f89..f4960f98 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 c35df3b0..2c844ef8 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 4100e291..53508e03 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 951e2651..4c0a22e9 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 2bee73ec..5ae9bade 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 27993f92..ad963335 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 d1011f12..b4f084fa 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 55956b7a..0ac2317f 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 b67742d2..709cdeef 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 fae808ea..1bac7c8b 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 64fb530c..2e31622f 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 2eb0b52c..c4affacd 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 129a0992..a4d06863 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 914450a9..9f35e5de 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 c817445c..7b53fa1d 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 37c0bca7..f6daa508 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 4ed76b40..7efc7b27 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 6c04e47f..8b25395f 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 e9bd5d0b..3baae6d5 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 7993e431..103037e2 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 46b8df14..81d7c1ab 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From b60d55236e81da053d72fbe3f910315ed6e3541e Mon Sep 17 00:00:00 2001 From: El RIDO 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 3b9b4420..b98425ec 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 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 a9c8a753..4b7d35c6 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, '; $values) { // fill missing sections with default values diff --git a/lib/Data/Database.php b/lib/Data/Database.php index 2c844ef8..9685edd5 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 b98425ec..55d8288e 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 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 4b7d35c6..36ef91a5 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, '; 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 36ef91a5..b7590dbc 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, '; 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 f52028c7..4db8a33e 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -1,4 +1,4 @@ -; 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 e7e6dc82..e5b82640 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 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 db00ecb8..baee718b 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 = ';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 56dde1a7..0c03f279 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 = '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 e5b82640..8b04928d 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 cd27cd83..8588aca7 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 4d314f78..a41ed005 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 44df563f..e1f31131 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 2ed38461..a6ec2e06 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 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 baee718b..5b8813d6 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -27,7 +27,7 @@ class Configuration * * @const string */ - const PROTECTION_LINE = ';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 0c03f279..c5f14ff1 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 8b04928d..0a122f0b 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 e1f31131..5c5e1453 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 a6ec2e06..a438d4c8 100644 --- a/tst/PrivateBinWithDbTest.php +++ b/tst/PrivateBinWithDbTest.php @@ -1,7 +1,6 @@ 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 a011bed3..aec2a732 100755 --- a/tst/ConfigurationTestGenerator.php +++ b/tst/ConfigurationTestGenerator.php @@ -159,7 +159,7 @@ new ConfigurationTestGenerator(array( array( 'type' => 'RegExp', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#', + '#]+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( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#', + '#]+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 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 3f24a2eb..807d29dd 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 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 5b8813d6..571ef562 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 = ';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 c5f14ff1..d14453aa 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 5c5e1453..72ee679a 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 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 571ef562..274743ed 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 d14453aa..7ab4af59 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); }