diff --git a/CHANGELOG.md b/CHANGELOG.md index 856d861..fb0d9de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # PrivateBin version history + * **1.5.1 (2022-12-24)** + * ADDED: script for administrative tasks: deleting pastes (#274), removing empty directories (#277), purging expired pastes (#276) & statistics (#319) + * FIXED: Revert Filesystem purge to limited and randomized lookup (#1030) + * FIXED: Catch JSON decode errors when invalid data gets sent to the API (#1030) + * FIXED: Support sorting v1 format in mixed version comments in Filesystem backend (#1030) * **1.5 (2022-12-11)** * ADDED: script for data storage backend migrations (#1012) * ADDED: Translations for Turkish, Slovak, Greek and Thai diff --git a/CREDITS.md b/CREDITS.md index 7a19c5f..ace4143 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -29,9 +29,8 @@ * rodehoed - option to exempt ips from the rate-limiter * Mark van Holsteijn - Google Cloud Storage backend * Austin Huang - Oracle database support -* Felix J. Ogris - S3 Storage backend +* Felix J. Ogris - S3 Storage backend, script for data backend migrations, dropped singleton behaviour of data backends * Mounir Idrassi & J. Mozdzen - secure YOURLS integration -* Felix J. Ogris - script for data backend migrations, dropped singleton behaviour of data backends ## Translations * Hexalyse - French diff --git a/INSTALL.md b/INSTALL.md index 0ba5228..26f8200 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -205,7 +205,7 @@ CREATE INDEX parent ON prefix_comment(pasteid); CREATE TABLE prefix_config ( id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) ); -INSERT INTO prefix_config VALUES('VERSION', '1.5.0'); +INSERT INTO prefix_config VALUES('VERSION', '1.5.1'); ``` In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns diff --git a/Makefile b/Makefile index d1ef6fd..e59fbc3 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: all coverage coverage-js coverage-php doc doc-js doc-php increment sign test test-js test-php help -CURRENT_VERSION = 1.5.0 -VERSION ?= 1.5.1 -VERSION_FILES = index.php cfg/ *.md css/ i18n/ img/ js/package.json js/privatebin.js lib/ Makefile tpl/ tst/ +CURRENT_VERSION = 1.5.1 +VERSION ?= 1.5.2 +VERSION_FILES = index.php bin/ cfg/ *.md css/ i18n/ img/ js/package.json js/privatebin.js lib/ Makefile tpl/ tst/ REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g") REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g") @@ -38,7 +38,7 @@ increment: ## Increment and commit new version number, set target version using git commit -m "incrementing version" sign: ## Sign a release. - git tag $(VERSION) + git tag --sign --message "Release v$(VERSION)" $(VERSION) git push origin $(VERSION) signrelease.sh diff --git a/README.md b/README.md index f8591e8..3a1be5c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/) -*Current version: 1.5.0* +*Current version: 1.5.1* **PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin) diff --git a/SECURITY.md b/SECURITY.md index 3ced5eb..afbb7f6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 1.5.0 | :heavy_check_mark: | -| < 1.5.0 | :x: | +| 1.5.1 | :heavy_check_mark: | +| < 1.5.1 | :x: | ## Reporting a Vulnerability diff --git a/bin/administration b/bin/administration new file mode 100755 index 0000000..c55da83 --- /dev/null +++ b/bin/administration @@ -0,0 +1,318 @@ +#!/usr/bin/env php +_store->exists($pasteId)) { + self::_error('given ID does not exist, has expired or was already deleted', 6); + } + $this->_store->delete($pasteId); + if ($this->_store->exists($pasteId)) { + self::_error('paste ID exists after deletion, permission problem?', 7); + } + exit("paste $pasteId successfully deleted" . PHP_EOL); + } + + /** + * removes empty directories, if current storage model uses Filesystem + * + * @access private + */ + private function _empty_dirs() + { + if ($this->_conf->getKey('class', 'model') !== 'Filesystem') { + self::_error('instance not using Filesystem storage, no directories to empty', 4); + } + $dir = $this->_conf->getKey('dir', 'model_options'); + passthru("find $dir -type d -empty -delete", $code); + exit($code); + } + + /** + * display a message on STDERR and exits + * + * @access private + * @static + * @param string $message + * @param int $code optional, defaults to 1 + */ + private static function _error($message, $code = 1) + { + self::_error_echo($message); + exit($code); + } + + /** + * display a message on STDERR + * + * @access private + * @static + * @param string $message + */ + private static function _error_echo($message) + { + fwrite(STDERR, 'Error: ' . $message . PHP_EOL); + } + + /** + * display usage help on STDOUT and exits + * + * @access private + * @static + * @param int $code optional, defaults to 0 + */ + private static function _help($code = 0) + { + echo <<<'EOT' +Usage: + administration [--delete | --empty-dirs | --help | --purge | --statistics] + +Options: + -d, --delete deletes the requested paste ID + -e, --empty-dirs removes empty directories (only if Filesystem storage is + configured) + -h, --help displays this help message + -p, --purge purge all expired pastes + -s, --statistics reads all stored pastes and comments and reports statistics +EOT, PHP_EOL; + exit($code); + } + + /** + * return option for given short or long keyname, if it got set + * + * @access private + * @static + * @param string $short + * @param string $long + * @return string|null + */ + private function _option($short, $long) + { + foreach (array($short, $long) as $key) { + if (array_key_exists($key, $this->_opts)) { + return $this->_opts[$key]; + } + } + return null; + } + + /** + * initialize options from given argument array + * + * @access private + * @static + * @param array $arguments + */ + private function _options_initialize($arguments) + { + if ($arguments > 3) { + self::_error_echo('too many arguments given'); + echo PHP_EOL; + self::_help(1); + } + + if ($arguments < 2) { + self::_error_echo('missing arguments'); + echo PHP_EOL; + self::_help(2); + } + + $this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics')); + if (!$this->_opts) { + self::_error_echo('unsupported arguments given'); + echo PHP_EOL; + self::_help(3); + } + } + + /** + * reads all stored pastes and comments and reports statistics + * + * @access public + */ + private function _statistics() + { + $counters = array( + 'burn' => 0, + 'discussion' => 0, + 'expired' => 0, + 'md' => 0, + 'percent' => 1, + 'plain' => 0, + 'progress' => 0, + 'syntax' => 0, + 'total' => 0, + 'unknown' => 0, + ); + $time = time(); + $ids = $this->_store->getAllPastes(); + $counters['total'] = count($ids); + $dots = $counters['total'] < 100 ? 10 : ( + $counters['total'] < 1000 ? 50 : 100 + ); + $percentages = $counters['total'] < 100 ? 0 : ( + $counters['total'] < 1000 ? 4 : 10 + ); + + echo "Total:\t\t\t${counters['total']}", PHP_EOL; + foreach ($ids as $pasteid) { + $paste = $this->_store->read($pasteid); + ++$counters['progress']; + + if ( + array_key_exists('expire_date', $paste['meta']) && + $paste['meta']['expire_date'] < $time + ) { + ++$counters['expired']; + } + + if (array_key_exists('adata', $paste)) { + $format = $paste['adata'][1]; + $discussion = $paste['adata'][2]; + $burn = $paste['adata'][3]; + } else { + $format = array_key_exists('formatter', $paste['meta']) ? $paste['meta']['formatter'] : 'plaintext'; + $discussion = array_key_exists('opendiscussion', $paste['meta']) ? $paste['meta']['opendiscussion'] : false; + $burn = array_key_exists('burnafterreading', $paste['meta']) ? $paste['meta']['burnafterreading'] : false; + } + + if ($format === 'plaintext') { + ++$counters['plain']; + } elseif ($format === 'syntaxhighlighting') { + ++$counters['syntax']; + } elseif ($format === 'markdown') { + ++$counters['md']; + } else { + ++$counters['unknown']; + } + + $counters['discussion'] += (int) $discussion; + $counters['burn'] += (int) $burn; + + // display progress + if ($counters['progress'] % $dots === 0) { + echo '.'; + if ($percentages) { + $progress = $percentages / $counters['total'] * $counters['progress']; + if ($progress >= $counters['percent']) { + printf(' %d%% ', 100 / $percentages * $progress); + ++$counters['percent']; + } + } + } + } + + echo PHP_EOL, << 0) { + echo "Unknown format:\t\t${counters['unknown']}", PHP_EOL; + } + } + + /** + * constructor + * + * initializes and runs administrative tasks + * + * @access public + */ + public function __construct() + { + $this->_options_initialize($_SERVER['argc']); + + if ($this->_option('h', 'help') !== null) { + self::_help(); + } + + $this->_conf = new Configuration; + + if ($this->_option('e', 'empty-dirs') !== null) { + $this->_empty_dirs(); + } + + $class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model'); + $this->_store = new $class($this->_conf->getSection('model_options')); + + if (($pasteId = $this->_option('d', 'delete')) !== null) { + $this->_delete($pasteId); + } + + if ($this->_option('p', 'purge') !== null) { + $this->_store->purge(PHP_INT_MAX); + exit('purging of expired pastes concluded' . PHP_EOL); + } + + if ($this->_option('s', 'statistics') !== null) { + $this->_statistics(); + } + } +} + +new Administration(); \ No newline at end of file diff --git a/bin/migrate b/bin/migrate index 515a5e8..76539ab 100755 --- a/bin/migrate +++ b/bin/migrate @@ -17,13 +17,14 @@ if (version_compare(PHP_VERSION, '7.1.0') < 0) { $longopts = array( "delete-after", - "delete-during" + "delete-during", + "help" ); $opts_arr = getopt("fhnv", $longopts, $rest); if ($opts_arr === false) { - dieerr("Erroneous command line options. Please use -h"); + dieerr("Erroneous command line options. Please use --help"); } -if (array_key_exists("h", $opts_arr)) { +if (array_key_exists("h", $opts_arr) || array_key_exists("help", $opts_arr)) { helpexit(); } @@ -173,12 +174,12 @@ function debug ($text) { function helpexit () { - print("migrate.php - Copy data between PrivateBin backends + print("migrate - Copy data between PrivateBin backends Usage: migrate [--delete-after] [--delete-during] [-f] [-n] [-v] srcconfdir [] - migrate [-h] + migrate [-h|--help] Options: --delete-after delete data from source after all pastes and comments have @@ -187,6 +188,7 @@ Options: comments have successfully been copied to the destination -f forcefully overwrite data which already exists at the destination + -h, --help displays this help message -n dry run, do not copy data -v be verbose use storage backend configration from conf.php found in diff --git a/composer.json b/composer.json index 6e99d5d..21696b9 100644 --- a/composer.json +++ b/composer.json @@ -31,8 +31,8 @@ "jdenticon/jdenticon": "^1.0" }, "suggest" : { - "google/cloud-storage" : "1.26.1", - "aws/aws-sdk-php" : "3.239.0" + "google/cloud-storage" : "1.30.1", + "aws/aws-sdk-php" : "3.254.0" }, "require-dev" : { "phpunit/phpunit" : "^4.6 || ^5.0" diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index 412963f..07bd918 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.5.0 + * @version 1.5.1 */ body { diff --git a/css/noscript.css b/css/noscript.css index 207ef96..c45a5d4 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.5.0 + * @version 1.5.1 */ /* When there is no script at all other */ diff --git a/css/privatebin.css b/css/privatebin.css index acc8e8b..918ba73 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.5.0 + * @version 1.5.1 */ /* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. diff --git a/i18n/cs.json b/i18n/cs.json index a0121e9..02424a4 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -47,7 +47,7 @@ "%d minutes (3rd plural)" ], "%d hours": [ - "%d hodin", + "%d hodina", "%d hodiny", "%d hodin", "%d hours (3rd plural)" diff --git a/i18n/lt.json b/i18n/lt.json index 74f36d8..a8c8d96 100644 --- a/i18n/lt.json +++ b/i18n/lt.json @@ -187,7 +187,7 @@ "URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.", "Save paste": "Įrašyti įdėjimą", "Your IP is not authorized to create pastes.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response." + "Trying to shorten a URL that isn't pointing at our instance.": "Bandoma sutrumpinti URL adresą, kuris nenurodo į mūsų egzempliorių.", + "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.", + "Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką." } diff --git a/i18n/nl.json b/i18n/nl.json index 600d41e..0c18589 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -1,10 +1,10 @@ { "PrivateBin": "PrivateBin", - "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is een minimalistische, open source online pastebin waarbij de server geen kennis heeft van de geplakte gegevens. Gegevens worden gecodeerd/gedecodeerd %s in de browser %s met behulp van 256 bits AES.", + "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is een minimalistische, open source online pastebin waarbij de server geen kennis heeft van de paste data zelf. Gegevens worden gecodeerd/gedecodeerd %s in de browser %s met behulp van 256-bits AES.", "More information on the project page.": "Meer informatie is te vinden op de projectpagina.", "Because ignorance is bliss": "Onwetendheid is een zegen", "en": "nl", - "Paste does not exist, has expired or has been deleted.": "Geplakte tekst bestaat niet, is verlopen of verwijderd.", + "Paste does not exist, has expired or has been deleted.": "Paste bestaat niet, is verlopen of verwijderd.", "%s requires php %s or above to work. Sorry.": "%s vereist PHP %s of hoger om te kunnen werken. Sorry", "%s requires configuration section [%s] to be present in configuration file.": "%s vereist dat de configuratiesectie [%s] aanwezig is in het configuratiebestand", "Please wait %d seconds between each post.": [ @@ -13,20 +13,20 @@ "Alstublieft %d seconden wachten tussen elk bericht.", "Alstublieft %d seconden wachten tussen elk bericht." ], - "Paste is limited to %s of encrypted data.": "Geplakte tekst is beperkt tot %s aan versleutelde gegevens", - "Invalid data.": "Ongeldige gegevens", - "You are unlucky. Try again.": "Helaas. Probeer het nog eens", + "Paste is limited to %s of encrypted data.": "Paste is beperkt tot %s aan versleutelde gegevens.", + "Invalid data.": "Ongeldige gegevens.", + "You are unlucky. Try again.": "Helaas. Probeer het nog eens.", "Error saving comment. Sorry.": "Fout bij het opslaan van het commentaar. Sorry", - "Error saving paste. Sorry.": "Fout bij het opslaan van de geplakte tekst. Sorry.", + "Error saving paste. Sorry.": "Fout bij het opslaan van de paste. Sorry.", "Invalid paste ID.": "Ongeldige ID.", - "Paste is not of burn-after-reading type.": "Geplakte tekst is geen 'vernietig na lezen' type", - "Wrong deletion token. Paste was not deleted.": "Foutieve verwijdercode. Geplakte tekst is niet verwijderd.", - "Paste was properly deleted.": "Geplakte tekst is correct verwijderd.", + "Paste is not of burn-after-reading type.": "Paste is geen 'vernietig na lezen' type.", + "Wrong deletion token. Paste was not deleted.": "Foutieve verwijdercode. Paste is niet verwijderd.", + "Paste was properly deleted.": "Paste is correct verwijderd.", "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript vereist om %s te laten werken. Sorry voor het ongemak.", - "%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken ", + "%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken.", "New": "Nieuw", "Send": "Verzenden", - "Clone": "Clonen", + "Clone": "Klonen", "Raw text": "Onbewerkte tekst", "Expires": "Verloopt", "Burn after reading": "Vernietig na lezen", @@ -77,7 +77,7 @@ "%d years (3rd plural)" ], "Never": "Nooit", - "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Opmerking: Dit is een testservice: Gegevens kunnen op elk gegeven moment verwijderd worden.", + "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Opmerking: Dit is een testservice: Gegevens kunnen op elk gegeven moment verwijderd worden. Katten zullen doodgaan als je misbruikt maakt van deze service.", "This document will expire in %d seconds.": [ "Dit document verloopt over %d seconde.", "Dit document verloopt over %d seconden.", @@ -108,14 +108,14 @@ "Dit document verloopt over %d maanden.", "Dit document verloopt over %d maanden." ], - "Please enter the password for this paste:": "Voer het wachtwoord in voor deze geplakte tekst:", + "Please enter the password for this paste:": "Voer het wachtwoord in voor deze paste:", "Could not decrypt data (Wrong key?)": "Kon de gegevens niet decoderen (verkeerde sleutel?)", - "Could not delete the paste, it was not stored in burn after reading mode.": "Verwijderen van de geplakte tekst niet mogelijk, deze werd niet opgeslagen in 'vernietig na lezen' modus.", - "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Sluit dit venster niet, dit bericht kan niet opnieuw worden weergegeven.", + "Could not delete the paste, it was not stored in burn after reading mode.": "Verwijderen van de paste niet mogelijk, deze werd niet opgeslagen in 'vernietig na lezen' modus.", + "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "ALLEEN VOOR JOUW OGEN BESTEMD. Sluit dit venster niet, dit bericht kan niet opnieuw worden weergegeven.", "Could not decrypt comment; Wrong key?": "Kon het commentaar niet decoderen; Verkeerde sleutel?", "Reply": "Beantwoorden", "Anonymous": "Anoniem", - "Avatar generated from IP address": "Anonieme avatar (van het IP adres)", + "Avatar generated from IP address": "Anonieme avatar (van het IP-adres)", "Add comment": "Commentaar toevoegen", "Optional nickname…": "Optionele bijnaam…", "Post comment": "Plaats een commentaar", @@ -125,11 +125,11 @@ "unknown status": "Onbekende status", "server error or not responding": "Serverfout of server reageert niet", "Could not post comment: %s": "Kon het commentaar niet plaatsen: %s", - "Sending paste…": "Geplakte tekst verzenden…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Uw geplakte tekst is %s (Druk [Ctrl]+[c] om te kopiëren)", + "Sending paste…": "Paste verzenden…", + "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Je paste is %s (Druk [Ctrl]+[c] om te kopiëren)", "Delete data": "Gegevens wissen", - "Could not create paste: %s": "Kon de geplakte tekst niet aanmaken: %s", - "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de geplakte tekst niet decoderen: Decoderingssleutel ontbreekt in URL (Hebt u een redirector of een URL-verkorter gebruikt die een deel van de URL verwijdert?)", + "Could not create paste: %s": "Kon de paste niet aanmaken: %s", + "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de paste niet decoderen: Decoderingssleutel ontbreekt in URL (Heb je een redirector of een URL-verkorter gebruikt die een deel van de URL verwijdert?)", "B": "B", "KiB": "KiB", "MiB": "MiB", @@ -145,49 +145,49 @@ "Markdown": "Markdown", "Download attachment": "Bijlage downloaden", "Cloned: '%s'": "Gekloond: '%s'", - "The cloned file '%s' was attached to this paste.": "Het gekloonde bestand '%s' is bijgevoegd aan de geplakte tekst.", + "The cloned file '%s' was attached to this paste.": "Het gekloonde bestand '%s' is bijgevoegd aan de paste.", "Attach a file": "Een bestand toevoegen", - "alternatively drag & drop a file or paste an image from the clipboard": "U kunt ook een bestand slepen en neerzetten of een afbeelding plakken van het klembord", - "File too large, to display a preview. Please download the attachment.": "Het bestand is te groot om voorbeeld weer te geven. Aub de bijlage downloaden", + "alternatively drag & drop a file or paste an image from the clipboard": "Je kunt ook een bestand slepen en neerzetten of een afbeelding plakken van het klembord", + "File too large, to display a preview. Please download the attachment.": "Het bestand is te groot om voorbeeld weer te geven. Aub de bijlage downloaden.", "Remove attachment": "Bijlage verwijderen", - "Your browser does not support uploading encrypted files. Please use a newer browser.": "Uw browser biedt geen ondersteuning voor het uploaden van gecodeerde bestanden. Gebruik alstublieft een nieuwere browser", - "Invalid attachment.": "Ongeldige bijlage", + "Your browser does not support uploading encrypted files. Please use a newer browser.": "Je browser biedt geen ondersteuning voor het uploaden van gecodeerde bestanden. Gebruik alstublieft een nieuwere browser.", + "Invalid attachment.": "Ongeldige bijlage.", "Options": "Opties", "Shorten URL": "URL verkorten", "Editor": "Editor", "Preview": "Preview", - "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vereist dat het PATH eindigt in een '%s'. Aub het PATH updaten in uw index.php.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vereist dat PATH eindigt in een '%s'. a.u.b. PATH updaten in je index.php.", "Decrypt": "Decoderen", "Enter password": "Voer het wachtwoord in", "Loading…": "Laden…", - "Decrypting paste…": "Geplakte tekst decoderen…", - "Preparing new paste…": "Nieuwe geplakte tekst voorbereiden…", - "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In het geval dat dit bericht nooit verdwijnt, kijkt u dan eens naar veelgestelde vragen voor informatie over het oplossen van problemen .", - "+++ no paste text +++": "+++ geen geplakte tekst +++", - "Could not get paste data: %s": "Kon geen klembordgegevens verkrijgen: %s", + "Decrypting paste…": "Paste decoderen…", + "Preparing new paste…": "Nieuwe paste voorbereiden…", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In het geval dat dit bericht nooit verdwijnt, kijkt dan eens naar veelgestelde vragen voor informatie over het oplossen van problemen .", + "+++ no paste text +++": "+++ geen paste tekst +++", + "Could not get paste data: %s": "Kon geen paste data verkrijgen: %s", "QR code": "QR-code", "This website is using an insecure HTTP connection! Please use it only for testing.": "Deze website gebruikt een onveilige HTTP-verbinding! Gelieve deze enkel te gebruiken om te testen.", "For more information see this FAQ entry.": "Voor meer informatie zie dit FAQ-artikel.", - "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Uw browser kan een HTTPS-verbinding nodig hebben om de WebCrypto API te ondersteunen. Probeer het met HTTPS.", - "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Uw browser ondersteunt WebAssembly niet, wat wordt gebruikt voor zlib compressie. U kunt niet-gecomprimeerde documenten maken, maar geen gecomprimeerde documenten lezen.", + "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "Je browser kan een HTTPS-verbinding nodig hebben om de WebCrypto API te ondersteunen. Probeer het met HTTPS.", + "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Je browser ondersteunt WebAssembly niet, wat wordt gebruikt voor zlib compressie. Je kunt niet-gecomprimeerde documenten maken, maar geen gecomprimeerde documenten lezen.", "waiting on user to provide a password": "wachtend op gebruiker om een wachtwoord te geven", - "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Kon de gegevens niet decoderen. Heeft u een verkeerd wachtwoord ingevoerd? Probeer het opnieuw met de knop bovenaan.", + "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Kon de gegevens niet decoderen. Heb je een verkeerd wachtwoord ingevoerd? Probeer het opnieuw met de knop bovenaan.", "Retry": "Opnieuw proberen", "Showing raw text…": "Platte tekst tonen…", "Notice:": "Let op:", "This link will expire after %s.": "Deze link vervalt na %s.", - "This link can only be accessed once, do not use back or refresh button in your browser.": "Deze link kan slechts eenmaal worden geopend, gebruik niet de terug- of verversknop in uw browser.", + "This link can only be accessed once, do not use back or refresh button in your browser.": "Deze link kan slechts eenmaal worden geopend, gebruik niet de terug- of verversknop in je browser.", "Link:": "Link:", - "Recipient may become aware of your timezone, convert time to UTC?": "Ontvanger kan zich bewust worden van uw tijdzone, tijd omzetten naar UTC?", + "Recipient may become aware of your timezone, convert time to UTC?": "Ontvanger kan zich bewust worden van je tijdzone, tijd omzetten naar UTC?", "Use Current Timezone": "Gebruik huidige tijdzone", "Convert To UTC": "Omzetten naar UTC", "Close": "Sluiten", "Encrypted note on %s": "Versleutelde notitie op %s", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Bezoek deze link om de notitie te bekijken. Als je de URL aan iemand geeft, kan die de notitie ook bekijken.", - "URL shortener may expose your decrypt key in URL.": "URL-verkorter kan uw ontcijferingssleutel in URL blootleggen.", + "URL shortener may expose your decrypt key in URL.": "URL-verkorter kan je ontcijferingssleutel in URL blootleggen.", "Save paste": "Notitie opslaan", - "Your IP is not authorized to create pastes.": "Uw IP-adres is niet gemachtigd om geplakte tekst te maken.", - "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "Error parsing YOURLS response.": "Error parsing YOURLS response." + "Your IP is not authorized to create pastes.": "Je IP-adres is niet gemachtigd om pastes te maken.", + "Trying to shorten a URL that isn't pointing at our instance.": "Proberen om een URL te verkorten dat niet naar ons systeem wijst.", + "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".", + "Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons." } diff --git a/index.php b/index.php index b0794ff..7a7a3d0 100644 --- a/index.php +++ b/index.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.5.0 + * @version 1.5.1 */ // change this, if your php files and data is outside of your webservers document root diff --git a/js/package.json b/js/package.json index f53e991..746584b 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "privatebin", - "version": "1.5.0", + "version": "1.5.1", "description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", "main": "privatebin.js", "directories": { diff --git a/js/privatebin.js b/js/privatebin.js index f5f1665..a3756f2 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.5.0 + * @version 1.5.1 * @name PrivateBin * @namespace */ diff --git a/lib/Configuration.php b/lib/Configuration.php index 5ef9c40..452e561 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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/Controller.php b/lib/Controller.php index 173f067..66376e4 100644 --- a/lib/Controller.php +++ b/lib/Controller.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.5.0 + * @version 1.5.1 */ namespace PrivateBin; @@ -28,7 +28,7 @@ class Controller * * @const string */ - const VERSION = '1.5.0'; + const VERSION = '1.5.1'; /** * minimal required PHP version diff --git a/lib/Data/AbstractData.php b/lib/Data/AbstractData.php index a1c0fb4..e8054c6 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Data; diff --git a/lib/Data/Database.php b/lib/Data/Database.php index f020a48..a7da867 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Data; diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php index bfd52e2..5a54039 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Data; @@ -232,7 +232,13 @@ class Filesystem extends AbstractData $comment['parentid'] = $items[2]; // Store in array - $key = $this->getOpenSlot($comments, (int) $comment['meta']['created']); + $key = $this->getOpenSlot( + $comments, ( + (int) array_key_exists('created', $comment['meta']) ? + $comment['meta']['created'] : // v2 comments + $comment['meta']['postdate'] // v1 comments + ) + ); $comments[$key] = $comment; } } @@ -362,12 +368,12 @@ class Filesystem extends AbstractData { $pastes = array(); $count = 0; + $opened = 0; + $limit = $batchsize * 10; // try at most 10 times $batchsize pastes before giving up $time = time(); - foreach ($this->_getPasteIterator() as $file) { - if ($file->isDir()) { - continue; - } - $pasteid = $file->getBasename('.php'); + $files = $this->getAllPastes(); + shuffle($files); + foreach ($files as $pasteid) { if ($this->exists($pasteid)) { $data = $this->read($pasteid); if ( @@ -375,11 +381,13 @@ class Filesystem extends AbstractData $data['meta']['expire_date'] < $time ) { $pastes[] = $pasteid; - ++$count; - if ($count >= $batchsize) { + if (++$count >= $batchsize) { break; } } + if (++$opened >= $limit) { + break; + } } } return $pastes; @@ -391,7 +399,7 @@ class Filesystem extends AbstractData public function getAllPastes() { $pastes = array(); - foreach ($this->_getPasteIterator() as $file) { + foreach (new \GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) { if ($file->isFile()) { $pastes[] = $file->getBasename('.php'); } @@ -435,20 +443,6 @@ class Filesystem extends AbstractData '.discussion' . DIRECTORY_SEPARATOR; } - /** - * Get an iterator matching paste files. - * - * Note that creating the iterator issues the glob() call, so we can't pre- - * generate this object before files that should get matched exist. - * - * @access private - * @return \GlobIterator - */ - private function _getPasteIterator() - { - return new \GlobIterator($this->_path . self::PASTE_FILE_PATTERN); - } - /** * store the data * diff --git a/lib/Data/S3Storage.php b/lib/Data/S3Storage.php index 55d5ca0..4411c97 100644 --- a/lib/Data/S3Storage.php +++ b/lib/Data/S3Storage.php @@ -4,7 +4,7 @@ * * an S3 compatible data backend for PrivateBin with CEPH/RadosGW in mind * see https://docs.ceph.com/en/latest/radosgw/s3/php/ - * based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.5.0 + * based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.5.1 * * @link https://github.com/PrivateBin/PrivateBin * @copyright 2022 Felix J. Ogris (https://ogris.de/) diff --git a/lib/Filter.php b/lib/Filter.php index 3f17e10..de6b0e6 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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/FormatV2.php b/lib/FormatV2.php index 0e0ce48..c35935e 100644 --- a/lib/FormatV2.php +++ b/lib/FormatV2.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/I18n.php b/lib/I18n.php index f851cb6..e80e019 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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/Json.php b/lib/Json.php index a248e2a..30da7a8 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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/Model.php b/lib/Model.php index da1988d..2f06fdd 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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/Model/AbstractModel.php b/lib/Model/AbstractModel.php index eb111a2..6e87d58 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Model; diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php index 749d792..fbb6113 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Model; diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php index 5f6a94e..1495d85 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Model; diff --git a/lib/Persistence/AbstractPersistence.php b/lib/Persistence/AbstractPersistence.php index 9feb77a..574d04e 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/PurgeLimiter.php b/lib/Persistence/PurgeLimiter.php index c6d3eaf..4bb96e8 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/ServerSalt.php b/lib/Persistence/ServerSalt.php index b73b685..821bd05 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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/TrafficLimiter.php b/lib/Persistence/TrafficLimiter.php index 3c33613..eff5e2a 100644 --- a/lib/Persistence/TrafficLimiter.php +++ b/lib/Persistence/TrafficLimiter.php @@ -8,7 +8,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.5.0 + * @version 1.5.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Request.php b/lib/Request.php index 0d5f096..c4dceb2 100644 --- a/lib/Request.php +++ b/lib/Request.php @@ -7,11 +7,13 @@ * @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.5.0 + * @version 1.5.1 */ namespace PrivateBin; +use Exception; + /** * Request * @@ -110,9 +112,13 @@ class Request case 'POST': // it might be a creation or a deletion, the latter is detected below $this->_operation = 'create'; - $this->_params = Json::decode( - file_get_contents(self::$_inputStream) - ); + try { + $this->_params = Json::decode( + file_get_contents(self::$_inputStream) + ); + } catch (Exception $e) { + // ignore error, $this->_params will remain empty + } break; default: $this->_params = $_GET; diff --git a/lib/View.php b/lib/View.php index b973878..6860632 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 https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/lib/Vizhash16x16.php b/lib/Vizhash16x16.php index 76e5fda..a2dc0dd 100644 --- a/lib/Vizhash16x16.php +++ b/lib/Vizhash16x16.php @@ -8,7 +8,7 @@ * @link https://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.5.0 + * @version 0.0.5 beta PrivateBin 1.5.1 */ namespace PrivateBin; diff --git a/lib/YourlsProxy.php b/lib/YourlsProxy.php index 71ca568..04f921a 100644 --- a/lib/YourlsProxy.php +++ b/lib/YourlsProxy.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.5.0 + * @version 1.5.1 */ namespace PrivateBin; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 29a8020..b3fc8af 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -73,7 +73,7 @@ endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index 375352f..7a457ee 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -51,7 +51,7 @@ endif; ?> - + diff --git a/tst/Bootstrap.php b/tst/Bootstrap.php index 48a91cb..bcf622f 100644 --- a/tst/Bootstrap.php +++ b/tst/Bootstrap.php @@ -149,7 +149,7 @@ class BucketStub extends Bucket throw new BadMethodCallException('not supported by this stub'); } - public function exists() + public function exists(array $options = array()) { return true; } diff --git a/tst/ControllerTest.php b/tst/ControllerTest.php index 698d5f8..c1876f7 100644 --- a/tst/ControllerTest.php +++ b/tst/ControllerTest.php @@ -436,8 +436,6 @@ class ControllerTest extends PHPUnit_Framework_TestCase * silently removed, check that this case is handled * * @runInSeparateProcess - * @expectedException Exception - * @expectedExceptionCode 90 */ public function testCreateBrokenUpload() { @@ -449,7 +447,12 @@ class ControllerTest extends PHPUnit_Framework_TestCase $_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['REMOTE_ADDR'] = '::1'; $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exists before posting data'); + ob_start(); new Controller; + $content = ob_get_contents(); + ob_end_clean(); + $response = json_decode($content, true); + $this->assertEquals(1, $response['status'], 'outputs error status'); $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data'); } diff --git a/tst/I18nTest.php b/tst/I18nTest.php index a70f6b3..852ee5d 100644 --- a/tst/I18nTest.php +++ b/tst/I18nTest.php @@ -135,7 +135,7 @@ class I18nTest extends PHPUnit_Framework_TestCase $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'cs;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2'; I18n::loadTranslations(); $this->assertEquals('cs', I18n::_('en'), 'browser language cs'); - $this->assertEquals('1 hodin', I18n::_('%d hours', 1), '1 hour in Czech'); + $this->assertEquals('1 hodina', I18n::_('%d hours', 1), '1 hour in Czech'); $this->assertEquals('2 hodiny', I18n::_('%d hours', 2), '2 hours in Czech'); $this->assertEquals('5 minut', I18n::_('%d minutes', 5), '5 minutes in Czech'); $this->assertEquals('14 minut', I18n::_('%d minutes', 14), '14 minutes in Czech'); diff --git a/tst/RequestTest.php b/tst/RequestTest.php index 9b440be..38501c5 100644 --- a/tst/RequestTest.php +++ b/tst/RequestTest.php @@ -97,7 +97,7 @@ class RequestTest extends PHPUnit_Framework_TestCase Request::setInputStream($file); $request = new Request; unlink($file); - $this->assertTrue($request->isJsonApiCall(), 'is JSON Api call'); + $this->assertTrue($request->isJsonApiCall(), 'is JSON API call'); $this->assertEquals('create', $request->getOperation()); $this->assertEquals('foo', $request->getParam('ct')); } @@ -111,7 +111,7 @@ class RequestTest extends PHPUnit_Framework_TestCase file_put_contents($file, '{"ct":"foo"}'); Request::setInputStream($file); $request = new Request; - $this->assertTrue($request->isJsonApiCall(), 'is JSON Api call'); + $this->assertTrue($request->isJsonApiCall(), 'is JSON API call'); $this->assertEquals('create', $request->getOperation()); $this->assertEquals('foo', $request->getParam('ct')); } @@ -125,7 +125,7 @@ class RequestTest extends PHPUnit_Framework_TestCase $_SERVER['QUERY_STRING'] = $id; $_GET[$id] = ''; $request = new Request; - $this->assertTrue($request->isJsonApiCall(), 'is JSON Api call'); + $this->assertTrue($request->isJsonApiCall(), 'is JSON API call'); $this->assertEquals($id, $request->getParam('pasteid')); $this->assertEquals('read', $request->getOperation()); } @@ -142,12 +142,25 @@ class RequestTest extends PHPUnit_Framework_TestCase file_put_contents($file, '{"deletetoken":"bar"}'); Request::setInputStream($file); $request = new Request; - $this->assertTrue($request->isJsonApiCall(), 'is JSON Api call'); + $this->assertTrue($request->isJsonApiCall(), 'is JSON API call'); $this->assertEquals('delete', $request->getOperation()); $this->assertEquals($id, $request->getParam('pasteid')); $this->assertEquals('bar', $request->getParam('deletetoken')); } + public function testPostGarbage() + { + $this->reset(); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $file = tempnam(sys_get_temp_dir(), 'FOO'); + file_put_contents($file, random_bytes(256)); + Request::setInputStream($file); + $request = new Request; + unlink($file); + $this->assertFalse($request->isJsonApiCall(), 'is HTML call'); + $this->assertEquals('create', $request->getOperation()); + } + public function testReadWithNegotiation() { $this->reset();