fix(api): remove author email addresses from comments and activity
getComment, getAllComments, getProjectActivity, getProjectActivities and getMyActivityStream returned the email address of the comment or event author to any project member. Comment events also carry it in their stored comment data. The models keep the column since the web UI needs it for avatars, the procedures drop it before answering. Fixes #5876
This commit is contained in:
1 parent
94a9f89416
commit
43d1e8b58c
6 files changed
+122
-5
No files matched your search
@@ -42,6 +42,36 @@ abstract class BaseProcedure extends Base
|
||||
return is_array($users) ? array_map(array($this, 'filterUser'), $users) : $users;
|
||||
}
|
||||
|
||||
protected function filterComment($comment)
|
||||
{
|
||||
if (is_array($comment)) {
|
||||
unset($comment['email']);
|
||||
}
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
protected function filterComments($comments)
|
||||
{
|
||||
return is_array($comments) ? array_map(array($this, 'filterComment'), $comments) : $comments;
|
||||
}
|
||||
|
||||
protected function filterEvent(array $event)
|
||||
{
|
||||
unset($event['email']);
|
||||
|
||||
if (isset($event['comment'])) {
|
||||
$event['comment'] = $this->filterComment($event['comment']);
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
protected function filterEvents(array $events)
|
||||
{
|
||||
return array_map(array($this, 'filterEvent'), $events);
|
||||
}
|
||||
|
||||
protected function getClassName()
|
||||
{
|
||||
$reflection = new ReflectionClass(get_called_class());
|
||||
|
||||
@@ -17,7 +17,7 @@ class CommentProcedure extends BaseProcedure
|
||||
public function getComment($comment_id)
|
||||
{
|
||||
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'getComment', $comment_id);
|
||||
return $this->commentModel->getById($comment_id);
|
||||
return $this->filterComment($this->commentModel->getById($comment_id));
|
||||
}
|
||||
|
||||
public function getAllComments($task_id)
|
||||
@@ -39,7 +39,7 @@ class CommentProcedure extends BaseProcedure
|
||||
$filteredComments[] = $comment;
|
||||
}
|
||||
|
||||
return $filteredComments;
|
||||
return $this->filterComments($filteredComments);
|
||||
}
|
||||
|
||||
public function removeComment($comment_id)
|
||||
|
||||
@@ -28,7 +28,7 @@ class MeProcedure extends BaseProcedure
|
||||
public function getMyActivityStream()
|
||||
{
|
||||
$project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId());
|
||||
return $this->helper->projectActivity->getProjectsEvents($project_ids, 100);
|
||||
return $this->filterEvents($this->helper->projectActivity->getProjectsEvents($project_ids, 100));
|
||||
}
|
||||
|
||||
public function createMyPrivateProject($name, $description = null)
|
||||
|
||||
@@ -97,13 +97,13 @@ class ProjectProcedure extends BaseProcedure
|
||||
->check($this->getClassName(), 'getProjectActivities', $project_id);
|
||||
}
|
||||
|
||||
return $this->helper->projectActivity->getProjectsEvents($project_ids);
|
||||
return $this->filterEvents($this->helper->projectActivity->getProjectsEvents($project_ids));
|
||||
}
|
||||
|
||||
public function getProjectActivity($project_id)
|
||||
{
|
||||
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectActivity', $project_id);
|
||||
return $this->helper->projectActivity->getProjectEvents($project_id);
|
||||
return $this->filterEvents($this->helper->projectActivity->getProjectEvents($project_id));
|
||||
}
|
||||
|
||||
public function createProject($name, $description = null, $owner_id = 0, $identifier = null, $start_date = null, $end_date = null, $priority_default = null, $priority_start = null, $priority_end = null, $email = null)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace KanboardTests\units\Api\Procedure;
|
||||
|
||||
use Kanboard\Api\Procedure\CommentProcedure;
|
||||
use Kanboard\Core\Security\Role;
|
||||
use KanboardTests\units\Base;
|
||||
|
||||
class CommentProcedureTest extends Base
|
||||
{
|
||||
public function testCommentsDoNotExposeTheAuthorEmail()
|
||||
{
|
||||
$this->assertEquals(2, $this->container['userModel']->create(array('username' => 'owner', 'email' => 'owner@example.org')));
|
||||
$this->assertEquals(3, $this->container['userModel']->create(array('username' => 'peer')));
|
||||
$this->assertEquals(1, $this->container['projectModel']->create(array('name' => 'P1')));
|
||||
$this->assertTrue($this->container['projectUserRoleModel']->addUser(1, 2, Role::PROJECT_MANAGER));
|
||||
$this->assertTrue($this->container['projectUserRoleModel']->addUser(1, 3, Role::PROJECT_MEMBER));
|
||||
$this->assertEquals(1, $this->container['taskCreationModel']->create(array('title' => 'Task', 'project_id' => 1)));
|
||||
$this->assertEquals(1, $this->container['commentModel']->create(array('task_id' => 1, 'user_id' => 2, 'comment' => 'hello')));
|
||||
|
||||
$this->container['userSession']->initialize($this->container['userModel']->getById(3));
|
||||
$procedure = new CommentProcedure($this->container);
|
||||
|
||||
$comment = $procedure->getComment(1);
|
||||
$this->assertEquals('owner', $comment['username']);
|
||||
$this->assertArrayNotHasKey('email', $comment);
|
||||
|
||||
$comments = $procedure->getAllComments(1);
|
||||
$this->assertCount(1, $comments);
|
||||
$this->assertEquals('owner', $comments[0]['username']);
|
||||
$this->assertArrayNotHasKey('email', $comments[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace KanboardTests\units\Api\Procedure;
|
||||
|
||||
use Kanboard\Api\Procedure\MeProcedure;
|
||||
use Kanboard\Api\Procedure\ProjectProcedure;
|
||||
use Kanboard\Core\Security\Role;
|
||||
use Kanboard\EventBuilder\CommentEventBuilder;
|
||||
use Kanboard\Model\CommentModel;
|
||||
use KanboardTests\units\Base;
|
||||
|
||||
class ProjectActivityProcedureTest extends Base
|
||||
{
|
||||
public function testProjectActivityDoesNotExposeTheAuthorEmail()
|
||||
{
|
||||
$this->createCommentEvent();
|
||||
$procedure = new ProjectProcedure($this->container);
|
||||
|
||||
$this->assertEventsWithoutEmail($procedure->getProjectActivity(1));
|
||||
$this->assertEventsWithoutEmail($procedure->getProjectActivities(array(1)));
|
||||
}
|
||||
|
||||
public function testMyActivityStreamDoesNotExposeTheAuthorEmail()
|
||||
{
|
||||
$this->createCommentEvent();
|
||||
$procedure = new MeProcedure($this->container);
|
||||
|
||||
$this->assertEventsWithoutEmail($procedure->getMyActivityStream());
|
||||
}
|
||||
|
||||
private function assertEventsWithoutEmail(array $events)
|
||||
{
|
||||
$this->assertCount(1, $events);
|
||||
$this->assertEquals('owner', $events[0]['author_username']);
|
||||
$this->assertEquals('hello', $events[0]['comment']['comment']);
|
||||
$this->assertStringNotContainsString('owner@example.org', json_encode($events));
|
||||
}
|
||||
|
||||
private function createCommentEvent()
|
||||
{
|
||||
$this->assertEquals(2, $this->container['userModel']->create(array('username' => 'owner', 'email' => 'owner@example.org')));
|
||||
$this->assertEquals(3, $this->container['userModel']->create(array('username' => 'peer')));
|
||||
$this->assertEquals(1, $this->container['projectModel']->create(array('name' => 'P1')));
|
||||
$this->assertTrue($this->container['projectUserRoleModel']->addUser(1, 2, Role::PROJECT_MANAGER));
|
||||
$this->assertTrue($this->container['projectUserRoleModel']->addUser(1, 3, Role::PROJECT_MEMBER));
|
||||
$this->assertEquals(1, $this->container['taskCreationModel']->create(array('title' => 'Task', 'project_id' => 1)));
|
||||
$this->assertEquals(1, $this->container['commentModel']->create(array('task_id' => 1, 'user_id' => 2, 'comment' => 'hello')));
|
||||
|
||||
$event = (new CommentEventBuilder($this->container))->withCommentId(1)->buildEvent();
|
||||
$this->assertNotFalse($this->container['projectActivityModel']->createEvent(1, 1, 2, CommentModel::EVENT_CREATE, $event->getAll()));
|
||||
|
||||
$this->container['userSession']->initialize($this->container['userModel']->getById(3));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user