1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-04-19 15:22:08 +02:00

Merge pull request #2021 from nickvergessen/ticket/12171

Ticket/12171 Attachments from soft-deleted posts are still downloadable
This commit is contained in:
Nathan Guse 2014-02-20 20:51:58 -06:00
commit b8d30bfc80
6 changed files with 455 additions and 35 deletions

View File

@ -144,7 +144,8 @@ require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);
$download_id = request_var('id', 0);
$topic_id = $request->variable('topic_id', 0);
$post_msg_id = $request->variable('post_msg_id', 0);
$post_id = $request->variable('post_id', 0);
$msg_id = $request->variable('msg_id', 0);
$archive = $request->variable('archive', '.tar');
$mode = request_var('mode', '');
$thumbnail = request_var('t', false);
@ -163,17 +164,22 @@ if (!$config['allow_attachments'] && !$config['allow_pm_attach'])
if ($download_id)
{
// Attachment id (only 1 attachment)
$sql_where = "attach_id = $download_id";
$sql_where = 'attach_id = ' . $download_id;
}
else if ($post_msg_id)
else if ($msg_id)
{
// Post id or private message id (multiple attachments)
$sql_where = "post_msg_id = $post_msg_id AND is_orphan = 0";
// Private message id (multiple attachments)
$sql_where = 'is_orphan = 0 AND in_message = 1 AND post_msg_id = ' . $msg_id;
}
else if ($post_id)
{
// Post id (multiple attachments)
$sql_where = 'is_orphan = 0 AND in_message = 0 AND post_msg_id = ' . $post_id;
}
else if ($topic_id)
{
// Topic id (multiple attachments)
$sql_where = "topic_id = $topic_id AND is_orphan = 0";
$sql_where = 'is_orphan = 0 AND topic_id = ' . $topic_id;
}
else
{
@ -240,6 +246,20 @@ else if ($download_id)
if (!$attachment['in_message'])
{
phpbb_download_handle_forum_auth($db, $auth, $attachment['topic_id']);
$sql = 'SELECT forum_id, post_visibility
FROM ' . POSTS_TABLE . '
WHERE post_id = ' . (int) $attachment['post_msg_id'];
$result = $db->sql_query($sql);
$post_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$post_row || ($post_row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $post_row['forum_id'])))
{
// Attachment of a soft deleted post and the user is not allowed to see the post
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
}
}
else
{
@ -251,7 +271,7 @@ else if ($download_id)
$extensions = array();
if (!extension_allowed($row['forum_id'], $attachment['extension'], $extensions))
{
send_status_line(404, 'Forbidden');
send_status_line(403, 'Forbidden');
trigger_error(sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension']));
}
}
@ -328,23 +348,32 @@ else
$archive = '.tar';
}
if ($post_msg_id)
$post_visibility = array();
if ($msg_id)
{
if ($attachment['in_message'])
{
$sql = 'SELECT message_subject AS attach_subject
FROM ' . PRIVMSGS_TABLE . "
WHERE msg_id = $post_msg_id";
}
else
{
$sql = 'SELECT post_subject AS attach_subject, forum_id
FROM ' . POSTS_TABLE . "
WHERE post_id = $post_msg_id";
}
$sql = 'SELECT message_subject AS attach_subject
FROM ' . PRIVMSGS_TABLE . "
WHERE msg_id = $msg_id";
}
else if ($post_id)
{
$sql = 'SELECT post_subject AS attach_subject, forum_id, post_visibility
FROM ' . POSTS_TABLE . "
WHERE post_id = $post_id";
}
else
{
$sql = 'SELECT post_id, post_visibility
FROM ' . POSTS_TABLE . "
WHERE topic_id = $topic_id
AND post_attachment = 1";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$post_visibility[(int) $row['post_id']] = (int) $row['post_visibility'];
}
$db->sql_freeresult($result);
$sql = 'SELECT topic_title AS attach_subject, forum_id
FROM ' . TOPICS_TABLE . "
WHERE topic_id = $topic_id";
@ -361,7 +390,7 @@ else
}
$clean_name = phpbb_download_clean_filename($row['attach_subject']);
$suffix = '_' . (($post_msg_id) ? $post_msg_id : $topic_id) . '_' . $clean_name;
$suffix = '_' . (($msg_id) ? 'm' . $msg_id : (($post_id) ? 'p' . $post_id : 't' . $topic_id)) . '_' . $clean_name;
$archive_name = 'attachments' . $suffix;
$store_name = 'att_' . time() . '_' . unique_id();
@ -379,13 +408,25 @@ else
$extensions = array();
$files_added = 0;
$forum_id = ($attachment['in_message']) ? false : (int) $row['forum_id'];
$disallowed = array();
$disallowed_extension = array();
foreach ($attachments as $attach)
{
if (!extension_allowed($forum_id, $attach['extension'], $extensions))
{
$disallowed[$attach['extension']] = $attach['extension'];
$disallowed_extension[$attach['extension']] = $attach['extension'];
continue;
}
if ($post_id && $row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $forum_id))
{
// Attachment of a soft deleted post and the user is not allowed to see the post
continue;
}
if ($topic_id && (!isset($post_visibility[$attach['post_msg_id']]) || $post_visibility[$attach['post_msg_id']] != ITEM_APPROVED) && !$auth->acl_get('m_approve', $forum_id))
{
// Attachment of a soft deleted post and the user is not allowed to see the post
continue;
}
@ -409,12 +450,17 @@ else
unlink($archive_path);
if (!$files_added)
if (!$files_added && !empty($disallowed_extension))
{
// None of the attachments had a valid extension
$disallowed = implode($user->lang['COMMA_SEPARATOR'], $disallowed);
send_status_line(404, 'Forbidden');
trigger_error($user->lang('EXTENSION_DISABLED_AFTER_POSTING', $disallowed));
$disallowed_extension = implode($user->lang['COMMA_SEPARATOR'], $disallowed_extension);
send_status_line(403, 'Forbidden');
trigger_error($user->lang('EXTENSION_DISABLED_AFTER_POSTING', $disallowed_extension));
}
else if (!$files_added)
{
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
}
file_gc();

