Merge branch 'master' into attachment-handling

# Conflicts:
#	js/privatebin.js
#	tpl/bootstrap.php
#	tpl/page.php
This commit is contained in:
thororm
2017-04-02 13:30:52 +02:00
60 changed files with 4651 additions and 2100 deletions

View File

@@ -1,2 +1 @@
Allow from none
Deny from all
Require all denied

View File

@@ -58,7 +58,7 @@ abstract class AbstractData
* @access public
* @static
* @param array $options
* @return privatebin_abstract
* @return AbstractData
*/
public static function getInstance($options)
{
@@ -88,7 +88,6 @@ abstract class AbstractData
*
* @access public
* @param string $pasteid
* @return void
*/
abstract public function delete($pasteid);
@@ -147,7 +146,6 @@ abstract class AbstractData
*
* @access public
* @param int $batchsize
* @return void
*/
public function purge($batchsize)
{

View File

@@ -282,7 +282,6 @@ class Database extends AbstractData
*
* @access public
* @param string $pasteid
* @return void
*/
public function delete($pasteid)
{
@@ -375,11 +374,10 @@ class Database extends AbstractData
$comments[$i]->data = $row['data'];
$comments[$i]->meta = new stdClass;
$comments[$i]->meta->postdate = (int) $row['postdate'];
if (array_key_exists('nickname', $row) && !empty($row['nickname'])) {
$comments[$i]->meta->nickname = $row['nickname'];
}
if (array_key_exists('vizhash', $row) && !empty($row['vizhash'])) {
$comments[$i]->meta->vizhash = $row['vizhash'];
foreach (array('nickname', 'vizhash') as $key) {
if (array_key_exists($key, $row) && !empty($row[$key])) {
$comments[$i]->meta->$key = $row[$key];
}
}
}
ksort($comments);
@@ -564,7 +562,6 @@ class Database extends AbstractData
*
* @access private
* @static
* @return void
*/
private static function _createPasteTable()
{
@@ -589,7 +586,6 @@ class Database extends AbstractData
*
* @access private
* @static
* @return void
*/
private static function _createCommentTable()
{
@@ -616,7 +612,6 @@ class Database extends AbstractData
*
* @access private
* @static
* @return void
*/
private static function _createConfigTable()
{
@@ -651,7 +646,6 @@ class Database extends AbstractData
* @access private
* @static
* @param string $oldversion
* @return void
*/
private static function _upgradeDatabase($oldversion)
{

View File

@@ -12,8 +12,8 @@
namespace PrivateBin\Data;
use PrivateBin\Json;
use PrivateBin\Model\Paste;
use PrivateBin\Persistence\DataStore;
/**
* Filesystem
@@ -22,15 +22,6 @@ use PrivateBin\Model\Paste;
*/
class Filesystem extends AbstractData
{
/**
* directory where data is stored
*
* @access private
* @static
* @var string
*/
private static $_dir = 'data/';
/**
* get instance of singleton
*
@@ -41,17 +32,16 @@ class Filesystem extends AbstractData
*/
public static function getInstance($options = null)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
// if given update the data directory
if (
is_array($options) &&
array_key_exists('dir', $options)
) {
self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR;
}
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
self::_init();
DataStore::setPath($options['dir']);
}
return self::$_instance;
}
@@ -62,19 +52,19 @@ class Filesystem extends AbstractData
* @access public
* @param string $pasteid
* @param array $paste
* @throws Exception
* @return bool
*/
public function create($pasteid, $paste)
{
$storagedir = self::_dataid2path($pasteid);
if (is_file($storagedir . $pasteid)) {
$file = $storagedir . $pasteid;
if (is_file($file)) {
return false;
}
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
return (bool) file_put_contents($storagedir . $pasteid, Json::encode($paste));
return DataStore::store($file, $paste);
}
/**
@@ -108,7 +98,6 @@ class Filesystem extends AbstractData
*
* @access public
* @param string $pasteid
* @return void
*/
public function delete($pasteid)
{
@@ -155,20 +144,19 @@ class Filesystem extends AbstractData
* @param string $parentid
* @param string $commentid
* @param array $comment
* @throws Exception
* @return bool
*/
public function createComment($pasteid, $parentid, $commentid, $comment)
{
$storagedir = self::_dataid2discussionpath($pasteid);
$filename = $pasteid . '.' . $commentid . '.' . $parentid;
if (is_file($storagedir . $filename)) {
$file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid;
if (is_file($file)) {
return false;
}
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
return (bool) file_put_contents($storagedir . $filename, Json::encode($comment));
return DataStore::store($file, $comment);
}
/**
@@ -237,8 +225,9 @@ class Filesystem extends AbstractData
protected function _getExpiredPastes($batchsize)
{
$pastes = array();
$mainpath = DataStore::getPath();
$firstLevel = array_filter(
scandir(self::$_dir),
scandir($mainpath),
'self::_isFirstLevelDir'
);
if (count($firstLevel) > 0) {
@@ -246,7 +235,7 @@ class Filesystem extends AbstractData
for ($i = 0, $max = $batchsize * 10; $i < $max; ++$i) {
$firstKey = array_rand($firstLevel);
$secondLevel = array_filter(
scandir(self::$_dir . $firstLevel[$firstKey]),
scandir($mainpath . DIRECTORY_SEPARATOR . $firstLevel[$firstKey]),
'self::_isSecondLevelDir'
);
@@ -257,8 +246,9 @@ class Filesystem extends AbstractData
}
$secondKey = array_rand($secondLevel);
$path = self::$_dir . $firstLevel[$firstKey] .
DIRECTORY_SEPARATOR . $secondLevel[$secondKey];
$path = $mainpath . DIRECTORY_SEPARATOR .
$firstLevel[$firstKey] . DIRECTORY_SEPARATOR .
$secondLevel[$secondKey];
if (!is_dir($path)) {
continue;
}
@@ -292,29 +282,6 @@ class Filesystem extends AbstractData
return $pastes;
}
/**
* initialize privatebin
*
* @access private
* @static
* @return void
*/
private static function _init()
{
// Create storage directory if it does not exist.
if (!is_dir(self::$_dir)) {
mkdir(self::$_dir, 0700);
}
// Create .htaccess file if it does not exist.
if (!is_file(self::$_dir . '.htaccess')) {
file_put_contents(
self::$_dir . '.htaccess',
'Allow from none' . PHP_EOL .
'Deny from all' . PHP_EOL
);
}
}
/**
* Convert paste id to storage path.
*
@@ -332,8 +299,10 @@ class Filesystem extends AbstractData
*/
private static function _dataid2path($dataid)
{
return self::$_dir . substr($dataid, 0, 2) . DIRECTORY_SEPARATOR .
substr($dataid, 2, 2) . DIRECTORY_SEPARATOR;
return DataStore::getPath(
substr($dataid, 0, 2) . DIRECTORY_SEPARATOR .
substr($dataid, 2, 2) . DIRECTORY_SEPARATOR
);
}
/**
@@ -363,7 +332,7 @@ class Filesystem extends AbstractData
private static function _isFirstLevelDir($element)
{
return self::_isSecondLevelDir($element) &&
is_dir(self::$_dir . DIRECTORY_SEPARATOR . $element);
is_dir(DataStore::getPath($element));
}
/**

View File

@@ -21,21 +21,6 @@ use Exception;
*/
class Filter
{
/**
* strips slashes deeply
*
* @access public
* @static
* @param mixed $value
* @return mixed
*/
public static function stripslashesDeep($value)
{
return is_array($value) ?
array_map('self::stripslashesDeep', $value) :
stripslashes($value);
}
/**
* format a given time string into a human readable label (localized)
*

View File

@@ -135,15 +135,17 @@ class I18n
*
* @access public
* @static
* @return void
*/
public static function loadTranslations()
{
$availableLanguages = self::getAvailableLanguages();
// check if the lang cookie was set and that language exists
if (array_key_exists('lang', $_COOKIE) && in_array($_COOKIE['lang'], $availableLanguages)) {
$match = $_COOKIE['lang'];
if (
array_key_exists('lang', $_COOKIE) &&
($key = array_search($_COOKIE['lang'], $availableLanguages)) !== false
) {
$match = $availableLanguages[$key];
}
// find a translation file matching the browsers language preferences
else {
@@ -256,7 +258,6 @@ class I18n
* @access public
* @static
* @param string $lang
* @return void
*/
public static function setLanguageFallback($lang)
{
@@ -304,7 +305,7 @@ class I18n
return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
case 'sl':
return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));
// de, en, es, it, no
// de, en, es, it, no, pt
default:
return $n != 1 ? 1 : 0;
}

View File

@@ -40,7 +40,6 @@ class Model
* Factory constructor.
*
* @param configuration $conf
* @return void
*/
public function __construct(Configuration $conf)
{
@@ -64,8 +63,6 @@ class Model
/**
* Checks if a purge is necessary and triggers it if yes.
*
* @return void
*/
public function purge()
{

View File

@@ -63,7 +63,6 @@ abstract class AbstractModel
* @access public
* @param Configuration $configuration
* @param AbstractData $storage
* @return void
*/
public function __construct(Configuration $configuration, AbstractData $storage)
{
@@ -90,7 +89,6 @@ abstract class AbstractModel
* @access public
* @param string $id
* @throws Exception
* @return void
*/
public function setId($id)
{
@@ -106,7 +104,6 @@ abstract class AbstractModel
* @access public
* @param string $data
* @throws Exception
* @return void
*/
public function setData($data)
{
@@ -133,7 +130,6 @@ abstract class AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
abstract public function store();
@@ -142,7 +138,6 @@ abstract class AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
abstract public function delete();

View File

@@ -61,7 +61,6 @@ class Comment extends AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
public function store()
{
@@ -101,7 +100,6 @@ class Comment extends AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
public function delete()
{
@@ -129,7 +127,6 @@ class Comment extends AbstractModel
* @access public
* @param Paste $paste
* @throws Exception
* @return void
*/
public function setPaste(Paste $paste)
{
@@ -154,7 +151,6 @@ class Comment extends AbstractModel
* @access public
* @param string $id
* @throws Exception
* @return void
*/
public function setParentId($id)
{
@@ -184,7 +180,6 @@ class Comment extends AbstractModel
* @access public
* @param string $nickname
* @throws Exception
* @return void
*/
public function setNickname($nickname)
{

View File

@@ -75,7 +75,6 @@ class Paste extends AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
public function store()
{
@@ -103,7 +102,6 @@ class Paste extends AbstractModel
*
* @access public
* @throws Exception
* @return void
*/
public function delete()
{
@@ -183,7 +181,6 @@ class Paste extends AbstractModel
* @access public
* @param string $attachment
* @throws Exception
* @return void
*/
public function setAttachment($attachment)
{
@@ -199,7 +196,6 @@ class Paste extends AbstractModel
* @access public
* @param string $attachmentname
* @throws Exception
* @return void
*/
public function setAttachmentName($attachmentname)
{
@@ -214,7 +210,6 @@ class Paste extends AbstractModel
*
* @access public
* @param string $expiration
* @return void
*/
public function setExpiration($expiration)
{
@@ -236,7 +231,6 @@ class Paste extends AbstractModel
* @access public
* @param string $burnafterreading
* @throws Exception
* @return void
*/
public function setBurnafterreading($burnafterreading = '1')
{
@@ -257,7 +251,6 @@ class Paste extends AbstractModel
* @access public
* @param string $opendiscussion
* @throws Exception
* @return void
*/
public function setOpendiscussion($opendiscussion = '1')
{
@@ -281,7 +274,6 @@ class Paste extends AbstractModel
* @access public
* @param string $format
* @throws Exception
* @return void
*/
public function setFormatter($format)
{

View File

@@ -36,7 +36,6 @@ abstract class AbstractPersistence
* @access public
* @static
* @param string $path
* @return void
*/
public static function setPath($path)
{
@@ -80,27 +79,23 @@ abstract class AbstractPersistence
* @access protected
* @static
* @throws Exception
* @return void
*/
protected static function _initialize()
{
// Create storage directory if it does not exist.
if (!is_dir(self::$_path)) {
if (!@mkdir(self::$_path)) {
if (!@mkdir(self::$_path, 0700)) {
throw new Exception('unable to create directory ' . self::$_path, 10);
}
}
// Create .htaccess file if it does not exist.
$file = self::$_path . DIRECTORY_SEPARATOR . '.htaccess';
if (!is_file($file)) {
$writtenBytes = @file_put_contents(
$file,
'Allow from none' . PHP_EOL .
'Deny from all' . PHP_EOL,
'Require all denied' . PHP_EOL,
LOCK_EX
);
if ($writtenBytes === false || $writtenBytes < 30) {
if ($writtenBytes === false || $writtenBytes < 19) {
throw new Exception('unable to write to file ' . $file, 11);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @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
*/
namespace PrivateBin\Persistence;
use Exception;
use PrivateBin\Json;
/**
* DataStore
*
* Handles data storage for Data\Filesystem.
*/
class DataStore extends AbstractPersistence
{
/**
* store the data
*
* @access public
* @static
* @param string $filename
* @param array $data
* @return bool
*/
public static function store($filename, $data)
{
$path = self::getPath();
if (strpos($filename, $path) === 0) {
$filename = substr($filename, strlen($path));
}
try {
self::_store($filename, Json::encode($data));
return true;
} catch (Exception $e) {
return false;
}
}
}

View File

@@ -36,7 +36,6 @@ class PurgeLimiter extends AbstractPersistence
* @access public
* @static
* @param int $limit
* @return void
*/
public static function setLimit($limit)
{
@@ -49,7 +48,6 @@ class PurgeLimiter extends AbstractPersistence
* @access public
* @static
* @param Configuration $conf
* @return void
*/
public static function setConfiguration(Configuration $conf)
{

View File

@@ -95,7 +95,6 @@ class ServerSalt extends AbstractPersistence
* @access public
* @static
* @param string $path
* @return void
*/
public static function setPath($path)
{

View File

@@ -45,7 +45,6 @@ class TrafficLimiter extends AbstractPersistence
* @access public
* @static
* @param int $limit
* @return void
*/
public static function setLimit($limit)
{
@@ -58,7 +57,6 @@ class TrafficLimiter extends AbstractPersistence
* @access public
* @static
* @param Configuration $conf
* @return void
*/
public static function setConfiguration(Configuration $conf)
{

View File

@@ -30,6 +30,13 @@ class PrivateBin
*/
const VERSION = '1.1';
/**
* minimal required PHP version
*
* @const string
*/
const MIN_PHP_VERSION = '5.4.0';
/**
* show the same error message if the paste expired or does not exist
*
@@ -116,12 +123,11 @@ class PrivateBin
*
* @access public
* @throws Exception
* @return void
*/
public function __construct()
{
if (version_compare(PHP_VERSION, '5.3.0') < 0) {
throw new Exception(I18n::_('%s requires php 5.3.0 or above to work. Sorry.', I18n::_('PrivateBin')), 1);
if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) {
throw new Exception(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION), 1);
}
if (strlen(PATH) < 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
throw new Exception(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR), 5);
@@ -164,21 +170,9 @@ class PrivateBin
* initialize privatebin
*
* @access private
* @return void
*/
private function _init()
{
foreach (array('cfg', 'lib') as $dir) {
if (!is_file(PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess')) {
file_put_contents(
PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess',
'Allow from none' . PHP_EOL .
'Deny from all' . PHP_EOL,
LOCK_EX
);
}
}
$this->_conf = new Configuration;
$this->_model = new Model($this->_conf);
$this->_request = new Request;
@@ -324,7 +318,6 @@ class PrivateBin
* @access private
* @param string $dataid
* @param string $deletetoken
* @return void
*/
private function _delete($dataid, $deletetoken)
{
@@ -334,19 +327,16 @@ class PrivateBin
// accessing this property ensures that the paste would be
// deleted if it has already expired
$burnafterreading = $paste->isBurnafterreading();
if ($deletetoken == 'burnafterreading') {
if ($burnafterreading) {
$paste->delete();
$this->_return_message(0, $dataid);
} else {
$this->_return_message(1, 'Paste is not of burn-after-reading type.');
}
if (
($burnafterreading && $deletetoken == 'burnafterreading') ||
Filter::slowEquals($deletetoken, $paste->getDeleteToken())
) {
// Paste exists and deletion token is valid: Delete the paste.
$paste->delete();
$this->_status = 'Paste was properly deleted.';
} else {
// Make sure the token is valid.
if (Filter::slowEquals($deletetoken, $paste->getDeleteToken())) {
// Paste exists and deletion token is valid: Delete the paste.
$paste->delete();
$this->_status = 'Paste was properly deleted.';
if (!$burnafterreading && $deletetoken == 'burnafterreading') {
$this->_error = 'Paste is not of burn-after-reading type.';
} else {
$this->_error = 'Wrong deletion token. Paste was not deleted.';
}
@@ -357,6 +347,13 @@ class PrivateBin
} catch (Exception $e) {
$this->_error = $e->getMessage();
}
if ($this->_request->isJsonApiCall()) {
if (strlen($this->_error)) {
$this->_return_message(1, $this->_error);
} else {
$this->_return_message(0, $dataid);
}
}
}
/**
@@ -364,7 +361,6 @@ class PrivateBin
*
* @access private
* @param string $dataid
* @return void
*/
private function _read($dataid)
{
@@ -397,7 +393,6 @@ class PrivateBin
* Display PrivateBin frontend.
*
* @access private
* @return void
*/
private function _view()
{
@@ -461,7 +456,6 @@ class PrivateBin
*
* @access private
* @param string $type
* @return void
*/
private function _jsonld($type)
{
@@ -494,7 +488,6 @@ class PrivateBin
* @param int $status
* @param string $message
* @param array $other
* @return void
*/
private function _return_message($status, $message, $other = array())
{

View File

@@ -41,7 +41,7 @@ class Request
const MIME_XHTML = 'application/xhtml+xml';
/**
* Input stream to use for PUT parameter parsing.
* Input stream to use for PUT parameter parsing
*
* @access private
* @var string
@@ -49,7 +49,7 @@ class Request
private static $_inputStream = 'php://input';
/**
* Operation to perform.
* Operation to perform
*
* @access private
* @var string
@@ -57,7 +57,7 @@ class Request
private $_operation = 'view';
/**
* Request parameters.
* Request parameters
*
* @access private
* @var array
@@ -65,7 +65,7 @@ class Request
private $_params = array();
/**
* If we are in a JSON API context.
* If we are in a JSON API context
*
* @access private
* @var bool
@@ -73,20 +73,12 @@ class Request
private $_isJsonApi = false;
/**
* Constructor.
* Constructor
*
* @access public
* @return void
*/
public function __construct()
{
// in case stupid admin has left magic_quotes enabled in php.ini (for PHP < 5.4)
if (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) {
$_POST = array_map('PrivateBin\\Filter::stripslashesDeep', $_POST);
$_GET = array_map('PrivateBin\\Filter::stripslashesDeep', $_GET);
$_COOKIE = array_map('PrivateBin\\Filter::stripslashesDeep', $_COOKIE);
}
// decide if we are in JSON API or HTML context
$this->_isJsonApi = $this->_detectJsonRequest();
@@ -129,7 +121,7 @@ class Request
}
/**
* Get current operation.
* Get current operation
*
* @access public
* @return string
@@ -140,7 +132,7 @@ class Request
}
/**
* Get a request parameter.
* Get a request parameter
*
* @access public
* @param string $param
@@ -153,7 +145,7 @@ class Request
}
/**
* If we are in a JSON API context.
* If we are in a JSON API context
*
* @access public
* @return bool
@@ -164,7 +156,7 @@ class Request
}
/**
* Override the default input stream source, used for unit testing.
* Override the default input stream source, used for unit testing
*
* @param string $input
*/
@@ -174,7 +166,7 @@ class Request
}
/**
* detect the clients supported media type and decide if its a JSON API call or not
* Detect the clients supported media type and decide if its a JSON API call or not
*
* Adapted from: https://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*

View File

@@ -35,7 +35,6 @@ class View
* @access public
* @param string $name
* @param mixed $value
* @return void
*/
public function assign($name, $value)
{
@@ -48,7 +47,6 @@ class View
* @access public
* @param string $template
* @throws Exception
* @return void
*/
public function draw($template)
{

View File

@@ -61,7 +61,6 @@ class Vizhash16x16
* constructor
*
* @access public
* @return void
*/
public function __construct()
{
@@ -210,7 +209,6 @@ class Vizhash16x16
* @param resource $image
* @param int $action
* @param int $color
* @return void
*/
private function drawshape($image, $action, $color)
{