remove v1 backend support and version checks in the frontend

This commit is contained in:
El RIDO 2025-07-05 17:21:12 +02:00
parent 6d5323e351
commit f7cf389f36
No known key found for this signature in database
GPG key ID: 0F5C940A6BD81F92
17 changed files with 186 additions and 526 deletions

View file

@ -177,11 +177,7 @@ CREATE TABLE prefix_paste (
dataid CHAR(16) NOT NULL, dataid CHAR(16) NOT NULL,
data MEDIUMBLOB, data MEDIUMBLOB,
expiredate INT, expiredate INT,
opendiscussion INT,
burnafterreading INT,
meta TEXT, meta TEXT,
attachment MEDIUMBLOB,
attachmentname BLOB,
PRIMARY KEY (dataid) PRIMARY KEY (dataid)
); );

View file

@ -91,7 +91,6 @@ jQuery.PrivateBin = (function($) {
* @class * @class
*/ */
function CryptoData(data) { function CryptoData(data) {
this.v = 1;
// store all keys in the default locations for drop-in replacement // store all keys in the default locations for drop-in replacement
for (let key in data) { for (let key in data) {
this[key] = data[key]; this[key] = data[key];
@ -102,11 +101,11 @@ jQuery.PrivateBin = (function($) {
* *
* @name CryptoData.getCipherData * @name CryptoData.getCipherData
* @function * @function
* @return {Array}|{string} * @return {Array}
*/ */
this.getCipherData = function() this.getCipherData = function()
{ {
return this.v === 1 ? this.data : [this.ct, this.adata]; return [this.ct, this.adata];
} }
} }
@ -131,7 +130,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.getFormat = function() this.getFormat = function()
{ {
return this.v === 1 ? this.meta.formatter : this.adata[1]; return this.adata[1];
} }
/** /**
@ -145,7 +144,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.getTimeToLive = function() this.getTimeToLive = function()
{ {
return (this.v === 1 ? this.meta.remaining_time : this.meta.time_to_live) || 0; return this.meta.time_to_live || 0;
} }
/** /**
@ -157,7 +156,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.isBurnAfterReadingEnabled = function() this.isBurnAfterReadingEnabled = function()
{ {
return (this.v === 1 ? this.meta.burnafterreading : this.adata[3]); return this.adata[3];
} }
/** /**
@ -169,7 +168,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.isDiscussionEnabled = function() this.isDiscussionEnabled = function()
{ {
return (this.v === 1 ? this.meta.opendiscussion : this.adata[2]); return this.adata[2];
} }
} }
@ -194,7 +193,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.getCreated = function() this.getCreated = function()
{ {
return this.meta[this.v === 1 ? 'postdate' : 'created'] || 0; return this.meta['created'] || 0;
} }
/** /**
@ -206,7 +205,7 @@ jQuery.PrivateBin = (function($) {
*/ */
this.getIcon = function() this.getIcon = function()
{ {
return this.meta[this.v === 1 ? 'vizhash' : 'icon'] || ''; return this.meta['icon'] || '';
} }
} }
@ -5316,7 +5315,7 @@ jQuery.PrivateBin = (function($) {
*/ */
async function decryptPaste(paste, key, password) async function decryptPaste(paste, key, password)
{ {
let pastePlain = await decryptOrPromptPassword( const pastePlain = await decryptOrPromptPassword(
key, password, key, password,
paste.getCipherData() paste.getCipherData()
); );
@ -5332,36 +5331,21 @@ jQuery.PrivateBin = (function($) {
} }
} }
if (paste.v > 1) { const pasteMessage = JSON.parse(pastePlain);
// version 2 paste if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) {
const pasteMessage = JSON.parse(pastePlain); if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) {
if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) { pasteMessage.attachment.forEach((attachment, key) => {
if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) { const attachment_name = pasteMessage.attachment_name[key];
pasteMessage.attachment.forEach((attachment, key) => { AttachmentViewer.setAttachment(attachment, attachment_name);
const attachment_name = pasteMessage.attachment_name[key];
AttachmentViewer.setAttachment(attachment, attachment_name);
});
} else {
// Continue to process attachment parameters as strings to ensure backward compatibility
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
}
AttachmentViewer.showAttachment();
}
pastePlain = pasteMessage.paste;
} else {
// version 1 paste
if (paste.hasOwnProperty('attachment') && paste.hasOwnProperty('attachmentname')) {
Promise.all([
CryptTool.decipher(key, password, paste.attachment),
CryptTool.decipher(key, password, paste.attachmentname)
]).then((attachment) => {
AttachmentViewer.setAttachment(attachment[0], attachment[1]);
AttachmentViewer.showAttachment();
}); });
} else {
// Continue to process attachment parameters as strings to ensure backward compatibility
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
} }
AttachmentViewer.showAttachment();
} }
PasteViewer.setFormat(paste.getFormat()); PasteViewer.setFormat(paste.getFormat());
PasteViewer.setText(pastePlain); PasteViewer.setText(pasteMessage.paste);
PasteViewer.run(); PasteViewer.run();
} }
@ -5388,28 +5372,15 @@ jQuery.PrivateBin = (function($) {
const comment = new Comment(paste.comments[i]), const comment = new Comment(paste.comments[i]),
commentPromise = CryptTool.decipher(key, password, comment.getCipherData()); commentPromise = CryptTool.decipher(key, password, comment.getCipherData());
paste.comments[i] = comment; paste.comments[i] = comment;
if (comment.v > 1) { commentDecryptionPromises.push(
// version 2 comment commentPromise.then(function (commentJson) {
commentDecryptionPromises.push( const commentMessage = JSON.parse(commentJson);
commentPromise.then(function (commentJson) { return [
const commentMessage = JSON.parse(commentJson); commentMessage.comment || '',
return [ commentMessage.nickname || ''
commentMessage.comment || '', ];
commentMessage.nickname || '' })
]; );
})
);
} else {
// version 1 comment
commentDecryptionPromises.push(
Promise.all([
commentPromise,
paste.comments[i].meta.hasOwnProperty('nickname') ?
CryptTool.decipher(key, password, paste.comments[i].meta.nickname) :
Promise.resolve('')
])
);
}
} }
return Promise.all(commentDecryptionPromises).then(function (plaintexts) { return Promise.all(commentDecryptionPromises).then(function (plaintexts) {
for (let i = 0; i < paste.comments.length; ++i) { for (let i = 0; i < paste.comments.length; ++i) {

View file

@ -177,36 +177,7 @@ describe('PasteStatus', function () {
this.timeout(30000); this.timeout(30000);
jsc.property( jsc.property(
'shows burn after reading message or remaining time v1', 'shows burn after reading message or remaining time',
'bool',
'nat',
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({'meta': {
'burnafterreading': burnafterreading,
'remaining_time': remainingTime
}}));
if (burnafterreading) {
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else if (remainingTime) {
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else {
result = $('#remainingtime').hasClass('hidden') &&
!$('#remainingtime').hasClass('foryoureyesonly');
}
clean();
return result;
}
);
jsc.property(
'shows burn after reading message or remaining time v2',
'bool', 'bool',
'nat', 'nat',
common.jscUrl(), common.jscUrl(),

View file

@ -116,7 +116,7 @@ class Configuration
'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==', 'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==',
'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==', 'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==',
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==', 'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
'js/privatebin.js' => 'sha512-wQci0zYb+eGsbQaLWunZ7sMoT7+3w5SUfvBJ3JactOOO2WytQGt/q6wRdWZsCkZjCE6hxkEBOxlfSqLHluh3KQ==', 'js/privatebin.js' => 'sha512-9PIA4e9hN7XUWzN4w7K0BKtEK3/N7ZztNchTrV5M0joeMCPdbU1dJWxRr0XmsFmb+V/Zsr8n+YopxiCc5HMPIQ==',
'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==', 'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==',
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==', 'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==', 'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',

View file

@ -239,19 +239,15 @@ class Controller
/** /**
* Store new paste or comment * Store new paste or comment
* *
* POST contains one or both: * POST contains:
* data = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct) * JSON encoded object with mandatory keys:
* attachment = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct) * v = 2 (version)
* * adata (array)
* All optional data will go to meta information: * ct (base64 encoded, encrypted text)
* expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never) * meta (optional):
* formatter (optional) = format to display the paste as (plaintext,syntaxhighlighting,markdown) (default:syntaxhighlighting) * expire = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:1week)
* burnafterreading (optional) = if this paste may only viewed once ? (0/1) (default:0) * parentid (optional) = in discussions, which comment this comment replies to.
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0) * pasteid (optional) = in discussions, which paste this comment belongs to.
* attachmentname = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* nickname (optional) = in discussion, encoded FormatV2 encrypted text nickname of author of comment (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* parentid (optional) = in discussion, which comment this comment replies to.
* pasteid (optional) = in discussion, which paste this comment belongs to.
* *
* @access private * @access private
* @return string * @return string

View file

@ -190,25 +190,4 @@ abstract class AbstractData
} }
return $postdate; return $postdate;
} }
/**
* Upgrade pre-version 1 pastes with attachment to version 1 format.
*
* @access protected
* @static
* @param array $paste
* @return array
*/
protected static function upgradePreV1Format(array &$paste)
{
if (array_key_exists('attachment', $paste['meta'])) {
$paste['attachment'] = $paste['meta']['attachment'];
unset($paste['meta']['attachment']);
if (array_key_exists('attachmentname', $paste['meta'])) {
$paste['attachmentname'] = $paste['meta']['attachmentname'];
unset($paste['meta']['attachmentname']);
}
}
return $paste;
}
} }

View file

@ -143,48 +143,20 @@ class Database extends AbstractData
public function create($pasteid, array &$paste) public function create($pasteid, array &$paste)
{ {
$expire_date = 0; $expire_date = 0;
$opendiscussion = $burnafterreading = false;
$attachment = $attachmentname = null;
$meta = $paste['meta']; $meta = $paste['meta'];
$isVersion1 = array_key_exists('data', $paste);
if (array_key_exists('expire_date', $meta)) { if (array_key_exists('expire_date', $meta)) {
$expire_date = (int) $meta['expire_date']; $expire_date = (int) $meta['expire_date'];
unset($meta['expire_date']); unset($meta['expire_date']);
} }
if (array_key_exists('opendiscussion', $meta)) {
$opendiscussion = $meta['opendiscussion'];
unset($meta['opendiscussion']);
}
if (array_key_exists('burnafterreading', $meta)) {
$burnafterreading = $meta['burnafterreading'];
unset($meta['burnafterreading']);
}
if ($isVersion1) {
if (array_key_exists('attachment', $meta)) {
$attachment = $meta['attachment'];
unset($meta['attachment']);
}
if (array_key_exists('attachmentname', $meta)) {
$attachmentname = $meta['attachmentname'];
unset($meta['attachmentname']);
}
} else {
$opendiscussion = $paste['adata'][2];
$burnafterreading = $paste['adata'][3];
}
try { try {
return $this->_exec( return $this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('paste') . 'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
'" VALUES(?,?,?,?,?,?,?,?)', '" VALUES(?,?,?,?)',
array( array(
$pasteid, $pasteid,
$isVersion1 ? $paste['data'] : Json::encode($paste), Json::encode($paste),
$expire_date, $expire_date,
(int) $opendiscussion,
(int) $burnafterreading,
Json::encode($meta), Json::encode($meta),
$attachment,
$attachmentname,
) )
); );
} catch (Exception $e) { } catch (Exception $e) {
@ -213,38 +185,17 @@ class Database extends AbstractData
return false; return false;
} }
// create array // create array
$data = Json::decode($row['data']); $paste = Json::decode($row['data']);
$isVersion2 = array_key_exists('v', $data) && $data['v'] >= 2;
$paste = $isVersion2 ? $data : array('data' => $row['data']);
try { try {
$row['meta'] = Json::decode($row['meta']); $paste['meta'] = Json::decode($row['meta']);
} catch (Exception $e) { } catch (Exception $e) {
$row['meta'] = array(); $paste['meta'] = array();
} }
$row = self::upgradePreV1Format($row); $expire_date = (int) $row['expiredate'];
$paste['meta'] = $row['meta'];
$expire_date = (int) $row['expiredate'];
if ($expire_date > 0) { if ($expire_date > 0) {
$paste['meta']['expire_date'] = $expire_date; $paste['meta']['expire_date'] = $expire_date;
} }
if ($isVersion2) {
return $paste;
}
// support v1 attachments
if (array_key_exists('attachment', $row) && !empty($row['attachment'])) {
$paste['attachment'] = $row['attachment'];
if (array_key_exists('attachmentname', $row) && !empty($row['attachmentname'])) {
$paste['attachmentname'] = $row['attachmentname'];
}
}
if ($row['opendiscussion']) {
$paste['meta']['opendiscussion'] = true;
}
if ($row['burnafterreading']) {
$paste['meta']['burnafterreading'] = true;
}
return $paste; return $paste;
} }
@ -299,21 +250,14 @@ class Database extends AbstractData
*/ */
public function createComment($pasteid, $parentid, $commentid, array &$comment) public function createComment($pasteid, $parentid, $commentid, array &$comment)
{ {
if (array_key_exists('data', $comment)) { try {
$version = 1; $data = Json::encode($comment);
$data = $comment['data']; } catch (Exception $e) {
} else { return false;
try {
$version = 2;
$data = Json::encode($comment);
} catch (Exception $e) {
return false;
}
} }
list($createdKey, $iconKey) = $this->_getVersionedKeys($version); $meta = $comment['meta'];
$meta = $comment['meta'];
unset($comment['meta']); unset($comment['meta']);
foreach (array('nickname', $iconKey) as $key) { foreach (array('nickname', 'icon') as $key) {
if (!array_key_exists($key, $meta)) { if (!array_key_exists($key, $meta)) {
$meta[$key] = null; $meta[$key] = null;
} }
@ -328,8 +272,8 @@ class Database extends AbstractData
$parentid, $parentid,
$data, $data,
$meta['nickname'], $meta['nickname'],
$meta[$iconKey], $meta['icon'],
$meta[$createdKey], $meta['created'],
) )
); );
} catch (Exception $e) { } catch (Exception $e) {
@ -355,20 +299,12 @@ class Database extends AbstractData
$comments = array(); $comments = array();
if (is_array($rows) && count($rows)) { if (is_array($rows) && count($rows)) {
foreach ($rows as $row) { foreach ($rows as $row) {
$i = $this->getOpenSlot($comments, (int) $row['postdate']); $i = $this->getOpenSlot($comments, (int) $row['postdate']);
$data = Json::decode($row['data']); $comments[$i] = Json::decode($row['data']);
if (array_key_exists('v', $data) && $data['v'] >= 2) {
$version = 2;
$comments[$i] = $data;
} else {
$version = 1;
$comments[$i] = array('data' => $row['data']);
}
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
$comments[$i]['id'] = $row['dataid']; $comments[$i]['id'] = $row['dataid'];
$comments[$i]['parentid'] = $row['parentid']; $comments[$i]['parentid'] = $row['parentid'];
$comments[$i]['meta'] = array($createdKey => (int) $row['postdate']); $comments[$i]['meta'] = array('created' => (int) $row['postdate']);
foreach (array('nickname' => 'nickname', 'vizhash' => $iconKey) as $rowKey => $commentKey) { foreach (array('nickname' => 'nickname', 'vizhash' => 'icon') as $rowKey => $commentKey) {
if (array_key_exists($rowKey, $row) && !empty($row[$rowKey])) { if (array_key_exists($rowKey, $row) && !empty($row[$rowKey])) {
$comments[$i]['meta'][$commentKey] = $row[$rowKey]; $comments[$i]['meta'][$commentKey] = $row[$rowKey];
} }
@ -561,21 +497,6 @@ class Database extends AbstractData
return $result; return $result;
} }
/**
* get version dependent key names
*
* @access private
* @param int $version
* @return array
*/
private function _getVersionedKeys($version)
{
if ($version === 1) {
return array('postdate', 'vizhash');
}
return array('created', 'icon');
}
/** /**
* get table list query, depending on the database type * get table list query, depending on the database type
* *
@ -737,16 +658,12 @@ class Database extends AbstractData
"\"dataid\" CHAR(16) NOT NULL$main_key, " . "\"dataid\" CHAR(16) NOT NULL$main_key, " .
"\"data\" $attachmentType, " . "\"data\" $attachmentType, " .
'"expiredate" INT, ' . '"expiredate" INT, ' .
'"opendiscussion" INT, ' . "\"meta\" $metaType$after_key )"
'"burnafterreading" INT, ' .
"\"meta\" $metaType, " .
"\"attachment\" $attachmentType, " .
"\"attachmentname\" $dataType$after_key )"
); );
} }
/** /**
* create the paste table * create the comment table
* *
* @access private * @access private
*/ */
@ -789,7 +706,7 @@ class Database extends AbstractData
} }
/** /**
* create the paste table * create the config table
* *
* @access private * @access private
*/ */
@ -839,6 +756,26 @@ class Database extends AbstractData
return preg_replace('/[^A-Za-z0-9_]+/', '', $this->_prefix . $identifier); return preg_replace('/[^A-Za-z0-9_]+/', '', $this->_prefix . $identifier);
} }
/**
* check if the current database type supports dropping columns
*
* @access private
* @return bool
*/
private function _supportsDropColumn()
{
$supportsDropColumn = true;
if ($this->_type === 'sqlite') {
try {
$row = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
$supportsDropColumn = version_compare($row['v'], '3.35.0', '>=');
} catch (PDOException $e) {
$supportsDropColumn = false;
}
}
return $supportsDropColumn;
}
/** /**
* upgrade the database schema from an old version * upgrade the database schema from an old version
* *
@ -910,22 +847,33 @@ class Database extends AbstractData
} }
} }
if (version_compare($oldversion, '1.7.1', '<=')) { if (version_compare($oldversion, '1.7.1', '<=')) {
$supportsDropColumn = true; if ($this->_supportsDropColumn()) {
if ($this->_type === 'sqlite') {
try {
$row = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
$supportsDropColumn = version_compare($row['v'], '3.35.0', '>=');
} catch (PDOException $e) {
$supportsDropColumn = false;
}
}
if ($supportsDropColumn) {
$this->_db->exec( $this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') . 'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
'" DROP COLUMN "postdate"' '" DROP COLUMN "postdate"'
); );
} }
} }
if (version_compare($oldversion, '1.7.8', '<=')) {
if ($this->_supportsDropColumn()) {
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
'" DROP COLUMN "opendiscussion"'
);
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
'" DROP COLUMN "burnafterreading"'
);
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
'" DROP COLUMN "attachment"'
);
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
'" DROP COLUMN "attachmentname"'
);
}
}
$this->_exec( $this->_exec(
'UPDATE "' . $this->_sanitizeIdentifier('config') . 'UPDATE "' . $this->_sanitizeIdentifier('config') .
'" SET "value" = ? WHERE "id" = ?', '" SET "value" = ? WHERE "id" = ?',

View file

@ -113,7 +113,7 @@ class Filesystem extends AbstractData
) { ) {
return false; return false;
} }
return self::upgradePreV1Format($paste); return $paste;
} }
/** /**

View file

@ -98,8 +98,7 @@ class GoogleCloudStorage extends AbstractData
/** /**
* Uploads the payload in the $this->_bucket under the specified key. * Uploads the payload in the $this->_bucket under the specified key.
* The entire payload is stored as a JSON document. The metadata is replicated * The entire payload is stored as a JSON document. The metadata is replicated
* as the GCS object's metadata except for the fields attachment, attachmentname * as the GCS object's metadata except for the field salt.
* and salt.
* *
* @param $key string to store the payload under * @param $key string to store the payload under
* @param $payload array to store * @param $payload array to store
@ -108,7 +107,7 @@ class GoogleCloudStorage extends AbstractData
private function _upload($key, &$payload) private function _upload($key, &$payload)
{ {
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array(); $metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']); unset($metadata['salt']);
foreach ($metadata as $k => $v) { foreach ($metadata as $k => $v) {
$metadata[$k] = strval($v); $metadata[$k] = strval($v);
} }

View file

@ -158,8 +158,7 @@ class S3Storage extends AbstractData
/** /**
* Uploads the payload in the $this->_bucket under the specified key. * Uploads the payload in the $this->_bucket under the specified key.
* The entire payload is stored as a JSON document. The metadata is replicated * The entire payload is stored as a JSON document. The metadata is replicated
* as the S3 object's metadata except for the fields attachment, attachmentname * as the S3 object's metadata except for the field salt.
* and salt.
* *
* @param $key string to store the payload under * @param $key string to store the payload under
* @param $payload array to store * @param $payload array to store
@ -168,7 +167,7 @@ class S3Storage extends AbstractData
private function _upload($key, &$payload) private function _upload($key, &$payload)
{ {
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array(); $metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']); unset($metadata['salt']);
foreach ($metadata as $k => $v) { foreach ($metadata as $k => $v) {
$metadata[$k] = strval($v); $metadata[$k] = strval($v);
} }

View file

@ -22,6 +22,27 @@ use PrivateBin\Persistence\ServerSalt;
*/ */
class Paste extends AbstractModel class Paste extends AbstractModel
{ {
/**
* authenticated data index of paste formatter (plaintext/syntaxhighlighting/markdown)
*
* @const int
*/
const ADATA_FORMATTER = 1;
/**
* authenticated data index of open-discussion flag (0/1)
*
* @const int
*/
const ADATA_OPEN_DISCUSSION = 2;
/**
* authenticated data index of burn-after-reading flag (0/1)
*
* @const int
*/
const ADATA_BURN_AFTER_READING = 3;
/** /**
* Get paste data. * Get paste data.
* *
@ -38,12 +59,13 @@ class Paste extends AbstractModel
// check if paste has expired and delete it if necessary. // check if paste has expired and delete it if necessary.
if (array_key_exists('expire_date', $data['meta'])) { if (array_key_exists('expire_date', $data['meta'])) {
if ($data['meta']['expire_date'] < time()) { $now = time();
if ($data['meta']['expire_date'] < $now) {
$this->delete(); $this->delete();
throw new Exception(Controller::GENERIC_ERROR, 63); throw new Exception(Controller::GENERIC_ERROR, 63);
} }
// We kindly provide the remaining time before expiration (in seconds) // We kindly provide the remaining time before expiration (in seconds)
$data['meta']['time_to_live'] = $data['meta']['expire_date'] - time(); $data['meta']['time_to_live'] = $data['meta']['expire_date'] - $now;
unset($data['meta']['expire_date']); unset($data['meta']['expire_date']);
} }
foreach (array('created', 'postdate') as $key) { foreach (array('created', 'postdate') as $key) {
@ -54,8 +76,8 @@ class Paste extends AbstractModel
// check if non-expired burn after reading paste needs to be deleted // check if non-expired burn after reading paste needs to be deleted
if ( if (
(array_key_exists('adata', $data) && $data['adata'][3] === 1) || array_key_exists('adata', $data) &&
(array_key_exists('burnafterreading', $data['meta']) && $data['meta']['burnafterreading']) $data['adata'][self::ADATA_BURN_AFTER_READING] === 1
) { ) {
$this->delete(); $this->delete();
} }
@ -205,9 +227,8 @@ class Paste extends AbstractModel
if (!array_key_exists('adata', $this->_data) && !array_key_exists('data', $this->_data)) { if (!array_key_exists('adata', $this->_data) && !array_key_exists('data', $this->_data)) {
$this->get(); $this->get();
} }
return return array_key_exists('adata', $this->_data) &&
(array_key_exists('adata', $this->_data) && $this->_data['adata'][2] === 1) || $this->_data['adata'][self::ADATA_OPEN_DISCUSSION] === 1;
(array_key_exists('opendiscussion', $this->_data['meta']) && $this->_data['meta']['opendiscussion']);
} }
/** /**
@ -242,23 +263,26 @@ class Paste extends AbstractModel
protected function _validate(array &$data) protected function _validate(array &$data)
{ {
// reject invalid or disabled formatters // reject invalid or disabled formatters
if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) { if (!array_key_exists($data['adata'][self::ADATA_FORMATTER], $this->_conf->getSection('formatter_options'))) {
throw new Exception('Invalid data.', 75); throw new Exception('Invalid data.', 75);
} }
// discussion requested, but disabled in config or burn after reading requested as well, or invalid integer // discussion requested, but disabled in config or burn after reading requested as well, or invalid integer
if ( if (
($data['adata'][2] === 1 && ( // open discussion flag ($data['adata'][self::ADATA_OPEN_DISCUSSION] === 1 && (
!$this->_conf->getKey('discussion') || !$this->_conf->getKey('discussion') ||
$data['adata'][3] === 1 // burn after reading flag $data['adata'][self::ADATA_BURN_AFTER_READING] === 1
)) || )) ||
($data['adata'][2] !== 0 && $data['adata'][2] !== 1) ($data['adata'][self::ADATA_OPEN_DISCUSSION] !== 0 && $data['adata'][self::ADATA_OPEN_DISCUSSION] !== 1)
) { ) {
throw new Exception('Invalid data.', 74); throw new Exception('Invalid data.', 74);
} }
// reject invalid burn after reading // reject invalid burn after reading
if ($data['adata'][3] !== 0 && $data['adata'][3] !== 1) { if (
$data['adata'][self::ADATA_BURN_AFTER_READING] !== 0 &&
$data['adata'][self::ADATA_BURN_AFTER_READING] !== 1
) {
throw new Exception('Invalid data.', 73); throw new Exception('Invalid data.', 73);
} }
} }

View file

@ -39,22 +39,6 @@ class Helper
*/ */
private static $pasteid = '5b65a01b43987bc2'; private static $pasteid = '5b65a01b43987bc2';
/**
* example paste version 1
*
* @var array
*/
private static $pasteV1 = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'attachment' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'attachmentname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'meta' => array(
'formatter' => 'plaintext',
'postdate' => 1344803344,
'opendiscussion' => true,
),
);
/** /**
* example paste version 2 * example paste version 2
* *
@ -91,17 +75,13 @@ class Helper
private static $commentid = '5a52eebf11c4c94b'; private static $commentid = '5a52eebf11c4c94b';
/** /**
* example comment * example comment meta data
* *
* @var array * @var array
*/ */
private static $commentV1 = array( private static $commentV2 = array(
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}', 'icon' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'meta' => array( 'created' => 1344803528,
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'postdate' => 1344803528,
),
); );
/** /**
@ -124,30 +104,12 @@ class Helper
/** /**
* get example paste, as stored on server * get example paste, as stored on server
* *
* @param int $version
* @param array $meta * @param array $meta
* @return array * @return array
*/ */
public static function getPaste($version = 2, array $meta = array()): array public static function getPaste(array $meta = array()): array
{ {
$example = self::getPasteWithAttachment($version, $meta); $example = self::$pasteV2;
// v1 has the attachment stored in a separate property
if ($version === 1) {
unset($example['attachment'], $example['attachmentname']);
}
return $example;
}
/**
* get example paste with attachment, as stored on server
*
* @param int $version
* @param array $meta
* @return array
*/
public static function getPasteWithAttachment($version = 2, array $meta = array()): array
{
$example = $version === 1 ? self::$pasteV1 : self::$pasteV2;
$example['meta']['salt'] = ServerSalt::generate(); $example['meta']['salt'] = ServerSalt::generate();
$example['meta'] = array_merge($example['meta'], $meta); $example['meta'] = array_merge($example['meta'], $meta);
return $example; return $example;
@ -156,31 +118,25 @@ class Helper
/** /**
* get example paste, as decoded from POST by the request object * get example paste, as decoded from POST by the request object
* *
* @param int $version
* @param array $meta * @param array $meta
* @return array * @return array
*/ */
public static function getPastePost($version = 2, array $meta = array()): array public static function getPastePost(array $meta = array()): array
{ {
$example = self::getPaste($version, $meta); $example = self::getPaste($meta);
if ($version == 2) { $example['meta'] = array('expire' => $example['meta']['expire']);
$example['meta'] = array('expire' => $example['meta']['expire']);
} else {
unset($example['meta']['postdate']);
}
return $example; return $example;
} }
/** /**
* get example paste, as received via POST by the user * get example paste, as received via POST by the user
* *
* @param int $version
* @param array $meta * @param array $meta
* @return string * @return string
*/ */
public static function getPasteJson($version = 2, array $meta = array()): string public static function getPasteJson(array $meta = array()): string
{ {
return json_encode(self::getPastePost($version, $meta)); return json_encode(self::getPastePost($meta));
} }
/** /**
@ -196,20 +152,16 @@ class Helper
/** /**
* get example comment, as stored on server * get example comment, as stored on server
* *
* @param int $version
* @param array $meta * @param array $meta
* @return array * @return array
*/ */
public static function getComment($version = 2, array $meta = array()): array public static function getComment(array $meta = array()): array
{ {
$example = $version === 1 ? self::$commentV1 : self::$pasteV2; $example = self::$pasteV2;
if ($version === 2) { $example['adata'] = $example['adata'][0];
$example['adata'] = $example['adata'][0]; $example['pasteid'] = $example['parentid'] = self::getPasteId();
$example['pasteid'] = $example['parentid'] = self::getPasteId(); unset($example['meta']['expire']);
$example['meta']['created'] = self::$commentV1['meta']['postdate']; $example['meta'] = array_merge($example['meta'], self::$commentV2);
$example['meta']['icon'] = self::$commentV1['meta']['vizhash'];
unset($example['meta']['expire']);
}
$example['meta'] = array_merge($example['meta'], $meta); $example['meta'] = array_merge($example['meta'], $meta);
return $example; return $example;
} }
@ -217,7 +169,6 @@ class Helper
/** /**
* get example comment, as decoded from POST by the request object * get example comment, as decoded from POST by the request object
* *
* @param int $version
* @return array * @return array
*/ */
public static function getCommentPost(): array public static function getCommentPost(): array
@ -230,7 +181,6 @@ class Helper
/** /**
* get example comment, as received via POST by user * get example comment, as received via POST by user
* *
* @param int $version
* @return string * @return string
*/ */
public static function getCommentJson(): string public static function getCommentJson(): string

View file

@ -201,7 +201,7 @@ class ControllerTest extends TestCase
$options = parse_ini_file(CONF, true); $options = parse_ini_file(CONF, true);
$options['traffic']['limit'] = 0; $options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options); Helper::createIniFile(CONF, $options);
$paste = Helper::getPasteJson(2, array('expire' => 25)); $paste = Helper::getPasteJson(array('expire' => 25));
$file = tempnam(sys_get_temp_dir(), 'FOO'); $file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, $paste); file_put_contents($file, $paste);
Request::setInputStream($file); Request::setInputStream($file);
@ -379,7 +379,7 @@ class ControllerTest extends TestCase
$options = parse_ini_file(CONF, true); $options = parse_ini_file(CONF, true);
$options['traffic']['limit'] = 0; $options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options); Helper::createIniFile(CONF, $options);
$paste = Helper::getPasteJson(2, array('expire' => 'foo')); $paste = Helper::getPasteJson(array('expire' => 'foo'));
$file = tempnam(sys_get_temp_dir(), 'FOO'); $file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, $paste); file_put_contents($file, $paste);
Request::setInputStream($file); Request::setInputStream($file);
@ -510,7 +510,7 @@ class ControllerTest extends TestCase
$options['traffic']['limit'] = 0; $options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options); Helper::createIniFile(CONF, $options);
$file = tempnam(sys_get_temp_dir(), 'FOO'); $file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, Helper::getPasteJson(1)); file_put_contents($file, '{"data":"","meta":{}}');
Request::setInputStream($file); Request::setInputStream($file);
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST'; $_SERVER['REQUEST_METHOD'] = 'POST';
@ -696,7 +696,7 @@ class ControllerTest extends TestCase
*/ */
public function testReadExpired() public function testReadExpired()
{ {
$expiredPaste = Helper::getPaste(2, array('expire_date' => 1344803344)); $expiredPaste = Helper::getPaste(array('expire_date' => 1344803344));
$this->_data->create(Helper::getPasteId(), $expiredPaste); $this->_data->create(Helper::getPasteId(), $expiredPaste);
$_SERVER['QUERY_STRING'] = Helper::getPasteId(); $_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_GET[Helper::getPasteId()] = ''; $_GET[Helper::getPasteId()] = '';
@ -767,37 +767,6 @@ class ControllerTest extends TestCase
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly'); $this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
} }
/**
* @runInSeparateProcess
*/
public function testReadOldSyntax()
{
$paste = Helper::getPaste(1);
$paste['meta'] = array(
'syntaxcoloring' => true,
'postdate' => $paste['meta']['postdate'],
'opendiscussion' => $paste['meta']['opendiscussion'],
);
$this->_data->create(Helper::getPasteId(), $paste);
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_GET[Helper::getPasteId()] = '';
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs success status');
$this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
$this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
$this->assertEquals($paste['data'], $response['data'], 'outputs data correctly');
$this->assertEquals('syntaxhighlighting', $response['meta']['formatter'], 'outputs format correctly');
$this->assertFalse(array_key_exists('postdate', $response['meta']), 'does not output postdate');
$this->assertEquals($paste['meta']['opendiscussion'], $response['meta']['opendiscussion'], 'outputs opendiscussion correctly');
$this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
}
/** /**
* @runInSeparateProcess * @runInSeparateProcess
*/ */
@ -933,7 +902,7 @@ class ControllerTest extends TestCase
*/ */
public function testDeleteExpired() public function testDeleteExpired()
{ {
$expiredPaste = Helper::getPaste(2, array('expire_date' => 1000)); $expiredPaste = Helper::getPaste(array('expire_date' => 1000));
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created'); $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created');
$this->_data->create(Helper::getPasteId(), $expiredPaste); $this->_data->create(Helper::getPasteId(), $expiredPaste);
$this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data'); $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');

View file

@ -60,8 +60,8 @@ class DatabaseTest extends TestCase
$this->assertEquals($paste, $this->_model->read(Helper::getPasteId())); $this->assertEquals($paste, $this->_model->read(Helper::getPasteId()));
// storing comments // storing comments
$comment1 = Helper::getComment(1); $comment1 = Helper::getComment();
$comment2 = Helper::getComment(2); $comment2 = Helper::getComment();
$meta1 = $comment1['meta']; $meta1 = $comment1['meta'];
$meta2 = $comment2['meta']; $meta2 = $comment2['meta'];
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist');
@ -78,7 +78,7 @@ class DatabaseTest extends TestCase
$comment2['meta'] = $meta2; $comment2['meta'] = $meta2;
$this->assertEquals( $this->assertEquals(
array( array(
$comment1['meta']['postdate'] => $comment1, $comment1['meta']['created'] => $comment1,
$comment2['meta']['created'] . '.1' => $comment2, $comment2['meta']['created'] . '.1' => $comment2,
), ),
$this->_model->readComments(Helper::getPasteId()) $this->_model->readComments(Helper::getPasteId())
@ -95,11 +95,8 @@ class DatabaseTest extends TestCase
{ {
// this assumes a version 1 formatted paste // this assumes a version 1 formatted paste
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344)); $original = $paste = Helper::getPaste(array('expire_date' => 1344803344));
$paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true; $paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true;
$paste['meta']['attachment'] = $paste['attachment'];
$paste['meta']['attachmentname'] = $paste['attachmentname'];
unset($paste['attachment'], $paste['attachmentname']);
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@ -113,8 +110,8 @@ class DatabaseTest extends TestCase
public function testPurge() public function testPurge()
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$expired = Helper::getPaste(2, array('expire_date' => 1344803344)); $expired = Helper::getPaste(array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); $paste = Helper::getPaste(array('expire_date' => time() + 3600));
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
$ids = array(); $ids = array();
foreach ($keys as $key) { foreach ($keys as $key) {
@ -145,7 +142,7 @@ class DatabaseTest extends TestCase
public function testErrorDetection() public function testErrorDetection()
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
@ -155,7 +152,7 @@ class DatabaseTest extends TestCase
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$data = Helper::getPaste(); $data = Helper::getPaste();
$comment = Helper::getComment(2, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31")); $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@ -263,91 +260,6 @@ class DatabaseTest extends TestCase
new Database($options); new Database($options);
} }
public function testOldAttachments()
{
mkdir($this->_path);
$path = $this->_path . DIRECTORY_SEPARATOR . 'attachement-test.sq3';
if (is_file($path)) {
unlink($path);
}
$this->_options['dsn'] = 'sqlite:' . $path;
$this->_options['tbl'] = 'bar_';
$model = new Database($this->_options);
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
$meta = $paste['meta'];
$meta['attachment'] = $paste['attachment'];
$meta['attachmentname'] = $paste['attachmentname'];
unset($paste['attachment'], $paste['attachmentname']);
$db = new PDO(
$this->_options['dsn'],
$this->_options['usr'],
$this->_options['pwd'],
$this->_options['opt']
);
$statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$paste['data'],
$paste['meta']['expire_date'],
0,
0,
json_encode($meta),
null,
null,
)
);
$statement->closeCursor();
$this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertEquals($original, $model->read(Helper::getPasteId()));
Helper::rmDir($this->_path);
}
public function testCorruptMeta()
{
mkdir($this->_path);
$path = $this->_path . DIRECTORY_SEPARATOR . 'meta-test.sq3';
if (is_file($path)) {
unlink($path);
}
$this->_options['dsn'] = 'sqlite:' . $path;
$this->_options['tbl'] = 'baz_';
$model = new Database($this->_options);
$paste = Helper::getPaste(1, array('expire_date' => 1344803344));
unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['postdate'], $paste['meta']['salt']);
$model->delete(Helper::getPasteId());
$db = new PDO(
$this->_options['dsn'],
$this->_options['usr'],
$this->_options['pwd'],
$this->_options['opt']
);
$statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$paste['data'],
$paste['meta']['expire_date'],
0,
0,
'{',
null,
null,
)
);
$statement->closeCursor();
$this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertEquals($paste, $model->read(Helper::getPasteId()));
Helper::rmDir($this->_path);
}
public function testTableUpgrade() public function testTableUpgrade()
{ {
mkdir($this->_path); mkdir($this->_path);

View file

@ -37,7 +37,7 @@ class FilesystemTest extends TestCase
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
// storing pastes // storing pastes
$paste = Helper::getPaste(2, array('expire_date' => 1344803344)); $paste = Helper::getPaste(array('expire_date' => 1344803344));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@ -67,10 +67,7 @@ class FilesystemTest extends TestCase
public function testFileBasedAttachmentStoreWorks() public function testFileBasedAttachmentStoreWorks()
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344)); $original = $paste = Helper::getPaste(array('expire_date' => 1344803344));
$paste['meta']['attachment'] = $paste['attachment'];
$paste['meta']['attachmentname'] = $paste['attachmentname'];
unset($paste['attachment'], $paste['attachmentname']);
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@ -84,8 +81,8 @@ class FilesystemTest extends TestCase
public function testPurge() public function testPurge()
{ {
mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true); mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true);
$expired = Helper::getPaste(2, array('expire_date' => 1344803344)); $expired = Helper::getPaste(array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); $paste = Helper::getPaste(array('expire_date' => time() + 3600));
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
$ids = array(); $ids = array();
foreach ($keys as $key) { foreach ($keys as $key) {
@ -115,7 +112,7 @@ class FilesystemTest extends TestCase
public function testErrorDetection() public function testErrorDetection()
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
@ -126,7 +123,7 @@ class FilesystemTest extends TestCase
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$data = Helper::getPaste(); $data = Helper::getPaste();
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31")); $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');

View file

@ -50,7 +50,7 @@ class GoogleCloudStorageTest extends TestCase
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
// storing pastes // storing pastes
$paste = Helper::getPaste(2, array('expire_date' => 1344803344)); $paste = Helper::getPaste(array('expire_date' => 1344803344));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@ -82,8 +82,8 @@ class GoogleCloudStorageTest extends TestCase
*/ */
public function testPurge() public function testPurge()
{ {
$expired = Helper::getPaste(2, array('expire_date' => 1344803344)); $expired = Helper::getPaste(array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); $paste = Helper::getPaste(array('expire_date' => time() + 3600));
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
$ids = array(); $ids = array();
foreach ($keys as $key) { foreach ($keys as $key) {
@ -113,7 +113,7 @@ class GoogleCloudStorageTest extends TestCase
public function testErrorDetection() public function testErrorDetection()
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31")); $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $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->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
@ -123,7 +123,7 @@ class GoogleCloudStorageTest extends TestCase
{ {
$this->_model->delete(Helper::getPasteId()); $this->_model->delete(Helper::getPasteId());
$data = Helper::getPaste(); $data = Helper::getPaste();
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31")); $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist'); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste'); $this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it'); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');

View file

@ -103,57 +103,6 @@ class ModelTest extends TestCase
$this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste'); $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
} }
public function testPasteV1()
{
$pasteData = Helper::getPaste(1);
unset($pasteData['meta']['formatter']);
$path = $this->_path . DIRECTORY_SEPARATOR . 'v1-test.sq3';
if (is_file($path)) {
unlink($path);
}
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite:' . $path,
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$model->getPaste('0000000000000000')->exists(); // triggers database table creation
$model->getPaste(Helper::getPasteId())->delete(); // deletes the cache
$db = new PDO(
$options['model_options']['dsn'],
$options['model_options']['usr'],
$options['model_options']['pwd'],
$options['model_options']['opt']
);
$statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$pasteData['data'],
0,
0,
0,
json_encode($pasteData['meta']),
null,
null,
)
);
$statement->closeCursor();
$paste = $model->getPaste(Helper::getPasteId());
$this->assertNotEmpty($paste->getDeleteToken(), 'excercise the condition to load the data from storage');
$this->assertEquals('plaintext', $paste->get()['meta']['formatter'], 'paste got created with default formatter');
}
public function testCommentDefaults() public function testCommentDefaults()
{ {
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model'); $class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
@ -428,8 +377,8 @@ class ModelTest extends TestCase
$conf = new Configuration; $conf = new Configuration;
$store = new Database($conf->getSection('model_options')); $store = new Database($conf->getSection('model_options'));
$store->delete(Helper::getPasteId()); $store->delete(Helper::getPasteId());
$expired = Helper::getPaste(2, array('expire_date' => 1344803344)); $expired = Helper::getPaste(array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600)); $paste = Helper::getPaste(array('expire_date' => time() + 3600));
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z'); $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z');
$ids = array(); $ids = array();
foreach ($keys as $key) { foreach ($keys as $key) {