diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ee0909d..189651d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
* CHANGED: Drop some PHP < 5.6 fallbacks, minimum version is PHP 7.3 as of release 1.6.0
* CHANGED: Set `lang` cookie with lax `SameSite` property
* CHANGED: Upgrading libraries to: DOMpurify 3.1.2 (#1299) & jQuery 3.7.1
+* CHANGED: `create` attribute is no longer returned in API for pastes & can be disabled for comments using `discussiondatedisplay` as well (#1290)
* FIXED: Add cache control headers also to API calls (#1263)
* FIXED: Shortened paste URL does not appear in email (#606)
diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php
index 75831f45..31dcb0a8 100644
--- a/cfg/conf.sample.php
+++ b/cfg/conf.sample.php
@@ -18,6 +18,11 @@ discussion = true
; preselect the discussion feature, defaults to false
opendiscussion = false
+; enable or disable the diplay of dates & times in the comments, defaults to true
+; Note that internally the creation time will still get tracked in order to sort
+; the comments by creation time, but you can choose not to display them.
+; discussiondatedisplay = false
+
; enable or disable the password feature, defaults to true
password = true
diff --git a/doc/Installation.md b/doc/Installation.md
index b09de9e1..d2f21f7d 100644
--- a/doc/Installation.md
+++ b/doc/Installation.md
@@ -170,14 +170,13 @@ user these additional privileges:
For reference or if you want to create the table schema for yourself to avoid
having to give PrivateBin too many permissions (replace `prefix_` with your own
-table prefix and create the table schema with your favourite MariaDB/MySQL
+table prefix and create the table schema with your favorite MariaDB/MySQL
client):
```sql
CREATE TABLE prefix_paste (
dataid CHAR(16) NOT NULL,
data MEDIUMBLOB,
- postdate INT,
expiredate INT,
opendiscussion INT,
burnafterreading INT,
diff --git a/js/privatebin.js b/js/privatebin.js
index e9c0dcde..606ba1bc 100644
--- a/js/privatebin.js
+++ b/js/privatebin.js
@@ -196,7 +196,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
this.getCreated = function()
{
- return this.meta[this.v === 1 ? 'postdate' : 'created'];
+ return this.meta[this.v === 1 ? 'postdate' : 'created'] || 0;
}
/**
@@ -2736,7 +2736,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
if (Editor.isPreview()) {
PasteViewer.run();
}
-
};
/**
@@ -3495,9 +3494,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
// set date
+ const created = comment.getCreated();
+ const commentDate = created == 0 ? '' : ' (' + (new Date(created * 1000).toLocaleString()) + ')';
$commentEntry.find('span.commentdate')
- .text(' (' + (new Date(comment.getCreated() * 1000).toLocaleString()) + ')')
- .attr('title', 'CommentID: ' + comment.id);
+ .text(commentDate)
+ .attr('title', 'CommentID: ' + comment.id);
// if an avatar is available, display it
const icon = comment.getIcon();
diff --git a/lib/Configuration.php b/lib/Configuration.php
index cf0febe6..4ffe4abc 100644
--- a/lib/Configuration.php
+++ b/lib/Configuration.php
@@ -40,6 +40,7 @@ class Configuration
'basepath' => '',
'discussion' => true,
'opendiscussion' => false,
+ 'discussiondatedisplay' => true,
'password' => true,
'fileupload' => false,
'burnafterreadingselected' => false,
diff --git a/lib/Data/Database.php b/lib/Data/Database.php
index 27874962..b9de2d47 100644
--- a/lib/Data/Database.php
+++ b/lib/Data/Database.php
@@ -146,9 +146,6 @@ class Database extends AbstractData
$attachment = $attachmentname = null;
$meta = $paste['meta'];
$isVersion1 = array_key_exists('data', $paste);
- list($createdKey) = $this->_getVersionedKeys($isVersion1 ? 1 : 2);
- $created = (int) $meta[$createdKey];
- unset($meta[$createdKey], $paste['meta']);
if (array_key_exists('expire_date', $meta)) {
$expire_date = (int) $meta['expire_date'];
unset($meta['expire_date']);
@@ -177,11 +174,10 @@ class Database extends AbstractData
try {
return $this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
- '" VALUES(?,?,?,?,?,?,?,?,?)',
+ '" VALUES(?,?,?,?,?,?,?,?)',
array(
$pasteid,
$isVersion1 ? $paste['data'] : Json::encode($paste),
- $created,
$expire_date,
(int) $opendiscussion,
(int) $burnafterreading,
@@ -218,13 +214,7 @@ class Database extends AbstractData
// create array
$data = Json::decode($row['data']);
$isVersion2 = array_key_exists('v', $data) && $data['v'] >= 2;
- if ($isVersion2) {
- $paste = $data;
- list($createdKey) = $this->_getVersionedKeys(2);
- } else {
- $paste = array('data' => $row['data']);
- list($createdKey) = $this->_getVersionedKeys(1);
- }
+ $paste = $isVersion2 ? $data : array('data' => $row['data']);
try {
$row['meta'] = Json::decode($row['meta']);
@@ -233,7 +223,6 @@ class Database extends AbstractData
}
$row = self::upgradePreV1Format($row);
$paste['meta'] = $row['meta'];
- $paste['meta'][$createdKey] = (int) $row['postdate'];
$expire_date = (int) $row['expiredate'];
if ($expire_date > 0) {
$paste['meta']['expire_date'] = $expire_date;
@@ -751,7 +740,6 @@ class Database extends AbstractData
'CREATE TABLE "' . $this->_sanitizeIdentifier('paste') . '" ( ' .
"\"dataid\" CHAR(16) NOT NULL$main_key, " .
"\"data\" $attachmentType, " .
- '"postdate" INT, ' .
'"expiredate" INT, ' .
'"opendiscussion" INT, ' .
'"burnafterreading" INT, ' .
@@ -926,6 +914,23 @@ class Database extends AbstractData
);
}
// no break, continue with updates for all newer versions
+ case '1.7.2':
+ $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;
+ }
+ }
+ if ($supportsDropColumn) {
+ $this->_db->exec(
+ 'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
+ '" DROP COLUMN "postdate"'
+ );
+ }
+ // no break, continue with updates for all newer versions
default:
$this->_exec(
'UPDATE "' . $this->_sanitizeIdentifier('config') .
diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php
index 8a529c84..c11f8cf6 100644
--- a/lib/Model/Paste.php
+++ b/lib/Model/Paste.php
@@ -37,7 +37,7 @@ class Paste extends AbstractModel
throw new Exception(Controller::GENERIC_ERROR, 64);
}
- // check if paste has expired and delete it if neccessary.
+ // check if paste has expired and delete it if necessary.
if (array_key_exists('expire_date', $data['meta'])) {
if ($data['meta']['expire_date'] < time()) {
$this->delete();
@@ -47,6 +47,11 @@ class Paste extends AbstractModel
$data['meta']['time_to_live'] = $data['meta']['expire_date'] - time();
unset($data['meta']['expire_date']);
}
+ foreach (array('created', 'postdate') as $key) {
+ if (array_key_exists($key, $data['meta'])) {
+ unset($data['meta'][$key]);
+ }
+ }
// check if non-expired burn after reading paste needs to be deleted
if (
@@ -92,8 +97,7 @@ class Paste extends AbstractModel
throw new Exception('You are unlucky. Try again.', 75);
}
- $this->_data['meta']['created'] = time();
- $this->_data['meta']['salt'] = ServerSalt::generate();
+ $this->_data['meta']['salt'] = ServerSalt::generate();
// store paste
if (
@@ -159,7 +163,17 @@ class Paste extends AbstractModel
*/
public function getComments()
{
- return $this->_store->readComments($this->getId());
+ if ($this->_conf->getKey('discussiondatedisplay')) {
+ return $this->_store->readComments($this->getId());
+ }
+ return array_map(function ($comment) {
+ foreach (array('created', 'postdate') as $key) {
+ if (array_key_exists($key, $comment['meta'])) {
+ unset($comment['meta'][$key]);
+ }
+ }
+ return $comment;
+ }, $this->_store->readComments($this->getId()));
}
/**
diff --git a/lib/Vizhash16x16.php b/lib/Vizhash16x16.php
index 2d296af8..5a408655 100644
--- a/lib/Vizhash16x16.php
+++ b/lib/Vizhash16x16.php
@@ -109,9 +109,9 @@ class Vizhash16x16
for ($i = 0; $i < 7; ++$i) {
$action = $this->getInt();
$color = imagecolorallocate($image, $r, $g, $b);
- $r = $r0 = ((int) $r0 + $this->getInt() / 25) % 256;
- $g = $g0 = ((int) $g0 + $this->getInt() / 25) % 256;
- $b = $b0 = ((int) $b0 + $this->getInt() / 25) % 256;
+ $r = $r0 = (int) ($r0 + $this->getInt() / 25) % 256;
+ $g = $g0 = (int) ($g0 + $this->getInt() / 25) % 256;
+ $b = $b0 = (int) ($b0 + $this->getInt() / 25) % 256;
$this->drawshape($image, $action, $color);
}
@@ -148,7 +148,7 @@ class Vizhash16x16
*/
private function getX()
{
- return (int) $this->width * $this->getInt() / 256;
+ return (int) ($this->width * $this->getInt() / 256);
}
/**
@@ -159,7 +159,7 @@ class Vizhash16x16
*/
private function getY()
{
- return (int) $this->height * $this->getInt() / 256;
+ return (int) ($this->height * $this->getInt() / 256);
}
/**
@@ -225,8 +225,8 @@ class Vizhash16x16
version_compare(PHP_VERSION, '8.1', '<') ? imagefilledpolygon($image, $points, 4, $color) : imagefilledpolygon($image, $points, $color);
break;
default:
- $start = $this->getInt() * 360 / 256;
- $end = $start + $this->getInt() * 180 / 256;
+ $start = (int) ($this->getInt() * 360 / 256);
+ $end = (int) ($start + $this->getInt() * 180 / 256);
imagefilledarc($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $start, $end, $color, IMG_ARC_PIE);
}
}
diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php
index d750b03d..1a05905d 100644
--- a/tpl/bootstrap.php
+++ b/tpl/bootstrap.php
@@ -73,7 +73,7 @@ endif;
?>
-
+
diff --git a/tpl/bootstrap5.php b/tpl/bootstrap5.php
index 116c31c1..5afa4827 100644
--- a/tpl/bootstrap5.php
+++ b/tpl/bootstrap5.php
@@ -57,7 +57,7 @@ endif;
?>
-
+
diff --git a/tpl/page.php b/tpl/page.php
index 12b166ac..a66184f6 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 183d1b1d..8ea249d2 100644
--- a/tst/Bootstrap.php
+++ b/tst/Bootstrap.php
@@ -660,7 +660,6 @@ class Helper
),
'meta' => array(
'expire' => '5min',
- 'created' => 1344803344,
),
'v' => 2,
'ct' => 'ME5JF/YBEijp2uYMzLZozbKtWc5wfy6R59NBb7SmRig=',
diff --git a/tst/ControllerTest.php b/tst/ControllerTest.php
index 8aee7829..b1a5774f 100644
--- a/tst/ControllerTest.php
+++ b/tst/ControllerTest.php
@@ -170,6 +170,7 @@ class ControllerTest extends TestCase
$this->assertEquals(0, $response['status'], 'outputs status');
$this->assertTrue($this->_data->exists($response['id']), 'paste exists after posting data');
$paste = $this->_data->read($response['id']);
+ $this->assertFalse(array_key_exists('created', $paste['meta']), 'does not output created');
$this->assertEquals(
hash_hmac('sha256', $response['id'], $paste['meta']['salt']),
$response['deletetoken'],
@@ -712,7 +713,7 @@ class ControllerTest extends TestCase
$this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
$this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
$this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
- $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
+ $this->assertFalse(array_key_exists('created', $response['meta']), 'does not output created');
$this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
// by default it will be deleted instantly after it is read
@@ -741,7 +742,7 @@ class ControllerTest extends TestCase
$this->assertEquals($paste['adata'][1], $response['adata'][1], 'outputs formatter correctly');
$this->assertEquals($paste['adata'][2], $response['adata'][2], 'outputs opendiscussion correctly');
$this->assertEquals($paste['adata'][3], $response['adata'][3], 'outputs burnafterreading correctly');
- $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs created correctly');
+ $this->assertFalse(array_key_exists('created', $response['meta']), 'does not output created');
$this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
}
@@ -771,7 +772,7 @@ class ControllerTest extends TestCase
$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->assertEquals($paste['meta']['postdate'], $response['meta']['postdate'], 'outputs postdate 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');
diff --git a/tst/Data/DatabaseTest.php b/tst/Data/DatabaseTest.php
index 1c5b79de..c903e715 100644
--- a/tst/Data/DatabaseTest.php
+++ b/tst/Data/DatabaseTest.php
@@ -259,12 +259,11 @@ class DatabaseTest extends TestCase
$this->_options['pwd'],
$this->_options['opt']
);
- $statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?,?)');
+ $statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$paste['data'],
- $paste['meta']['postdate'],
$paste['meta']['expire_date'],
0,
0,
@@ -292,7 +291,7 @@ class DatabaseTest extends TestCase
$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']['salt']);
+ unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['postdate'], $paste['meta']['salt']);
$model->delete(Helper::getPasteId());
$db = new PDO(
@@ -301,12 +300,11 @@ class DatabaseTest extends TestCase
$this->_options['pwd'],
$this->_options['opt']
);
- $statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?,?)');
+ $statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$paste['data'],
- $paste['meta']['postdate'],
$paste['meta']['expire_date'],
0,
0,
diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php
index 032ff4d7..6de7f7bd 100644
--- a/tst/JsonApiTest.php
+++ b/tst/JsonApiTest.php
@@ -180,7 +180,7 @@ class JsonApiTest extends TestCase
$this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
$this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
$this->assertEquals($paste['ct'], $response['ct'], 'outputs data correctly');
- $this->assertEquals($paste['meta']['created'], $response['meta']['created'], 'outputs postdate correctly');
+ $this->assertFalse(array_key_exists('created', $paste['meta']), 'does not output created');
$this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
}
diff --git a/tst/ModelTest.php b/tst/ModelTest.php
index 03855405..16f3fa6e 100644
--- a/tst/ModelTest.php
+++ b/tst/ModelTest.php
@@ -134,12 +134,11 @@ class ModelTest extends TestCase
$options['model_options']['pwd'],
$options['model_options']['opt']
);
- $statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?,?)');
+ $statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?)');
$statement->execute(
array(
Helper::getPasteId(),
$pasteData['data'],
- $pasteData['meta']['postdate'],
0,
0,
0,
@@ -452,12 +451,13 @@ class ModelTest extends TestCase
public function testCommentWithDisabledVizhash()
{
- $options = parse_ini_file(CONF, true);
- $options['main']['icon'] = 'none';
- $options['model'] = array(
+ $options = parse_ini_file(CONF, true);
+ $options['main']['discussiondatedisplay'] = 'false';
+ $options['main']['icon'] = 'none';
+ $options['model'] = array(
'class' => 'Database',
);
- $options['model_options'] = array(
+ $options['model_options'] = array(
'dsn' => 'sqlite::memory:',
'usr' => null,
'pwd' => null,
@@ -494,6 +494,10 @@ class ModelTest extends TestCase
$comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']);
$this->assertFalse(array_key_exists('icon', $comment['meta']), 'icon was not generated');
+ $this->assertTrue(array_key_exists('created', $comment['meta']), 'creation is set, when using default configuration');
+
+ $comment = current($paste->get()['comments']);
+ $this->assertFalse(array_key_exists('created', $comment['meta']), 'creation is not set, if using disabled configuration');
}
public function testCommentVizhash()