From aa7be4172819ebc368351849b3f11995ffa78c8b Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Fri, 1 Nov 2019 14:13:29 +0100 Subject: [PATCH 1/3] Fix ACLFormatterTest - Add nullable to expand() function again - Add angle bracket support to toString() --- mod/lockview.php | 8 ++++---- src/Model/Item.php | 8 ++++---- src/Module/Item/Compose.php | 8 ++++---- src/Util/ACLFormatter.php | 19 +++++++++++++++---- src/Worker/Notifier.php | 8 ++++---- tests/src/Util/ACLFormaterTest.php | 24 ++++++++++++++++++++---- 6 files changed, 51 insertions(+), 24 deletions(-) diff --git a/mod/lockview.php b/mod/lockview.php index af57730c8..9f9dcfea4 100644 --- a/mod/lockview.php +++ b/mod/lockview.php @@ -64,10 +64,10 @@ function lockview_content(App $a) /** @var ACLFormatter $aclFormatter */ $aclFormatter = BaseObject::getClass(ACLFormatter::class); - $allowed_users = $aclFormatter->expand($item['allow_cid'] ?? ''); - $allowed_groups = $aclFormatter->expand($item['allow_gid'] ?? ''); - $deny_users = $aclFormatter->expand($item['deny_cid'] ?? ''); - $deny_groups = $aclFormatter->expand($item['deny_gid'] ?? ''); + $allowed_users = $aclFormatter->expand($item['allow_cid']); + $allowed_groups = $aclFormatter->expand($item['allow_gid']); + $deny_users = $aclFormatter->expand($item['deny_cid']); + $deny_groups = $aclFormatter->expand($item['deny_gid']); $o = L10n::t('Visible to:') . '
'; $l = []; diff --git a/src/Model/Item.php b/src/Model/Item.php index e298cc160..9501c8e5d 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2904,10 +2904,10 @@ class Item extends BaseObject /** @var ACLFormatter $aclFormater */ $aclFormater = self::getClass(ACLFormatter::class); - $allow_people = $aclFormater->expand($obj['allow_cid'] ?? ''); - $allow_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['allow_gid'] ?? ''), $check_dead); - $deny_people = $aclFormater->expand($obj['deny_cid'] ?? ''); - $deny_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['deny_gid'] ?? ''), $check_dead); + $allow_people = $aclFormater->expand($obj['allow_cid']); + $allow_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['allow_gid']), $check_dead); + $deny_people = $aclFormater->expand($obj['deny_cid']); + $deny_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['deny_gid']), $check_dead); $recipients = array_unique(array_merge($allow_people, $allow_groups)); $deny = array_unique(array_merge($deny_people, $deny_groups)); $recipients = array_diff($recipients, $deny); diff --git a/src/Module/Item/Compose.php b/src/Module/Item/Compose.php index 0d3b4eaac..c44e4c61a 100644 --- a/src/Module/Item/Compose.php +++ b/src/Module/Item/Compose.php @@ -74,8 +74,8 @@ class Compose extends BaseModule $compose_title = L10n::t('Compose new post'); $type = 'post'; $doesFederate = true; - $contact_allow = implode(',', $aclFormatter->expand($user['allow_cid'] ?? '')); - $group_allow = implode(',', $aclFormatter->expand($user['allow_gid'] ?? '')) ?: Group::FOLLOWERS; + $contact_allow = implode(',', $aclFormatter->expand($user['allow_cid'])); + $group_allow = implode(',', $aclFormatter->expand($user['allow_gid'])) ?: Group::FOLLOWERS; break; } @@ -86,8 +86,8 @@ class Compose extends BaseModule $wall = $_REQUEST['wall'] ?? $type == 'post'; $contact_allow = $_REQUEST['contact_allow'] ?? $contact_allow; $group_allow = $_REQUEST['group_allow'] ?? $group_allow; - $contact_deny = $_REQUEST['contact_deny'] ?? implode(',', $aclFormatter->expand($user['deny_cid'] ?? '')); - $group_deny = $_REQUEST['group_deny'] ?? implode(',', $aclFormatter->expand($user['deny_gid'] ?? '')); + $contact_deny = $_REQUEST['contact_deny'] ?? implode(',', $aclFormatter->expand($user['deny_cid'])); + $group_deny = $_REQUEST['group_deny'] ?? implode(',', $aclFormatter->expand($user['deny_gid'])); $visibility = ($contact_allow . $user['allow_gid'] . $user['deny_cid'] . $user['deny_gid']) ? 'custom' : 'public'; $acl_contacts = Contact::selectToArray(['id', 'name', 'addr', 'micro'], ['uid' => local_user(), 'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]); diff --git a/src/Util/ACLFormatter.php b/src/Util/ACLFormatter.php index 4a36f3ebf..d194e2e67 100644 --- a/src/Util/ACLFormatter.php +++ b/src/Util/ACLFormatter.php @@ -12,12 +12,17 @@ final class ACLFormatter /** * Turn user/group ACLs stored as angle bracketed text into arrays * - * @param string $ids A angle-bracketed list of IDs + * @param string|null $ids A angle-bracketed list of IDs * - * @return array The array based on the IDs + * @return array|null The array based on the IDs (null in case there is no list) */ - public function expand(string $ids) + public function expand(string $ids = null) { + // In case there is no ID list, return null (=> no ACL set) + if (!isset($ids)) { + return null; + } + // turn string array of angle-bracketed elements into numeric array // e.g. "<1><2><3>" => array(1,2,3); preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $ids, $matches, PREG_PATTERN_ORDER); @@ -31,12 +36,18 @@ final class ACLFormatter * @param string $item The item to sanitise */ private function sanitize(string &$item) { + // The item is an ACL int value if (intval($item)) { $item = '<' . intval(Strings::escapeTags(trim($item))) . '>'; + // The item is a allowed ACL character } elseif (in_array($item, [Group::FOLLOWERS, Group::MUTUALS])) { $item = '<' . $item . '>'; - } else { + // The item is already a ACL string + } elseif (preg_match('/<\d+?>/', $item)) { unset($item); + // The item is not supported, so remove it (cleanup) + } else { + $item = ''; } } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 9ab07e6d4..8b6be76b5 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -279,10 +279,10 @@ class Notifier /** @var ACLFormatter $aclFormatter */ $aclFormatter = BaseObject::getClass(ACLFormatter::class); - $allow_people = $aclFormatter->expand($parent['allow_cid'] ?? ''); - $allow_groups = Group::expand($uid, $aclFormatter->expand($parent['allow_gid'] ?? ''),true); - $deny_people = $aclFormatter->expand($parent['deny_cid'] ?? ''); - $deny_groups = Group::expand($uid, $aclFormatter->expand($parent['deny_gid'] ?? '')); + $allow_people = $aclFormatter->expand($parent['allow_cid']); + $allow_groups = Group::expand($uid, $aclFormatter->expand($parent['allow_gid']),true); + $deny_people = $aclFormatter->expand($parent['deny_cid']); + $deny_groups = Group::expand($uid, $aclFormatter->expand($parent['deny_gid'])); // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing // a delivery fork. private groups (forum_mode == 2) do not uplink diff --git a/tests/src/Util/ACLFormaterTest.php b/tests/src/Util/ACLFormaterTest.php index ac5b25e6c..630a30e40 100644 --- a/tests/src/Util/ACLFormaterTest.php +++ b/tests/src/Util/ACLFormaterTest.php @@ -164,15 +164,14 @@ class ACLFormaterTest extends TestCase } /** - * Test expected exception in case of wrong typehint - * - * @expectedException Error + * Test nullable expand (=> no ACL set) */ public function testExpandNull() { $aclFormatter = new ACLFormatter(); - $aclFormatter->expand(null); + $this->assertNull($aclFormatter->expand(null)); + $this->assertNull($aclFormatter->expand()); } public function dataAclToString() @@ -198,6 +197,23 @@ class ACLFormaterTest extends TestCase 'input' => 'a,bsd23,4', 'assert' => '<4>', ], + /** @see https://github.com/friendica/friendica/pull/7787 */ + 'bug-7778-angle-brackets' => [ + 'input' => ["<40195>"], + 'assert' => "<40195>", + ], + Group::FOLLOWERS => [ + 'input' => [Group::FOLLOWERS, 1], + 'assert' => '<' . Group::FOLLOWERS . '><1>', + ], + Group::MUTUALS => [ + 'input' => [Group::MUTUALS, 1], + 'assert' => '<' . Group::MUTUALS . '><1>', + ], + 'wrong-angle-brackets' => [ + 'input' => ["","<123>"], + 'assert' => "<123>", + ], ]; } From f4ad82bcfb29e3015bf4903311f35e13bd8f73ed Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Fri, 1 Nov 2019 15:43:16 +0100 Subject: [PATCH 2/3] make ACLFormatter::expand() nullable and return an empty array - optimize tests --- src/Util/ACLFormatter.php | 6 +- tests/src/Util/ACLFormaterTest.php | 233 +++++++++++------------------ 2 files changed, 93 insertions(+), 146 deletions(-) diff --git a/src/Util/ACLFormatter.php b/src/Util/ACLFormatter.php index d194e2e67..a7d851508 100644 --- a/src/Util/ACLFormatter.php +++ b/src/Util/ACLFormatter.php @@ -14,13 +14,13 @@ final class ACLFormatter * * @param string|null $ids A angle-bracketed list of IDs * - * @return array|null The array based on the IDs (null in case there is no list) + * @return array The array based on the IDs (empty in case there is no list) */ public function expand(string $ids = null) { - // In case there is no ID list, return null (=> no ACL set) + // In case there is no ID list, return empty array (=> no ACL set) if (!isset($ids)) { - return null; + return []; } // turn string array of angle-bracketed elements into numeric array diff --git a/tests/src/Util/ACLFormaterTest.php b/tests/src/Util/ACLFormaterTest.php index 630a30e40..ae875856a 100644 --- a/tests/src/Util/ACLFormaterTest.php +++ b/tests/src/Util/ACLFormaterTest.php @@ -12,155 +12,96 @@ use PHPUnit\Framework\TestCase; */ class ACLFormaterTest extends TestCase { - /** - * test expand_acl, perfect input - */ - public function testExpandAclNormal() + public function assertAcl($text, array $assert = []) { $aclFormatter = new ACLFormatter(); - $text='<1><2><3><' . Group::FOLLOWERS . '><' . Group::MUTUALS . '>'; - $this->assertEquals(array('1', '2', '3', Group::FOLLOWERS, Group::MUTUALS), $aclFormatter->expand($text)); + $acl = $aclFormatter->expand($text); + + $this->assertEquals($assert, $acl); + + $this->assertMergable($acl); + } + + public function assertMergable(array $aclOne, array $aclTwo = []) + { + $this->assertTrue(is_array($aclOne)); + $this->assertTrue(is_array($aclTwo)); + + $aclMerged = array_unique(array_merge($aclOne, $aclTwo)); + $this->assertTrue(is_array($aclMerged)); + + return $aclMerged; + } + + public function dataExpand() + { + return [ + 'normal' => [ + 'input' => '<1><2><3><' . Group::FOLLOWERS . '><' . Group::MUTUALS . '>', + 'assert' => ['1', '2', '3', Group::FOLLOWERS, Group::MUTUALS], + ], + 'nigNumber' => [ + 'input' => '<1><' . PHP_INT_MAX . '><15>', + 'assert' => ['1', (string)PHP_INT_MAX, '15'], + ], + 'string' => [ + 'input' => '<1><279012>', + 'assert' => ['1', '279012'], + ], + 'space' => [ + 'input' => '<1><279 012><32>', + 'assert' => ['1', '32'], + ], + 'empty' => [ + 'input' => '', + 'assert' => [], + ], + /// @todo should there be an exception? + 'noBrackets' => [ + 'input' => 'According to documentation, that\'s invalid. ', //should be invalid + 'assert' => [], + ], + /// @todo should there be an exception? + 'justOneBracket' => [ + 'input' => ' [], + ], + /// @todo should there be an exception? + 'justOneBracket2' => [ + 'input' => 'Another invalid> string', //should be invalid + 'assert' => [], + ], + /// @todo should there be an exception? + 'closeOnly' => [ + 'input' => 'Another> invalid> string>', //should be invalid + 'assert' => [], + ], + /// @todo should there be an exception? + 'openOnly' => [ + 'input' => ' [], + ], + /// @todo should there be an exception? + 'noMatching1' => [ + 'input' => ' invalid ', //should be invalid + 'assert' => [], + ], + /// @todo should there be an exception? Or array(1, 3) + // (This should be array(1,3) - mike) + 'emptyMatch' => [ + 'input' => '<1><><3>', //should be invalid + 'assert' => ['1', '3'], + ], + ]; } /** - * test with a big number + * @dataProvider dataExpand */ - public function testExpandAclBigNumber() + public function testExpand($input, array $assert) { - $aclFormatter = new ACLFormatter(); - - $text='<1><' . PHP_INT_MAX . '><15>'; - $this->assertEquals(array('1', (string)PHP_INT_MAX, '15'), $aclFormatter->expand($text)); - } - - /** - * test with a string in it. - * - * @todo is this valid input? Otherwise: should there be an exception? - */ - public function testExpandAclString() - { - $aclFormatter = new ACLFormatter(); - - $text="<1><279012>"; - $this->assertEquals(array('1', '279012'), $aclFormatter->expand($text)); - } - - /** - * test with a ' ' in it. - * - * @todo is this valid input? Otherwise: should there be an exception? - */ - public function testExpandAclSpace() - { - $aclFormatter = new ACLFormatter(); - - $text="<1><279 012><32>"; - $this->assertEquals(array('1', '32'), $aclFormatter->expand($text)); - } - - /** - * test empty input - */ - public function testExpandAclEmpty() - { - $aclFormatter = new ACLFormatter(); - - $text=""; - $this->assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, no < at all - * - * @todo should there be an exception? - */ - public function testExpandAclNoBrackets() - { - $aclFormatter = new ACLFormatter(); - - $text="According to documentation, that's invalid. "; //should be invalid - $this->assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, just open < - * - * @todo should there be an exception? - */ - public function testExpandAclJustOneBracket1() - { - $aclFormatter = new ACLFormatter(); - - $text="assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, just close > - * - * @todo should there be an exception? - */ - public function testExpandAclJustOneBracket2() - { - $aclFormatter = new ACLFormatter(); - - $text="Another invalid> string"; //should be invalid - $this->assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, just close > - * - * @todo should there be an exception? - */ - public function testExpandAclCloseOnly() - { - $aclFormatter = new ACLFormatter(); - - $text="Another> invalid> string>"; //should be invalid - $this->assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, just open < - * - * @todo should there be an exception? - */ - public function testExpandAclOpenOnly() - { - $aclFormatter = new ACLFormatter(); - - $text="assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, open and close do not match - * - * @todo should there be an exception? - */ - public function testExpandAclNoMatching1() - { - $aclFormatter = new ACLFormatter(); - - $text=" invalid "; //should be invalid - $this->assertEquals(array(), $aclFormatter->expand($text)); - } - - /** - * test invalid input, empty <> - * - * @todo should there be an exception? Or array(1, 3) - * (This should be array(1,3) - mike) - */ - public function testExpandAclEmptyMatch() - { - $aclFormatter = new ACLFormatter(); - - $text="<1><><3>"; - $this->assertEquals(array('1', '3'), $aclFormatter->expand($text)); + $this->assertAcl($input, $assert); } /** @@ -170,8 +111,14 @@ class ACLFormaterTest extends TestCase { $aclFormatter = new ACLFormatter(); - $this->assertNull($aclFormatter->expand(null)); - $this->assertNull($aclFormatter->expand()); + $allow_people = $aclFormatter->expand(); + $allow_groups = $aclFormatter->expand(); + + $this->assertEmpty($aclFormatter->expand(null)); + $this->assertEmpty($aclFormatter->expand()); + + $recipients = array_unique(array_merge($allow_people, $allow_groups)); + $this->assertEmpty($recipients); } public function dataAclToString() From c1c4640c1be543ce7c04e36e84a398e63f73ce9b Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Fri, 1 Nov 2019 15:49:18 +0100 Subject: [PATCH 3/3] remove unneeded todo --- tests/src/Util/ACLFormaterTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/src/Util/ACLFormaterTest.php b/tests/src/Util/ACLFormaterTest.php index ae875856a..4dccda600 100644 --- a/tests/src/Util/ACLFormaterTest.php +++ b/tests/src/Util/ACLFormaterTest.php @@ -87,10 +87,8 @@ class ACLFormaterTest extends TestCase 'input' => ' invalid ', //should be invalid 'assert' => [], ], - /// @todo should there be an exception? Or array(1, 3) - // (This should be array(1,3) - mike) 'emptyMatch' => [ - 'input' => '<1><><3>', //should be invalid + 'input' => '<1><><3>', 'assert' => ['1', '3'], ], ];