2015-08-15 18:32:31 +02:00
< ? php
2016-07-21 17:09:48 +02:00
2020-10-10 12:08:58 +02:00
use PHPUnit\Framework\TestCase ;
2016-08-09 11:54:42 +02:00
use PrivateBin\Data\Filesystem ;
2016-07-21 17:09:48 +02:00
2020-10-10 12:08:58 +02:00
class FilesystemTest extends TestCase
2015-08-15 18:32:31 +02:00
{
private $_model ;
private $_path ;
2017-03-24 21:30:08 +01:00
private $_invalidPath ;
2020-10-10 12:22:20 +02:00
public function setUp () : void
2015-08-15 18:32:31 +02:00
{
/* Setup Routine */
2017-03-24 21:35:50 +01:00
$this -> _path = sys_get_temp_dir () . DIRECTORY_SEPARATOR . 'privatebin_data' ;
2017-03-24 21:30:08 +01:00
$this -> _invalidPath = $this -> _path . DIRECTORY_SEPARATOR . 'bar' ;
2017-03-24 21:35:50 +01:00
$this -> _model = Filesystem :: getInstance ( array ( 'dir' => $this -> _path ));
2017-03-24 21:30:08 +01:00
if ( ! is_dir ( $this -> _path )) {
mkdir ( $this -> _path );
}
if ( ! is_dir ( $this -> _invalidPath )) {
mkdir ( $this -> _invalidPath );
}
2015-08-15 18:32:31 +02:00
}
2020-10-10 12:22:20 +02:00
public function tearDown () : void
2015-08-15 18:32:31 +02:00
{
/* Tear Down Routine */
2017-03-24 21:30:08 +01:00
chmod ( $this -> _invalidPath , 0700 );
2016-08-09 11:54:42 +02:00
Helper :: rmDir ( $this -> _path );
2015-08-15 18:32:31 +02:00
}
public function testFileBasedDataStoreWorks ()
{
2016-08-09 11:54:42 +02:00
$this -> _model -> delete ( Helper :: getPasteId ());
2015-09-26 12:29:27 +02:00
2015-08-15 18:32:31 +02:00
// storing pastes
2019-05-10 07:55:39 +02:00
$paste = Helper :: getPaste ( 2 , array ( 'expire_date' => 1344803344 ));
2016-08-09 11:54:42 +02:00
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste does not yet exist' );
$this -> assertTrue ( $this -> _model -> create ( Helper :: getPasteId (), $paste ), 'store new paste' );
$this -> assertTrue ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste exists after storing it' );
$this -> assertFalse ( $this -> _model -> create ( Helper :: getPasteId (), $paste ), 'unable to store the same paste twice' );
2019-05-10 07:55:39 +02:00
$this -> assertEquals ( $paste , $this -> _model -> read ( Helper :: getPasteId ()));
2015-08-15 18:32:31 +02:00
// storing comments
2016-08-09 11:54:42 +02:00
$this -> assertFalse ( $this -> _model -> existsComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId ()), 'comment does not yet exist' );
2016-08-11 14:41:52 +02:00
$this -> assertTrue ( $this -> _model -> createComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId (), Helper :: getComment ()), 'store comment' );
2016-08-09 11:54:42 +02:00
$this -> assertTrue ( $this -> _model -> existsComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId ()), 'comment exists after storing it' );
2017-03-24 21:30:08 +01:00
$this -> assertFalse ( $this -> _model -> createComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId (), Helper :: getComment ()), 'unable to store the same comment twice' );
2019-05-10 07:55:39 +02:00
$comment = Helper :: getComment ();
$comment [ 'id' ] = Helper :: getCommentId ();
$comment [ 'parentid' ] = Helper :: getPasteId ();
2015-08-15 18:32:31 +02:00
$this -> assertEquals (
2019-05-10 07:55:39 +02:00
array ( $comment [ 'meta' ][ 'created' ] => $comment ),
2016-08-09 11:54:42 +02:00
$this -> _model -> readComments ( Helper :: getPasteId ())
2015-08-15 18:32:31 +02:00
);
// deleting pastes
2016-08-09 11:54:42 +02:00
$this -> _model -> delete ( Helper :: getPasteId ());
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste successfully deleted' );
$this -> assertFalse ( $this -> _model -> existsComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId ()), 'comment was deleted with paste' );
$this -> assertFalse ( $this -> _model -> read ( Helper :: getPasteId ()), 'paste can no longer be found' );
2015-08-15 18:32:31 +02:00
}
2015-09-26 12:29:27 +02:00
public function testFileBasedAttachmentStoreWorks ()
{
2016-08-09 11:54:42 +02:00
$this -> _model -> delete ( Helper :: getPasteId ());
2019-05-10 07:55:39 +02:00
$original = $paste = Helper :: getPasteWithAttachment ( 1 , array ( 'expire_date' => 1344803344 ));
2016-10-29 10:24:08 +02:00
$paste [ 'meta' ][ 'attachment' ] = $paste [ 'attachment' ];
2015-09-26 12:29:27 +02:00
$paste [ 'meta' ][ 'attachmentname' ] = $paste [ 'attachmentname' ];
unset ( $paste [ 'attachment' ], $paste [ 'attachmentname' ]);
2016-08-09 11:54:42 +02:00
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste does not yet exist' );
$this -> assertTrue ( $this -> _model -> create ( Helper :: getPasteId (), $paste ), 'store new paste' );
$this -> assertTrue ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste exists after storing it' );
$this -> assertFalse ( $this -> _model -> create ( Helper :: getPasteId (), $paste ), 'unable to store the same paste twice' );
2019-05-10 07:55:39 +02:00
$this -> assertEquals ( $original , $this -> _model -> read ( Helper :: getPasteId ()));
2015-09-26 12:29:27 +02:00
}
2016-12-25 12:04:47 +01:00
/**
* pastes a - g are expired and should get deleted , x never expires and y - z expire in an hour
*/
2016-07-15 17:02:59 +02:00
public function testPurge ()
{
2016-07-18 14:47:32 +02:00
mkdir ( $this -> _path . DIRECTORY_SEPARATOR . '00' , 0777 , true );
2019-05-10 07:55:39 +02:00
$expired = Helper :: getPaste ( 2 , array ( 'expire_date' => 1344803344 ));
$paste = Helper :: getPaste ( 2 , array ( 'expire_date' => time () + 3600 ));
2016-12-25 12:04:47 +01:00
$keys = array ( 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'x' , 'y' , 'z' );
2016-10-29 10:24:08 +02:00
$ids = array ();
2016-07-26 08:19:35 +02:00
foreach ( $keys as $key ) {
2019-05-10 22:46:39 +02:00
$ids [ $key ] = hash ( 'fnv164' , $key );
2016-07-15 17:02:59 +02:00
$this -> assertFalse ( $this -> _model -> exists ( $ids [ $key ]), " paste $key does not yet exist " );
2016-07-26 08:19:35 +02:00
if ( in_array ( $key , array ( 'x' , 'y' , 'z' ))) {
2016-07-15 17:02:59 +02:00
$this -> assertTrue ( $this -> _model -> create ( $ids [ $key ], $paste ), " store $key paste " );
2016-12-25 12:04:47 +01:00
} elseif ( $key === 'x' ) {
$this -> assertTrue ( $this -> _model -> create ( $ids [ $key ], Helper :: getPaste ()), " store $key paste " );
2016-07-26 08:19:35 +02:00
} else {
2016-07-15 17:02:59 +02:00
$this -> assertTrue ( $this -> _model -> create ( $ids [ $key ], $expired ), " store $key paste " );
}
$this -> assertTrue ( $this -> _model -> exists ( $ids [ $key ]), " paste $key exists after storing it " );
}
$this -> _model -> purge ( 10 );
2016-07-26 08:19:35 +02:00
foreach ( $ids as $key => $id ) {
if ( in_array ( $key , array ( 'x' , 'y' , 'z' ))) {
2016-07-19 08:40:33 +02:00
$this -> assertTrue ( $this -> _model -> exists ( $id ), " paste $key exists after purge " );
$this -> _model -> delete ( $id );
2016-07-26 08:19:35 +02:00
} else {
2016-07-19 08:40:33 +02:00
$this -> assertFalse ( $this -> _model -> exists ( $id ), " paste $key was purged " );
2016-07-15 17:02:59 +02:00
}
}
}
2016-08-11 14:41:52 +02:00
public function testErrorDetection ()
{
$this -> _model -> delete ( Helper :: getPasteId ());
2019-05-10 07:55:39 +02:00
$paste = Helper :: getPaste ( 2 , array ( 'expire' => " Invalid UTF-8 sequence: \xB1 \x31 " ));
2016-08-11 14:41:52 +02:00
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste does not yet exist' );
$this -> assertFalse ( $this -> _model -> create ( Helper :: getPasteId (), $paste ), 'unable to store broken paste' );
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste does still not exist' );
2021-06-13 10:44:26 +02:00
$this -> assertFalse ( $this -> _model -> setValue ( 'foo' , 'non existing namespace' ), 'rejects setting value in non existing namespace' );
2016-08-11 14:41:52 +02:00
}
public function testCommentErrorDetection ()
{
$this -> _model -> delete ( Helper :: getPasteId ());
2019-05-10 07:55:39 +02:00
$comment = Helper :: getComment ( 1 , array ( 'nickname' => " Invalid UTF-8 sequence: \xB1 \x31 " ));
2016-08-11 14:41:52 +02:00
$this -> assertFalse ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste does not yet exist' );
2016-08-11 15:03:48 +02:00
$this -> assertTrue ( $this -> _model -> create ( Helper :: getPasteId (), Helper :: getPaste ()), 'store new paste' );
2016-08-11 14:41:52 +02:00
$this -> assertTrue ( $this -> _model -> exists ( Helper :: getPasteId ()), 'paste exists after storing it' );
$this -> assertFalse ( $this -> _model -> existsComment ( Helper :: getPasteId (), Helper :: getPasteId (), Helper :: getCommentId ()), 'comment does not yet exist' );
$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' );
}
2017-10-08 07:46:28 +02:00
public function testOldFilesGetConverted ()
{
// generate 10 (default purge batch size) pastes in the old format
2017-10-08 11:31:41 +02:00
$paste = Helper :: getPaste ();
$comment = Helper :: getComment ();
2017-10-08 07:46:28 +02:00
$commentid = Helper :: getCommentId ();
2017-10-08 11:31:41 +02:00
$ids = array ();
2017-10-08 07:46:28 +02:00
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 );
2017-10-08 11:31:41 +02:00
$storagedir = $this -> _path . DIRECTORY_SEPARATOR . substr ( $dataid , 0 , 2 ) .
2017-10-08 07:46:28 +02:00
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 " );
2020-10-11 10:31:24 +02:00
$this -> assertFileDoesNotExist ( $storagedir . $dataid , " old format paste $dataid got removed " );
2017-10-08 07:46:28 +02:00
$this -> assertTrue ( $this -> _model -> exists ( $dataid ), " paste $dataid exists " );
2019-05-10 07:55:39 +02:00
$this -> assertEquals ( $this -> _model -> read ( $dataid ), $paste , " paste $dataid wasn't modified in the conversion " );
2017-10-08 07:46:28 +02:00
$storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR ;
$this -> assertFileExists ( $storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php' , " comment of $dataid exists in new format " );
2020-10-11 10:31:24 +02:00
$this -> assertFileDoesNotExist ( $storagedir . $dataid . '.' . $commentid . '.' . $dataid , " old format comment of $dataid got removed " );
2017-10-08 07:46:28 +02:00
$this -> assertTrue ( $this -> _model -> existsComment ( $dataid , $dataid , $commentid ), " comment in paste $dataid exists " );
2019-05-10 07:55:39 +02:00
$comment = $comment ;
$comment [ 'id' ] = $commentid ;
$comment [ 'parentid' ] = $dataid ;
$this -> assertEquals ( $this -> _model -> readComments ( $dataid ), array ( $comment [ 'meta' ][ 'created' ] => $comment ), " comment of $dataid wasn't modified in the conversion " );
2017-10-08 07:46:28 +02:00
}
}
2015-08-15 18:32:31 +02:00
}