burn after reading messages are only deleted after callback by JS when

successfully decrypted, resolves #11
This commit is contained in:
El RIDO 2015-08-31 22:10:41 +02:00
parent 9fdbba76ce
commit 802a0b26b9
3 changed files with 94 additions and 22 deletions

View File

@ -238,6 +238,10 @@ function displayMessages(key, comments) {
// Display paste expiration. // Display paste expiration.
if (comments[0].meta.expire_date) $('#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').removeClass('hidden'); if (comments[0].meta.expire_date) $('#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').removeClass('hidden');
if (comments[0].meta.burnafterreading) { if (comments[0].meta.burnafterreading) {
$.get(scriptLocation() + "?pasteid=" + pasteID() + '&deletetoken=burnafterreading', 'json')
.fail(function() {
showError('Could not delete the paste, it was not stored in burn after reading mode.');
});
$('#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').removeClass('hidden'); $('#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').removeClass('hidden');
$('#clonebutton').addClass('hidden'); // Discourage cloning (as it can't really be prevented). $('#clonebutton').addClass('hidden'); // Discourage cloning (as it can't really be prevented).
} }
@ -382,11 +386,7 @@ function send_data() {
burnafterreading: $('#burnafterreading').is(':checked') ? 1 : 0, burnafterreading: $('#burnafterreading').is(':checked') ? 1 : 0,
opendiscussion: $('#opendiscussion').is(':checked') ? 1 : 0 opendiscussion: $('#opendiscussion').is(':checked') ? 1 : 0
}; };
$.post(scriptLocation(), data_to_send, 'json') $.post(scriptLocation(), data_to_send, function(data) {
.error(function() {
showError('Data could not be sent (serveur error or not responding).');
})
.success(function(data) {
if (data.status == 0) { if (data.status == 0) {
stateExistingPaste(); stateExistingPaste();
var url = scriptLocation() + "?" + data.id + '#' + randomkey; var url = scriptLocation() + "?" + data.id + '#' + randomkey;
@ -412,6 +412,9 @@ function send_data() {
else { else {
showError('Could not create paste.'); showError('Could not create paste.');
} }
}, 'json')
.fail(function() {
showError('Data could not be sent (server error or not responding).');
}); });
} }

View File

@ -24,6 +24,13 @@ class zerobin
*/ */
const VERSION = 'Alpha 0.19'; const VERSION = 'Alpha 0.19';
/**
* show the same error message if the paste expired or does not exist
*
* @const string
*/
const GENERIC_ERROR = 'Paste does not exist, has expired or has been deleted.';
/** /**
* configuration array * configuration array
* *
@ -99,7 +106,11 @@ class zerobin
// delete an existing paste // delete an existing paste
elseif (!empty($_GET['deletetoken']) && !empty($_GET['pasteid'])) elseif (!empty($_GET['deletetoken']) && !empty($_GET['pasteid']))
{ {
$this->_delete($_GET['pasteid'], $_GET['deletetoken']); $result = $this->_delete($_GET['pasteid'], $_GET['deletetoken']);
if (strlen($result)) {
echo $result;
return;
}
} }
// display an existing paste // display an existing paste
elseif (!empty($_SERVER['QUERY_STRING'])) elseif (!empty($_SERVER['QUERY_STRING']))
@ -355,7 +366,7 @@ class zerobin
* @access private * @access private
* @param string $dataid * @param string $dataid
* @param string $deletetoken * @param string $deletetoken
* @return void * @return string
*/ */
private function _delete($dataid, $deletetoken) private function _delete($dataid, $deletetoken)
{ {
@ -363,14 +374,42 @@ class zerobin
if (!filter::is_valid_paste_id($dataid)) if (!filter::is_valid_paste_id($dataid))
{ {
$this->_error = 'Invalid paste ID.'; $this->_error = 'Invalid paste ID.';
return; return '';
} }
// Check that paste exists. // Check that paste exists.
if (!$this->_model()->exists($dataid)) if (!$this->_model()->exists($dataid))
{ {
$this->_error = 'Paste does not exist, has expired or has been deleted.'; $this->_error = self::GENERIC_ERROR;
return; return '';
}
// Get the paste itself.
$paste = $this->_model()->read($dataid);
// See if paste has expired.
if (
isset($paste->meta->expire_date) &&
$paste->meta->expire_date < time()
)
{
// Delete the paste
$this->_model()->delete($dataid);
$this->_error = self::GENERIC_ERROR;
}
if ($deletetoken == 'burnafterreading') {
header('Content-type: application/json');
if (
isset($paste->meta->burnafterreading) &&
$paste->meta->burnafterreading
)
{
// Delete the paste
$this->_model()->delete($dataid);
return $this->_return_message(0, 'Paste was properly deleted.');
}
return $this->_return_message(1, 'Paste is not of burn-after-reading type.');
} }
// Make sure token is valid. // Make sure token is valid.
@ -378,12 +417,13 @@ class zerobin
if (!filter::slow_equals($deletetoken, hash_hmac('sha1', $dataid, serversalt::get()))) if (!filter::slow_equals($deletetoken, hash_hmac('sha1', $dataid, serversalt::get())))
{ {
$this->_error = 'Wrong deletion token. Paste was not deleted.'; $this->_error = 'Wrong deletion token. Paste was not deleted.';
return; return '';
} }
// Paste exists and deletion token is valid: Delete the paste. // Paste exists and deletion token is valid: Delete the paste.
$this->_model()->delete($dataid); $this->_model()->delete($dataid);
$this->_status = 'Paste was properly deleted.'; $this->_status = 'Paste was properly deleted.';
return '';
} }
/** /**
@ -402,9 +442,6 @@ class zerobin
return; return;
} }
// show the same error message if the paste expired or does not exist
$genericError = 'Paste does not exist, has expired or has been deleted.';
// Check that paste exists. // Check that paste exists.
if ($this->_model()->exists($dataid)) if ($this->_model()->exists($dataid))
{ {
@ -419,7 +456,7 @@ class zerobin
{ {
// Delete the paste // Delete the paste
$this->_model()->delete($dataid); $this->_model()->delete($dataid);
$this->_error = $genericError; $this->_error = self::GENERIC_ERROR;
} }
// If no error, return the paste. // If no error, return the paste.
else else
@ -444,17 +481,11 @@ class zerobin
); );
} }
$this->_data = json_encode($messages); $this->_data = json_encode($messages);
// If the paste was meant to be read only once, delete it.
if (
property_exists($paste->meta, 'burnafterreading') &&
$paste->meta->burnafterreading
) $this->_model()->delete($dataid);
} }
} }
else else
{ {
$this->_error = $genericError; $this->_error = self::GENERIC_ERROR;
} }
} }

View File

@ -527,4 +527,42 @@ class zerobinTest extends PHPUnit_Framework_TestCase
); );
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after failing to delete data'); $this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after failing to delete data');
} }
/**
* @runInSeparateProcess
*/
public function testDeleteBurnAfterReading()
{
$this->reset();
$burnPaste = self::$paste;
$burnPaste['meta']['burnafterreading'] = true;
$this->_model->create(self::$pasteid, $burnPaste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$_GET['deletetoken'] = 'burnafterreading';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
}
/**
* @runInSeparateProcess
*/
public function testDeleteInvalidBurnAfterReading()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$_GET['deletetoken'] = 'burnafterreading';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs status');
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste successfully deleted');
}
} }