View File

@ -625,17 +625,29 @@ function phpbb_increment_downloads($db, $ids)
*/
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
{
$sql = 'SELECT t.forum_id, f.forum_name, f.forum_password, f.parent_id
FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f
WHERE t.topic_id = " . (int) $topic_id . "
AND t.forum_id = f.forum_id";
$sql_array = array(
'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
'FROM' => array(
TOPICS_TABLE => 't',
FORUMS_TABLE => 'f',
),
'WHERE' => 't.topic_id = ' . (int) $topic_id . '
AND t.forum_id = f.forum_id',
);
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
if ($row && $row['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
{
if ($row && $row['forum_password'])
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
}
else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
{
if ($row['forum_password'])
{
// Do something else ... ?
login_forum_box($row);

View File

@ -274,7 +274,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
// Display not already displayed Attachments for this post, we already parsed them. ;)
if (isset($attachments) && sizeof($attachments))
{
$methods = phpbb_gen_download_links('post_msg_id', $msg_id, $phpbb_root_path, $phpEx);
$methods = phpbb_gen_download_links('msg_id', $msg_id, $phpbb_root_path, $phpEx);
foreach ($methods as $method)
{
$template->assign_block_vars('dl_method', $method);

View File

@ -1736,7 +1736,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
);
}
$methods = phpbb_gen_download_links('post_msg_id', $row['post_id'], $phpbb_root_path, $phpEx);
$methods = phpbb_gen_download_links('post_id', $row['post_id'], $phpbb_root_path, $phpEx);
foreach ($methods as $method)
{
$template->assign_block_vars('postrow.dl_method', $method);

View File

@ -0,0 +1,345 @@
<?php
/**
*
* @package testing
* @copyright (c) 2014 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
/**
* @group functional
*/
class phpbb_functional_download_test extends phpbb_functional_test_case
{
protected $data = array();
public function test_setup_forums()
{
$this->login();
$this->admin_login();
$crawler = self::request('GET', "adm/index.php?i=acp_forums&mode=manage&sid={$this->sid}");
$form = $crawler->selectButton('addforum')->form(array(
'forum_name' => 'Download #1',
));
$crawler = self::submit($form);
$form = $crawler->selectButton('update')->form(array(
'forum_perm_from' => 2,
));
$crawler = self::submit($form);
}
public function test_create_post()
{
$this->login();
$this->load_ids(array(
'forums' => array(
'Download #1',
),
));
// Test creating topic
$post = $this->create_topic($this->data['forums']['Download #1'], 'Download Topic #1', 'This is a test topic posted by the testing framework.', array('upload_files' => 1));
$crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
$this->assertContains('Download Topic #1', $crawler->filter('html')->text());
$this->data['topics']['Download Topic #1'] = (int) $post['topic_id'];
$this->data['posts']['Download Topic #1'] = (int) $this->get_parameter_from_link($crawler->filter('.post')->selectLink($this->lang('POST', '', ''))->link()->getUri(), 'p');
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Download #1'], $post['topic_id'], 'Re: Download Topic #1-#2', 'This is a test post posted by the testing framework.', array('upload_files' => 1));
$crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
$this->assertContains('Re: Download Topic #1-#2', $crawler->filter('html')->text());
$this->data['posts']['Re: Download Topic #1-#2'] = (int) $this->get_parameter_from_link($crawler->filter('.post')->eq(1)->selectLink($this->lang('POST', '', ''))->link()->getUri(), 'p');
}
public function test_download_accessible()
{
$this->load_ids(array(
'forums' => array(
'Download #1',
),
'topics' => array(
'Download Topic #1',
),
'posts' => array(
'Download Topic #1',
'Re: Download Topic #1-#2',
),
'attachments' => true,
));
// Download topic archive as guest
$crawler = self::request('GET', "download/file.php?archive=.zip&topic_id={$this->data['topics']['Download Topic #1']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download post archive as guest
$crawler = self::request('GET', "download/file.php?archive=.zip&post_id={$this->data['posts']['Re: Download Topic #1-#2']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download attachment as guest
$crawler = self::request('GET', "download/file.php?id={$this->data['attachments'][$this->data['posts']['Re: Download Topic #1-#2']]}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('image/jpeg', $finfo->buffer($content));
}
public function test_softdelete_post()
{
$this->login();
$this->load_ids(array(
'forums' => array(
'Download #1',
),
'topics' => array(
'Download Topic #1',
),
'posts' => array(
'Download Topic #1',
'Re: Download Topic #1-#2',
),
));
$this->add_lang('posting');
$crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Download #1']}&p={$this->data['posts']['Re: Download Topic #1-#2']}&sid={$this->sid}");
$this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
$form = $crawler->selectButton('Yes')->form();
$crawler = self::submit($form);
$this->assertContainsLang('POST_DELETED', $crawler->text());
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Download Topic #1']}&sid={$this->sid}");
$this->assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text());
}
public function test_download_softdeleted_post()
{
$this->load_ids(array(
'forums' => array(
'Download #1',
),
'topics' => array(
'Download Topic #1',
),
'posts' => array(
'Download Topic #1',
'Re: Download Topic #1-#2',
),
'attachments' => true,
));
$this->add_lang('viewtopic');
// Download topic archive as guest: still works
$crawler = self::request('GET', "download/file.php?archive=.zip&topic_id={$this->data['topics']['Download Topic #1']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// No download post archive as guest
$crawler = self::request('GET', "download/file.php?archive=.zip&post_id={$this->data['posts']['Re: Download Topic #1-#2']}", array(), false);
self::assert_response_html(404);
$this->assertContainsLang('ERROR_NO_ATTACHMENT', $crawler->filter('#message')->text());
// No download attachment as guest
$crawler = self::request('GET', "download/file.php?id={$this->data['attachments'][$this->data['posts']['Re: Download Topic #1-#2']]}", array(), false);
self::assert_response_html(404);
$this->assertContainsLang('ERROR_NO_ATTACHMENT', $crawler->filter('#message')->text());
// Login as admin and try again, should work now.
$this->login();
// Download topic archive as admin
$crawler = self::request('GET', "download/file.php?archive=.zip&topic_id={$this->data['topics']['Download Topic #1']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download post archive as admin
$crawler = self::request('GET', "download/file.php?archive=.zip&post_id={$this->data['posts']['Re: Download Topic #1-#2']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download attachment as admin
$crawler = self::request('GET', "download/file.php?id={$this->data['attachments'][$this->data['posts']['Re: Download Topic #1-#2']]}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('image/jpeg', $finfo->buffer($content));
}
public function test_softdelete_topic()
{
$this->login();
$this->load_ids(array(
'forums' => array(
'Download #1',
),
'topics' => array(
'Download Topic #1',
),
'posts' => array(
'Download Topic #1',
'Re: Download Topic #1-#2',
),
));
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Download Topic #1']}&sid={$this->sid}");
$this->add_lang('posting');
$form = $crawler->selectButton('Go')->eq(2)->form();
$form['action']->select('delete_topic');
$crawler = self::submit($form);
$this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
$this->add_lang('mcp');
$form = $crawler->selectButton('Yes')->form();
$crawler = self::submit($form);
$this->assertContainsLang('TOPIC_DELETED_SUCCESS', $crawler->text());
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Download Topic #1']}&sid={$this->sid}");
$this->assertContains('Download Topic #1', $crawler->filter('h2')->text());
}
public function test_download_softdeleted_topic()
{
$this->load_ids(array(
'forums' => array(
'Download #1',
),
'topics' => array(
'Download Topic #1',
),
'posts' => array(
'Download Topic #1',
'Re: Download Topic #1-#2',
),
'attachments' => true,
));
$this->add_lang('viewtopic');
// Download topic archive as guest: still works
$crawler = self::request('GET', "download/file.php?archive=.zip&topic_id={$this->data['topics']['Download Topic #1']}", array(), false);
self::assert_response_html(404);
$this->assertContainsLang('ERROR_NO_ATTACHMENT', $crawler->filter('#message')->text());
// No download post archive as guest
$crawler = self::request('GET', "download/file.php?archive=.zip&post_id={$this->data['posts']['Re: Download Topic #1-#2']}", array(), false);
self::assert_response_html(404);
$this->assertContainsLang('ERROR_NO_ATTACHMENT', $crawler->filter('#message')->text());
// No download attachment as guest
$crawler = self::request('GET', "download/file.php?id={$this->data['attachments'][$this->data['posts']['Re: Download Topic #1-#2']]}", array(), false);
self::assert_response_html(404);
$this->assertContainsLang('ERROR_NO_ATTACHMENT', $crawler->filter('#message')->text());
// Login as admin and try again, should work now.
$this->login();
// Download topic archive as admin
$crawler = self::request('GET', "download/file.php?archive=.zip&topic_id={$this->data['topics']['Download Topic #1']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download post archive as admin
$crawler = self::request('GET', "download/file.php?archive=.zip&post_id={$this->data['posts']['Re: Download Topic #1-#2']}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('application/zip', $finfo->buffer($content));
// Download attachment as admin
$crawler = self::request('GET', "download/file.php?id={$this->data['attachments'][$this->data['posts']['Re: Download Topic #1-#2']]}", array(), false);
self::assert_response_status_code(200);
$content = self::$client->getResponse()->getContent();
$finfo = new finfo(FILEINFO_MIME_TYPE);
self::assertEquals('image/jpeg', $finfo->buffer($content));
}
public function load_ids($data)
{
$this->db = $this->get_db();
if (!empty($data['forums']))
{
$sql = 'SELECT *
FROM phpbb_forums
WHERE ' . $this->db->sql_in_set('forum_name', $data['forums']);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
if (in_array($row['forum_name'], $data['forums']))
{
$this->data['forums'][$row['forum_name']] = (int) $row['forum_id'];
}
}
$this->db->sql_freeresult($result);
}
if (!empty($data['topics']))
{
$sql = 'SELECT *
FROM phpbb_topics
WHERE ' . $this->db->sql_in_set('topic_title', $data['topics']);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
if (in_array($row['topic_title'], $data['topics']))
{
$this->data['topics'][$row['topic_title']] = (int) $row['topic_id'];
}
}
$this->db->sql_freeresult($result);
}
$post_ids = array();
if (!empty($data['posts']))
{
$sql = 'SELECT *
FROM phpbb_posts
WHERE ' . $this->db->sql_in_set('post_subject', $data['posts']);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
if (in_array($row['post_subject'], $data['posts']))
{
$this->data['posts'][$row['post_subject']] = (int) $row['post_id'];
$post_ids[] = (int) $row['post_id'];
}
}
$this->db->sql_freeresult($result);
if (isset($data['attachments']))
{
$sql = 'SELECT *
FROM phpbb_attachments
WHERE in_message = 0 AND ' . $this->db->sql_in_set('post_msg_id', $post_ids);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$this->data['attachments'][(int) $row['post_msg_id']] = (int) $row['attach_id'];
}
$this->db->sql_freeresult($result);
}
}
}
}

View File

@ -928,6 +928,23 @@ class phpbb_functional_test_case extends phpbb_test_case
$crawler = self::request('GET', $posting_url);
$this->assertContains($this->lang($posting_contains), $crawler->filter('html')->text());
if (!empty($form_data['upload_files']))
{
for ($i = 0; $i < $form_data['upload_files']; $i++)
{
$file = array(
'tmp_name' => __DIR__ . '/../functional/fixtures/files/valid.jpg',
'name' => 'valid.jpg',
'type' => 'image/jpeg',
'size' => filesize(__DIR__ . '/../functional/fixtures/files/valid.jpg'),
'error' => UPLOAD_ERR_OK,
);
$crawler = self::$client->request('POST', $posting_url, array('add_file' => $this->lang('ADD_FILE')), array('fileupload' => $file));
}
unset($form_data['upload_files']);
}
$hidden_fields = array(
$crawler->filter('[type="hidden"]')->each(function ($node, $i) {
return array('name' => $node->attr('name'), 'value' => $node->attr('value'));