Migrate PermissionSet to Depository paradigm
This commit is contained in:
parent
430e6c3285
commit
62eb16e9ad
21 changed files with 437 additions and 387 deletions
|
@ -13,7 +13,7 @@ use Psr\Log\LoggerInterface;
|
||||||
* Depositories are meant to store and retrieve Entities from the database.
|
* Depositories are meant to store and retrieve Entities from the database.
|
||||||
*
|
*
|
||||||
* The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
|
* The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
|
||||||
* which means we can't direcly overload base methods and make parameters more strict (from a parent class to a child
|
* which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
|
||||||
* class for example)
|
* class for example)
|
||||||
*
|
*
|
||||||
* Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
|
* Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
|
||||||
|
|
|
@ -7,7 +7,7 @@ use Friendica\BaseEntity;
|
||||||
interface ICanCreateFromTableRow
|
interface ICanCreateFromTableRow
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns the correcponding Entity given a table row record
|
* Returns the corresponding Entity given a table row record
|
||||||
*
|
*
|
||||||
* @param array $row
|
* @param array $row
|
||||||
* @return BaseEntity
|
* @return BaseEntity
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (C) 2010-2021, the Friendica project
|
|
||||||
*
|
|
||||||
* @license GNU AGPL version 3 or any later version
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Friendica\Collection;
|
|
||||||
|
|
||||||
use Friendica\BaseCollection;
|
|
||||||
|
|
||||||
class PermissionSets extends BaseCollection
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -21,14 +21,12 @@
|
||||||
|
|
||||||
namespace Friendica\Core;
|
namespace Friendica\Core;
|
||||||
|
|
||||||
use Friendica\App;
|
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Database\DBStructure;
|
use Friendica\Database\DBStructure;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
|
||||||
use Friendica\Model\Photo;
|
use Friendica\Model\Photo;
|
||||||
use Friendica\Object\Image;
|
use Friendica\Object\Image;
|
||||||
use Friendica\Repository\PermissionSet;
|
use Friendica\Security\PermissionSet\Depository\PermissionSet;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
use Friendica\Worker\Delivery;
|
use Friendica\Worker\Delivery;
|
||||||
|
|
||||||
|
@ -283,16 +281,13 @@ class UserImport
|
||||||
DI::profileField()->migrateFromLegacyProfile($profile);
|
DI::profileField()->migrateFromLegacyProfile($profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
///@TODO Replace with permissionset import
|
$permissionSet = DI::permissionSet()->selectDefaultForUser($newuid);
|
||||||
$self_contact = Contact::selectFirst(['id'], ['uid' => $newuid, 'self' => true]);
|
|
||||||
$allow_cid = DI::aclFormatter()->toString($self_contact['id']);
|
|
||||||
$self_psid = DI::permissionSet()->getIdFromACL($newuid, $allow_cid);
|
|
||||||
|
|
||||||
foreach ($account['profile_fields'] ?? [] as $profile_field) {
|
foreach ($account['profile_fields'] ?? [] as $profile_field) {
|
||||||
$profile_field['uid'] = $newuid;
|
$profile_field['uid'] = $newuid;
|
||||||
|
|
||||||
///@TODO Replace with permissionset import
|
///@TODO Replace with permissionset import
|
||||||
$profile_field['psid'] = $profile_field['psid'] ? $self_psid : PermissionSet::PUBLIC;
|
$profile_field['psid'] = $profile_field['psid'] ? $permissionSet->uid : PermissionSet::PUBLIC;
|
||||||
|
|
||||||
if (self::dbImportAssoc('profile_field', $profile_field) === false) {
|
if (self::dbImportAssoc('profile_field', $profile_field) === false) {
|
||||||
Logger::info("uimport:insert profile field " . $profile_field['id'] . " : ERROR : " . DBA::errorMessage());
|
Logger::info("uimport:insert profile field " . $profile_field['id'] . " : ERROR : " . DBA::errorMessage());
|
||||||
|
|
13
src/DI.php
13
src/DI.php
|
@ -22,6 +22,7 @@
|
||||||
namespace Friendica;
|
namespace Friendica;
|
||||||
|
|
||||||
use Dice\Dice;
|
use Dice\Dice;
|
||||||
|
use Friendica\Security\PermissionSet\Depository\PermissionSet;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -443,11 +444,19 @@ abstract class DI
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Repository\PermissionSet
|
* @return PermissionSet
|
||||||
*/
|
*/
|
||||||
public static function permissionSet()
|
public static function permissionSet()
|
||||||
{
|
{
|
||||||
return self::$dice->create(Repository\PermissionSet::class);
|
return self::$dice->create(PermissionSet::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Friendica\Security\PermissionSet\Factory\PermissionSet
|
||||||
|
*/
|
||||||
|
public static function permissionSetFactory()
|
||||||
|
{
|
||||||
|
return self::$dice->create(\Friendica\Security\PermissionSet\Factory\PermissionSet::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,8 +27,8 @@ use Friendica\Collection\Api\Mastodon\Fields;
|
||||||
use Friendica\Model\APContact;
|
use Friendica\Model\APContact;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Network\HTTPException;
|
||||||
use Friendica\Repository\PermissionSet;
|
|
||||||
use Friendica\Repository\ProfileField;
|
use Friendica\Repository\ProfileField;
|
||||||
|
use Friendica\Security\PermissionSet\Depository\PermissionSet;
|
||||||
use ImagickException;
|
use ImagickException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
|
|
@ -980,13 +980,14 @@ class Item
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates or assigns the permission set
|
// Creates or assigns the permission set
|
||||||
$item['psid'] = PermissionSet::getIdFromACL(
|
$item['psid'] = DI::permissionSet()->selectOrCreate(
|
||||||
$item['uid'],
|
DI::permissionSetFactory()->createFromString(
|
||||||
$item['allow_cid'],
|
$item['uid'],
|
||||||
$item['allow_gid'],
|
$item['allow_cid'],
|
||||||
$item['deny_cid'],
|
$item['allow_gid'],
|
||||||
$item['deny_gid']
|
$item['deny_cid'],
|
||||||
);
|
$item['deny_gid']
|
||||||
|
))->id;
|
||||||
|
|
||||||
if (!empty($item['extid'])) {
|
if (!empty($item['extid'])) {
|
||||||
$item['external-id'] = ItemURI::getIdByURI($item['extid']);
|
$item['external-id'] = ItemURI::getIdByURI($item['extid']);
|
||||||
|
@ -1952,18 +1953,19 @@ class Item
|
||||||
$private = self::PUBLIC;
|
$private = self::PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
$psid = PermissionSet::getIdFromACL(
|
$permissionSet = DI::permissionSet()->selectOrCreate(
|
||||||
$user['uid'],
|
DI::permissionSetFactory()->createFromString(
|
||||||
$user['allow_cid'],
|
$user['uid'],
|
||||||
$user['allow_gid'],
|
$user['allow_cid'],
|
||||||
$user['deny_cid'],
|
$user['allow_gid'],
|
||||||
$user['deny_gid']
|
$user['deny_cid'],
|
||||||
);
|
$user['deny_gid']
|
||||||
|
));
|
||||||
|
|
||||||
$forum_mode = ($prvgroup ? 2 : 1);
|
$forum_mode = ($prvgroup ? 2 : 1);
|
||||||
|
|
||||||
$fields = ['wall' => true, 'origin' => true, 'forum_mode' => $forum_mode, 'contact-id' => $self['id'],
|
$fields = ['wall' => true, 'origin' => true, 'forum_mode' => $forum_mode, 'contact-id' => $self['id'],
|
||||||
'owner-id' => $owner_id, 'private' => $private, 'psid' => $psid];
|
'owner-id' => $owner_id, 'private' => $private, 'psid' => $permissionSet->id];
|
||||||
self::update($fields, ['id' => $item['id']]);
|
self::update($fields, ['id' => $item['id']]);
|
||||||
|
|
||||||
Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']);
|
Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']);
|
||||||
|
@ -2549,12 +2551,12 @@ class Item
|
||||||
$condition = [];
|
$condition = [];
|
||||||
} elseif ($remote_user) {
|
} elseif ($remote_user) {
|
||||||
// Authenticated visitor - fetch the matching permissionsets
|
// Authenticated visitor - fetch the matching permissionsets
|
||||||
$set = PermissionSet::get($owner_id, $remote_user);
|
$permissionSets = DI::permissionSet()->selectByContactId($remote_user, $owner_id);
|
||||||
if (!empty($set)) {
|
if (!empty($set)) {
|
||||||
$condition = ["(`private` != ? OR (`private` = ? AND `wall`
|
$condition = ["(`private` != ? OR (`private` = ? AND `wall`
|
||||||
AND `psid` IN (" . implode(', ', array_fill(0, count($set), '?')) . ")))",
|
AND `psid` IN (" . implode(', ', array_fill(0, count($set), '?')) . ")))",
|
||||||
self::PRIVATE, self::PRIVATE];
|
self::PRIVATE, self::PRIVATE];
|
||||||
$condition = array_merge($condition, $set);
|
$condition = array_merge($condition, $permissionSets->column('id'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2595,10 +2597,10 @@ class Item
|
||||||
* If pre-verified, the caller is expected to have already
|
* If pre-verified, the caller is expected to have already
|
||||||
* done this and passed the groups into this function.
|
* done this and passed the groups into this function.
|
||||||
*/
|
*/
|
||||||
$set = PermissionSet::get($owner_id, $remote_user);
|
$permissionSets = DI::permissionSet()->selectByContactId($remote_user, $owner_id);
|
||||||
|
|
||||||
if (!empty($set)) {
|
if (!empty($set)) {
|
||||||
$sql_set = sprintf(" OR (" . $table . "`private` = %d AND " . $table . "`wall` AND " . $table . "`psid` IN (", self::PRIVATE) . implode(',', $set) . "))";
|
$sql_set = sprintf(" OR (" . $table . "`private` = %d AND " . $table . "`wall` AND " . $table . "`psid` IN (", self::PRIVATE) . implode(',', $permissionSets->column('id')) . "))";
|
||||||
} else {
|
} else {
|
||||||
$sql_set = '';
|
$sql_set = '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (C) 2010-2021, the Friendica project
|
|
||||||
*
|
|
||||||
* @license GNU AGPL version 3 or any later version
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Friendica\Model;
|
|
||||||
|
|
||||||
use Friendica\BaseModel;
|
|
||||||
use Friendica\DI;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* functions for interacting with the permission set of an object (item, photo, event, ...)
|
|
||||||
*
|
|
||||||
* @property int uid
|
|
||||||
* @property string allow_cid
|
|
||||||
* @property string allow_gid
|
|
||||||
* @property string deny_cid
|
|
||||||
* @property string deny_gid
|
|
||||||
*/
|
|
||||||
class PermissionSet extends BaseModel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Fetch the id of a given permission set. Generate a new one when needed
|
|
||||||
*
|
|
||||||
* @param int $uid
|
|
||||||
* @param string|null $allow_cid Allowed contact IDs - empty = everyone
|
|
||||||
* @param string|null $allow_gid Allowed group IDs - empty = everyone
|
|
||||||
* @param string|null $deny_cid Disallowed contact IDs - empty = no one
|
|
||||||
* @param string|null $deny_gid Disallowed group IDs - empty = no one
|
|
||||||
* @return int id
|
|
||||||
* @throws \Exception
|
|
||||||
* @deprecated since 2020.03, use Repository\PermissionSet instead
|
|
||||||
* @see \Friendica\Repository\PermissionSet->getIdFromACL
|
|
||||||
*/
|
|
||||||
public static function getIdFromACL(
|
|
||||||
int $uid,
|
|
||||||
string $allow_cid = null,
|
|
||||||
string $allow_gid = null,
|
|
||||||
string $deny_cid = null,
|
|
||||||
string $deny_gid = null
|
|
||||||
) {
|
|
||||||
return DI::permissionSet()->getIdFromACL($uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a permission set for a given contact
|
|
||||||
*
|
|
||||||
* @param integer $uid User id whom the items belong
|
|
||||||
* @param integer $contact_id Contact id of the visitor
|
|
||||||
*
|
|
||||||
* @return array of permission set ids.
|
|
||||||
* @throws \Exception
|
|
||||||
* @deprecated since 2020.03, use Repository\PermissionSet instead
|
|
||||||
* @see \Friendica\Repository\PermissionSet->selectByContactId
|
|
||||||
*/
|
|
||||||
public static function get($uid, $contact_id)
|
|
||||||
{
|
|
||||||
$permissionSets = DI::permissionSet()->selectByContactId($contact_id, $uid);
|
|
||||||
|
|
||||||
return $permissionSets->column('id');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,7 +23,7 @@ namespace Friendica\Model;
|
||||||
|
|
||||||
use Friendica\BaseModel;
|
use Friendica\BaseModel;
|
||||||
use Friendica\Database\Database;
|
use Friendica\Database\Database;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Security\PermissionSet\Entity\PermissionSet;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,14 +46,14 @@ class ProfileField extends BaseModel
|
||||||
/** @var PermissionSet */
|
/** @var PermissionSet */
|
||||||
private $permissionset;
|
private $permissionset;
|
||||||
|
|
||||||
/** @var \Friendica\Repository\PermissionSet */
|
/** @var \Friendica\Security\PermissionSet\Depository\PermissionSet */
|
||||||
private $permissionSetRepository;
|
private $permissionSetDepository;
|
||||||
|
|
||||||
public function __construct(Database $dba, LoggerInterface $logger, \Friendica\Repository\PermissionSet $permissionSetRepository, array $data = [])
|
public function __construct(Database $dba, LoggerInterface $logger,\Friendica\Security\PermissionSet\Depository\PermissionSet $permissionSetDepository, array $data = [])
|
||||||
{
|
{
|
||||||
parent::__construct($dba, $logger, $data);
|
parent::__construct($dba, $logger, $data);
|
||||||
|
|
||||||
$this->permissionSetRepository = $permissionSetRepository;
|
$this->permissionSetDepository = $permissionSetDepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
|
@ -62,9 +62,7 @@ class ProfileField extends BaseModel
|
||||||
|
|
||||||
switch ($name) {
|
switch ($name) {
|
||||||
case 'permissionset':
|
case 'permissionset':
|
||||||
$this->permissionset =
|
$this->permissionset = $this->permissionset ?? $this->permissionSetDepository->selectOneById($this->psid);
|
||||||
$this->permissionset ??
|
|
||||||
$this->permissionSetRepository->selectFirst(['id' => $this->psid, 'uid' => $this->uid]);
|
|
||||||
|
|
||||||
$return = $this->permissionset;
|
$return = $this->permissionset;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Objects extends BaseModule
|
||||||
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']);
|
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']);
|
||||||
if (!empty($permissionSets)) {
|
if (!empty($permissionSets)) {
|
||||||
$psid = array_merge($permissionSets->column('id'),
|
$psid = array_merge($permissionSets->column('id'),
|
||||||
[DI::permissionSet()->getIdFromACL($item['uid'], '', '', '', '')]);
|
[DI::permissionSet()->selectEmptyForUser($item['uid'])]);
|
||||||
$validated = in_array($item['psid'], $psid);
|
$validated = in_array($item['psid'], $psid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Profile;
|
use Friendica\Model\Profile;
|
||||||
use Friendica\Module\BaseApi;
|
use Friendica\Module\BaseApi;
|
||||||
use Friendica\Network\HTTPException;
|
use Friendica\Network\HTTPException;
|
||||||
use Friendica\Repository\PermissionSet;
|
use Friendica\Security\PermissionSet\Depository\PermissionSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API endpoint: /api/friendica/profile/show
|
* API endpoint: /api/friendica/profile/show
|
||||||
|
|
|
@ -39,7 +39,7 @@ class PermissionTooltip extends \Friendica\BaseModule
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($model['psid'])) {
|
if (isset($model['psid'])) {
|
||||||
$permissionSet = DI::permissionSet()->selectFirst(['id' => $model['psid']]);
|
$permissionSet = DI::permissionSet()->selectOneById($model['psid']);
|
||||||
$model['allow_cid'] = $permissionSet->allow_cid;
|
$model['allow_cid'] = $permissionSet->allow_cid;
|
||||||
$model['allow_gid'] = $permissionSet->allow_gid;
|
$model['allow_gid'] = $permissionSet->allow_gid;
|
||||||
$model['deny_cid'] = $permissionSet->deny_cid;
|
$model['deny_cid'] = $permissionSet->deny_cid;
|
||||||
|
@ -61,12 +61,10 @@ class PermissionTooltip extends \Friendica\BaseModule
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$aclFormatter = DI::aclFormatter();
|
$allowed_users = $model['allow_cid'];
|
||||||
|
$allowed_groups = $model['allow_gid'];
|
||||||
$allowed_users = $aclFormatter->expand($model['allow_cid']);
|
$deny_users = $model['deny_cid'];
|
||||||
$allowed_groups = $aclFormatter->expand($model['allow_gid']);
|
$deny_groups = $model['deny_gid'];
|
||||||
$deny_users = $aclFormatter->expand($model['deny_cid']);
|
|
||||||
$deny_groups = $aclFormatter->expand($model['deny_gid']);
|
|
||||||
|
|
||||||
$o = DI::l10n()->t('Visible to:') . '<br />';
|
$o = DI::l10n()->t('Visible to:') . '<br />';
|
||||||
$l = [];
|
$l = [];
|
||||||
|
|
|
@ -213,7 +213,7 @@ class Status extends BaseProfile
|
||||||
$permissionSets = DI::permissionSet()->selectByContactId($remote_user, $profile['uid']);
|
$permissionSets = DI::permissionSet()->selectByContactId($remote_user, $profile['uid']);
|
||||||
if (!empty($permissionSets)) {
|
if (!empty($permissionSets)) {
|
||||||
$condition = ['psid' => array_merge($permissionSets->column('id'),
|
$condition = ['psid' => array_merge($permissionSets->column('id'),
|
||||||
[DI::permissionSet()->getIdFromACL($profile['uid'], '', '', '', '')])];
|
[DI::permissionSet()->selectEmptyForUser($profile['uid'])])];
|
||||||
}
|
}
|
||||||
} elseif ($profile['uid'] == local_user()) {
|
} elseif ($profile['uid'] == local_user()) {
|
||||||
$condition = [];
|
$condition = [];
|
||||||
|
|
|
@ -28,6 +28,7 @@ use Friendica\Core\Renderer;
|
||||||
use Friendica\Core\Theme;
|
use Friendica\Core\Theme;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Profile;
|
use Friendica\Model\Profile;
|
||||||
use Friendica\Model\ProfileField;
|
use Friendica\Model\ProfileField;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
|
@ -161,7 +162,9 @@ class Index extends BaseSettings
|
||||||
$profileFields = DI::profileField()->selectByUserId(local_user());
|
$profileFields = DI::profileField()->selectByUserId(local_user());
|
||||||
foreach ($profileFields as $profileField) {
|
foreach ($profileFields as $profileField) {
|
||||||
/** @var ProfileField $profileField */
|
/** @var ProfileField $profileField */
|
||||||
$defaultPermissions = ACL::getDefaultUserPermissions($profileField->permissionset->toArray());
|
$defaultPermissions = $profileField->permissionset->withAllowedContacts(
|
||||||
|
Contact::pruneUnavailable($profileField->permissionset->allow_cid)
|
||||||
|
);
|
||||||
|
|
||||||
$custom_fields[] = [
|
$custom_fields[] = [
|
||||||
'id' => $profileField->id,
|
'id' => $profileField->id,
|
||||||
|
@ -173,7 +176,7 @@ class Index extends BaseSettings
|
||||||
DI::page(),
|
DI::page(),
|
||||||
$a->getLoggedInUserId(),
|
$a->getLoggedInUserId(),
|
||||||
false,
|
false,
|
||||||
$defaultPermissions,
|
$defaultPermissions->toArray(),
|
||||||
['network' => Protocol::DFRN],
|
['network' => Protocol::DFRN],
|
||||||
'profile_field[' . $profileField->id . ']'
|
'profile_field[' . $profileField->id . ']'
|
||||||
),
|
),
|
||||||
|
|
|
@ -242,7 +242,7 @@ class Transmitter
|
||||||
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $owner['uid']);
|
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $owner['uid']);
|
||||||
if (!empty($permissionSets)) {
|
if (!empty($permissionSets)) {
|
||||||
$condition = ['psid' => array_merge($permissionSets->column('id'),
|
$condition = ['psid' => array_merge($permissionSets->column('id'),
|
||||||
[DI::permissionSet()->getIdFromACL($owner['uid'], '', '', '', '')])];
|
[DI::permissionSet()->selectEmptyForUser($owner['uid'])])];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (C) 2010-2021, the Friendica project
|
|
||||||
*
|
|
||||||
* @license GNU AGPL version 3 or any later version
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Friendica\Repository;
|
|
||||||
|
|
||||||
use Friendica\BaseRepository;
|
|
||||||
use Friendica\Collection;
|
|
||||||
use Friendica\Database\Database;
|
|
||||||
use Friendica\Model;
|
|
||||||
use Friendica\Network\HTTPException;
|
|
||||||
use Friendica\Util\ACLFormatter;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
|
|
||||||
class PermissionSet extends BaseRepository
|
|
||||||
{
|
|
||||||
/** @var int Virtual permission set id for public permission */
|
|
||||||
const PUBLIC = 0;
|
|
||||||
|
|
||||||
protected static $table_name = 'permissionset';
|
|
||||||
|
|
||||||
protected static $model_class = Model\PermissionSet::class;
|
|
||||||
|
|
||||||
protected static $collection_class = Collection\PermissionSets::class;
|
|
||||||
|
|
||||||
/** @var ACLFormatter */
|
|
||||||
private $aclFormatter;
|
|
||||||
|
|
||||||
public function __construct(Database $dba, LoggerInterface $logger, ACLFormatter $aclFormatter)
|
|
||||||
{
|
|
||||||
parent::__construct($dba, $logger);
|
|
||||||
|
|
||||||
$this->aclFormatter = $aclFormatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $data
|
|
||||||
* @return Model\PermissionSet
|
|
||||||
*/
|
|
||||||
protected function create(array $data)
|
|
||||||
{
|
|
||||||
return new Model\PermissionSet($this->dba, $this->logger, $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $condition
|
|
||||||
* @return Model\PermissionSet
|
|
||||||
* @throws \Friendica\Network\HTTPException\NotFoundException
|
|
||||||
*/
|
|
||||||
public function selectFirst(array $condition)
|
|
||||||
{
|
|
||||||
if (isset($condition['id']) && !$condition['id']) {
|
|
||||||
return $this->create([
|
|
||||||
'id' => self::PUBLIC,
|
|
||||||
'uid' => $condition['uid'] ?? 0,
|
|
||||||
'allow_cid' => '',
|
|
||||||
'allow_gid' => '',
|
|
||||||
'deny_cid' => '',
|
|
||||||
'deny_gid' => '',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::selectFirst($condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $condition
|
|
||||||
* @param array $params
|
|
||||||
* @return Collection\PermissionSets
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function select(array $condition = [], array $params = [])
|
|
||||||
{
|
|
||||||
return parent::select($condition, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $condition
|
|
||||||
* @param array $params
|
|
||||||
* @param int|null $min_id
|
|
||||||
* @param int|null $max_id
|
|
||||||
* @param int $limit
|
|
||||||
* @return Collection\PermissionSets
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
|
|
||||||
{
|
|
||||||
return parent::selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the id of a given permission set. Generate a new one when needed
|
|
||||||
*
|
|
||||||
* @param int $uid
|
|
||||||
* @param string|null $allow_cid Allowed contact IDs - empty = everyone
|
|
||||||
* @param string|null $allow_gid Allowed group IDs - empty = everyone
|
|
||||||
* @param string|null $deny_cid Disallowed contact IDs - empty = no one
|
|
||||||
* @param string|null $deny_gid Disallowed group IDs - empty = no one
|
|
||||||
* @return int id
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function getIdFromACL(
|
|
||||||
int $uid,
|
|
||||||
string $allow_cid = null,
|
|
||||||
string $allow_gid = null,
|
|
||||||
string $deny_cid = null,
|
|
||||||
string $deny_gid = null
|
|
||||||
) {
|
|
||||||
$allow_cid = $this->aclFormatter->sanitize($allow_cid);
|
|
||||||
$allow_gid = $this->aclFormatter->sanitize($allow_gid);
|
|
||||||
$deny_cid = $this->aclFormatter->sanitize($deny_cid);
|
|
||||||
$deny_gid = $this->aclFormatter->sanitize($deny_gid);
|
|
||||||
|
|
||||||
// Public permission
|
|
||||||
if (!$allow_cid && !$allow_gid && !$deny_cid && !$deny_gid) {
|
|
||||||
return self::PUBLIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
$condition = [
|
|
||||||
'uid' => $uid,
|
|
||||||
'allow_cid' => $allow_cid,
|
|
||||||
'allow_gid' => $allow_gid,
|
|
||||||
'deny_cid' => $deny_cid,
|
|
||||||
'deny_gid' => $deny_gid
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
$permissionset = $this->selectFirst($condition);
|
|
||||||
} catch(HTTPException\NotFoundException $exception) {
|
|
||||||
$permissionset = $this->insert($condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $permissionset->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a permission set collection for a given contact
|
|
||||||
*
|
|
||||||
* @param integer $contact_id Contact id of the visitor
|
|
||||||
* @param integer $uid User id whom the items belong, used for ownership check.
|
|
||||||
*
|
|
||||||
* @return Collection\PermissionSets
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function selectByContactId($contact_id, $uid)
|
|
||||||
{
|
|
||||||
$cdata = Model\Contact::getPublicAndUserContactID($contact_id, $uid);
|
|
||||||
if (!empty($cdata)) {
|
|
||||||
$public_contact_str = '<' . $cdata['public'] . '>';
|
|
||||||
$user_contact_str = '<' . $cdata['user'] . '>';
|
|
||||||
$contact_id = $cdata['user'];
|
|
||||||
} else {
|
|
||||||
$public_contact_str = '<' . $contact_id . '>';
|
|
||||||
$user_contact_str = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$groups = [];
|
|
||||||
if (!empty($user_contact_str) && $this->dba->exists('contact', ['id' => $contact_id, 'uid' => $uid, 'blocked' => false])) {
|
|
||||||
$groups = Model\Group::getIdsByContactId($contact_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$group_str = '<<>>'; // should be impossible to match
|
|
||||||
foreach ($groups as $group_id) {
|
|
||||||
$group_str .= '|<' . preg_quote($group_id) . '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($user_contact_str)) {
|
|
||||||
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR `deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
|
||||||
AND (allow_cid REGEXP ? OR allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
|
||||||
$uid, $user_contact_str, $public_contact_str, $group_str,
|
|
||||||
$user_contact_str, $public_contact_str, $group_str];
|
|
||||||
} else {
|
|
||||||
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
|
||||||
AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
|
||||||
$uid, $public_contact_str, $group_str, $public_contact_str, $group_str];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->select($condition);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,7 +28,7 @@ use Friendica\Core\L10n;
|
||||||
use Friendica\Database\Database;
|
use Friendica\Database\Database;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Model;
|
use Friendica\Model;
|
||||||
use Friendica\Util\ACLFormatter;
|
use Friendica\Security\PermissionSet\Depository\PermissionSet;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
@ -42,18 +42,18 @@ class ProfileField extends BaseRepository
|
||||||
|
|
||||||
/** @var PermissionSet */
|
/** @var PermissionSet */
|
||||||
private $permissionSet;
|
private $permissionSet;
|
||||||
/** @var ACLFormatter */
|
/** @var \Friendica\Security\PermissionSet\Factory\PermissionSet */
|
||||||
private $aclFormatter;
|
private $permissionSetFactory;
|
||||||
/** @var L10n */
|
/** @var L10n */
|
||||||
private $l10n;
|
private $l10n;
|
||||||
|
|
||||||
public function __construct(Database $dba, LoggerInterface $logger, PermissionSet $permissionSet, ACLFormatter $aclFormatter, L10n $l10n)
|
public function __construct(Database $dba, LoggerInterface $logger, PermissionSet $permissionSet, \Friendica\Security\PermissionSet\Factory\PermissionSet $permissionSetFactory, L10n $l10n)
|
||||||
{
|
{
|
||||||
parent::__construct($dba, $logger);
|
parent::__construct($dba, $logger);
|
||||||
|
|
||||||
$this->permissionSet = $permissionSet;
|
$this->permissionSet = $permissionSet;
|
||||||
$this->aclFormatter = $aclFormatter;
|
$this->permissionSetFactory = $permissionSetFactory;
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,7 +160,7 @@ class ProfileField extends BaseRepository
|
||||||
|
|
||||||
return parent::update($model);
|
return parent::update($model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $uid User Id
|
* @param int $uid User Id
|
||||||
* @param Collection\ProfileFields $profileFields Collection of existing profile fields
|
* @param Collection\ProfileFields $profileFields Collection of existing profile fields
|
||||||
|
@ -176,24 +176,24 @@ class ProfileField extends BaseRepository
|
||||||
|
|
||||||
// Creation of the new field
|
// Creation of the new field
|
||||||
if (!empty($profileFieldInputs['new']['label'])) {
|
if (!empty($profileFieldInputs['new']['label'])) {
|
||||||
$psid = $this->permissionSet->getIdFromACL(
|
$psid = $this->permissionSet->selectOrCreate($this->permissionSetFactory->createFromString(
|
||||||
$uid,
|
$uid,
|
||||||
$this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''),
|
$profileFieldInputs['new']['contact_allow'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs['new']['group_allow'] ?? ''),
|
$profileFieldInputs['new']['group_allow'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''),
|
$profileFieldInputs['new']['contact_deny'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs['new']['group_deny'] ?? '')
|
$profileFieldInputs['new']['group_deny'] ?? ''
|
||||||
);
|
))->id;
|
||||||
|
|
||||||
$newProfileField = $this->insert([
|
$newProfileField = $this->insert([
|
||||||
'uid' => $uid,
|
'uid' => $uid,
|
||||||
'label' => $profileFieldInputs['new']['label'],
|
'label' => $profileFieldInputs['new']['label'],
|
||||||
'value' => $profileFieldInputs['new']['value'],
|
'value' => $profileFieldInputs['new']['value'],
|
||||||
'psid' => $psid,
|
'psid' => $psid,
|
||||||
'order' => $profileFieldOrder['new'],
|
'order' => $profileFieldOrder['new'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$profileFieldInputs[$newProfileField->id] = $profileFieldInputs['new'];
|
$profileFieldInputs[$newProfileField->id] = $profileFieldInputs['new'];
|
||||||
$profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new'];
|
$profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new'];
|
||||||
|
|
||||||
$profileFields[] = $newProfileField;
|
$profileFields[] = $newProfileField;
|
||||||
}
|
}
|
||||||
|
@ -220,15 +220,15 @@ class ProfileField extends BaseRepository
|
||||||
// Update existing profile fields from form values
|
// Update existing profile fields from form values
|
||||||
$profileFields = $profileFields->map(function (Model\ProfileField $profileField) use ($uid, &$profileFieldInputs, &$profileFieldOrder) {
|
$profileFields = $profileFields->map(function (Model\ProfileField $profileField) use ($uid, &$profileFieldInputs, &$profileFieldOrder) {
|
||||||
if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) {
|
if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) {
|
||||||
$psid = $this->permissionSet->getIdFromACL(
|
$psid = $this->permissionSet->selectOrCreate($this->permissionSetFactory->createFromString(
|
||||||
$uid,
|
$uid,
|
||||||
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_allow'] ?? ''),
|
$profileFieldInputs[$profileField->id]['contact_allow'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_allow'] ?? ''),
|
$profileFieldInputs[$profileField->id]['group_allow'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_deny'] ?? ''),
|
$profileFieldInputs[$profileField->id]['contact_deny'] ?? '',
|
||||||
$this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_deny'] ?? '')
|
$profileFieldInputs[$profileField->id]['group_deny'] ?? ''
|
||||||
);
|
))->id;
|
||||||
|
|
||||||
$profileField->psid = $psid;
|
$profileField->psid = $psid;
|
||||||
$profileField->label = $profileFieldInputs[$profileField->id]['label'];
|
$profileField->label = $profileFieldInputs[$profileField->id]['label'];
|
||||||
$profileField->value = $profileFieldInputs[$profileField->id]['value'];
|
$profileField->value = $profileFieldInputs[$profileField->id]['value'];
|
||||||
$profileField->order = $profileFieldOrder[$profileField->id];
|
$profileField->order = $profileFieldOrder[$profileField->id];
|
||||||
|
@ -257,17 +257,22 @@ class ProfileField extends BaseRepository
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$contacts = [];
|
||||||
|
|
||||||
if (!$profile['is-default']) {
|
if (!$profile['is-default']) {
|
||||||
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'profile-id' => $profile['id']]);
|
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'profile-id' => $profile['id']]);
|
||||||
if (!count($contacts)) {
|
if (!count($contacts)) {
|
||||||
// No contact visibility selected defaults to user-only permission
|
// No contact visibility selected defaults to user-only permission
|
||||||
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'self' => true]);
|
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'self' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$allow_cid = $this->aclFormatter->toString(array_column($contacts, 'id'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$psid = $this->permissionSet->getIdFromACL($profile['uid'], $allow_cid ?? '');
|
$psid = $this->permissionSet->selectOrCreate(
|
||||||
|
new \Friendica\Security\PermissionSet\Entity\PermissionSet(
|
||||||
|
$profile['uid'],
|
||||||
|
array_column($contacts, 'id') ?? []
|
||||||
|
)
|
||||||
|
)->id;
|
||||||
|
|
||||||
$order = 1;
|
$order = 1;
|
||||||
|
|
||||||
|
@ -297,8 +302,8 @@ class ProfileField extends BaseRepository
|
||||||
foreach ($custom_fields as $field => $label) {
|
foreach ($custom_fields as $field => $label) {
|
||||||
if (!empty($profile[$field]) && $profile[$field] > DBA::NULL_DATE && $profile[$field] > DBA::NULL_DATETIME) {
|
if (!empty($profile[$field]) && $profile[$field] > DBA::NULL_DATE && $profile[$field] > DBA::NULL_DATETIME) {
|
||||||
$this->insert([
|
$this->insert([
|
||||||
'uid' => $profile['uid'],
|
'uid' => $profile['uid'],
|
||||||
'psid' => $psid,
|
'psid' => $psid,
|
||||||
'order' => $order++,
|
'order' => $order++,
|
||||||
'label' => trim($label, ':'),
|
'label' => trim($label, ':'),
|
||||||
'value' => $profile[$field],
|
'value' => $profile[$field],
|
||||||
|
@ -310,7 +315,7 @@ class ProfileField extends BaseRepository
|
||||||
|
|
||||||
if ($profile['is-default']) {
|
if ($profile['is-default']) {
|
||||||
$profile['profile-name'] = null;
|
$profile['profile-name'] = null;
|
||||||
$profile['is-default'] = null;
|
$profile['is-default'] = null;
|
||||||
$this->dba->update('profile', $profile, ['id' => $profile['id']]);
|
$this->dba->update('profile', $profile, ['id' => $profile['id']]);
|
||||||
} elseif (!empty($profile['id'])) {
|
} elseif (!empty($profile['id'])) {
|
||||||
$this->dba->delete('profile', ['id' => $profile['id']]);
|
$this->dba->delete('profile', ['id' => $profile['id']]);
|
||||||
|
|
10
src/Security/PermissionSet/Collection/PermissionSets.php
Normal file
10
src/Security/PermissionSet/Collection/PermissionSets.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Security\PermissionSet\Collection;
|
||||||
|
|
||||||
|
use Friendica\BaseCollection;
|
||||||
|
|
||||||
|
class PermissionSets extends BaseCollection
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
210
src/Security/PermissionSet/Depository/PermissionSet.php
Normal file
210
src/Security/PermissionSet/Depository/PermissionSet.php
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (C) 2010-2021, the Friendica project
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Friendica\Security\PermissionSet\Depository;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Friendica\BaseDepository;
|
||||||
|
use Friendica\Database\Database;
|
||||||
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\Group;
|
||||||
|
use Friendica\Network\HTTPException\NotFoundException;
|
||||||
|
use Friendica\Security\PermissionSet\Factory;
|
||||||
|
use Friendica\Security\PermissionSet\Collection;
|
||||||
|
use Friendica\Security\PermissionSet\Entity;
|
||||||
|
use Friendica\Util\ACLFormatter;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class PermissionSet extends BaseDepository
|
||||||
|
{
|
||||||
|
/** @var int Virtual permission set id for public permission */
|
||||||
|
const PUBLIC = 0;
|
||||||
|
|
||||||
|
/** @var Factory\PermissionSet */
|
||||||
|
protected $factory;
|
||||||
|
|
||||||
|
protected static $table_name = 'permissionset';
|
||||||
|
|
||||||
|
/** @var ACLFormatter */
|
||||||
|
private $aclFormatter;
|
||||||
|
|
||||||
|
public function __construct(Database $database, LoggerInterface $logger, Factory\PermissionSet $factory, ACLFormatter $aclFormatter)
|
||||||
|
{
|
||||||
|
parent::__construct($database, $logger, $factory);
|
||||||
|
|
||||||
|
$this->aclFormatter = $aclFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $condition
|
||||||
|
* @param array $params
|
||||||
|
*
|
||||||
|
* @return Entity\PermissionSet
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
private function selectOne(array $condition, array $params = []): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
return parent::_selectOne($condition, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function select(array $condition, array $params = []): Collection\PermissionSets
|
||||||
|
{
|
||||||
|
return new Collection\PermissionSets(parent::_select($condition, $params)->getArrayCopy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $id
|
||||||
|
*
|
||||||
|
* @return Entity\PermissionSet
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function selectOneById(int $id): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
return $this->selectOne(['id' => $id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a permission set collection for a given contact
|
||||||
|
*
|
||||||
|
* @param int $cid Contact id of the visitor
|
||||||
|
* @param int $uid User id whom the items belong, used for ownership check.
|
||||||
|
*
|
||||||
|
* @return Collection\PermissionSets
|
||||||
|
*/
|
||||||
|
public function selectByContactId(int $cid, int $uid): Collection\PermissionSets
|
||||||
|
{
|
||||||
|
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||||
|
if (!empty($cdata)) {
|
||||||
|
$public_contact_str = $this->aclFormatter->toString($cdata['public']);
|
||||||
|
$user_contact_str = $this->aclFormatter->toString($cdata['user']);
|
||||||
|
$cid = $cdata['user'];
|
||||||
|
} else {
|
||||||
|
$public_contact_str = $this->aclFormatter->toString($cid);
|
||||||
|
$user_contact_str = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$groups = [];
|
||||||
|
if (!empty($user_contact_str) && $this->db->exists('contact', [
|
||||||
|
'id' => $cid,
|
||||||
|
'uid' => $uid,
|
||||||
|
'blocked' => false
|
||||||
|
])) {
|
||||||
|
$groups = Group::getIdsByContactId($cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$group_str = '<<>>'; // should be impossible to match
|
||||||
|
foreach ($groups as $group_id) {
|
||||||
|
$group_str .= '|<' . preg_quote($group_id) . '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($user_contact_str)) {
|
||||||
|
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR `deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
||||||
|
AND (allow_cid REGEXP ? OR allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
||||||
|
$uid, $user_contact_str, $public_contact_str, $group_str,
|
||||||
|
$user_contact_str, $public_contact_str, $group_str];
|
||||||
|
} else {
|
||||||
|
$condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
|
||||||
|
AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
|
||||||
|
$uid, $public_contact_str, $group_str, $public_contact_str, $group_str];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->select($condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the default PermissionSet for a given user, create it if it doesn't exist
|
||||||
|
*
|
||||||
|
* @param int $uid
|
||||||
|
*
|
||||||
|
* @return Entity\PermissionSet
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function selectDefaultForUser(int $uid): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
$self_contact = Contact::selectFirst(['id'], ['uid' => $uid, 'self' => true]);
|
||||||
|
|
||||||
|
return $this->selectOrCreate($this->factory->createFromString(
|
||||||
|
$uid,
|
||||||
|
$this->aclFormatter->toString($self_contact['id'])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the empty PermissionSet for a given user, create it if it doesn't exist
|
||||||
|
*
|
||||||
|
* @param int $uid
|
||||||
|
*
|
||||||
|
* @return Entity\PermissionSet
|
||||||
|
*/
|
||||||
|
public function selectEmptyForUser(int $uid): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
return $this->selectOrCreate($this->factory->createFromString($uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects or creates a PermissionSet based on it's fields
|
||||||
|
*
|
||||||
|
* @param Entity\PermissionSet $permissionSet
|
||||||
|
*
|
||||||
|
* @return Entity\PermissionSet
|
||||||
|
*/
|
||||||
|
public function selectOrCreate(Entity\PermissionSet $permissionSet): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
if ($permissionSet->id) {
|
||||||
|
return $permissionSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = [
|
||||||
|
'uid' => $permissionSet->uid,
|
||||||
|
'allow_cid' => $this->aclFormatter->toString($permissionSet->allow_cid),
|
||||||
|
'allow_gid' => $this->aclFormatter->toString($permissionSet->allow_gid),
|
||||||
|
'deny_cid' => $this->aclFormatter->toString($permissionSet->deny_cid),
|
||||||
|
'deny_gid' => $this->aclFormatter->toString($permissionSet->deny_gid),
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->selectOne($fields);
|
||||||
|
} catch (NotFoundException $exception) {
|
||||||
|
return $this->save($permissionSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(Entity\PermissionSet $permissionSet): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
$fields = [
|
||||||
|
'uid' => $permissionSet->uid,
|
||||||
|
'allow_cid' => $this->aclFormatter->toString($permissionSet->allow_cid),
|
||||||
|
'allow_gid' => $this->aclFormatter->toString($permissionSet->allow_gid),
|
||||||
|
'deny_cid' => $this->aclFormatter->toString($permissionSet->deny_cid),
|
||||||
|
'deny_gid' => $this->aclFormatter->toString($permissionSet->deny_gid),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($permissionSet->id) {
|
||||||
|
$this->db->update(self::$table_name, $fields, ['id' => $permissionSet->id]);
|
||||||
|
} else {
|
||||||
|
$this->db->insert(self::$table_name, $fields);
|
||||||
|
|
||||||
|
$permissionSet = $this->selectOneById($this->db->lastInsertId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $permissionSet;
|
||||||
|
}
|
||||||
|
}
|
66
src/Security/PermissionSet/Entity/PermissionSet.php
Normal file
66
src/Security/PermissionSet/Entity/PermissionSet.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Security\PermissionSet\Entity;
|
||||||
|
|
||||||
|
use Friendica\BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property-read int|null $id
|
||||||
|
* @property-read int $uid
|
||||||
|
* @property-read string[] $allow_cid
|
||||||
|
* @property-read string[] $allow_gid
|
||||||
|
* @property-read string[] $deny_cid
|
||||||
|
* @property-read string[] $deny_gid
|
||||||
|
*/
|
||||||
|
class PermissionSet extends BaseEntity
|
||||||
|
{
|
||||||
|
/** @var int|null */
|
||||||
|
protected $id;
|
||||||
|
/** @var int */
|
||||||
|
protected $uid;
|
||||||
|
/** @var string[] */
|
||||||
|
protected $allow_cid;
|
||||||
|
/** @var string[] */
|
||||||
|
protected $allow_gid;
|
||||||
|
/** @var string[] */
|
||||||
|
protected $deny_cid;
|
||||||
|
/** @var string[] */
|
||||||
|
protected $deny_gid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|null $id
|
||||||
|
* @param int $uid
|
||||||
|
* @param string[] $allow_cid
|
||||||
|
* @param string[] $allow_gid
|
||||||
|
* @param string[] $deny_cid
|
||||||
|
* @param string[] $deny_gid
|
||||||
|
*
|
||||||
|
* @see \Friendica\Security\PermissionSet\Factory\PermissionSet
|
||||||
|
*/
|
||||||
|
public function __construct(int $uid, array $allow_cid = [], array $allow_gid = [], array $deny_cid = [], array $deny_gid = [], int $id = null)
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
$this->uid = $uid;
|
||||||
|
$this->allow_cid = $allow_cid;
|
||||||
|
$this->allow_gid = $allow_gid;
|
||||||
|
$this->deny_cid = $deny_cid;
|
||||||
|
$this->deny_gid = $deny_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Entity with a new allowed_cid list (wipes the id because it isn't the same entity anymore)
|
||||||
|
*
|
||||||
|
* @param array $allow_cid
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function withAllowedContacts(array $allow_cid): PermissionSet
|
||||||
|
{
|
||||||
|
$clone = clone $this;
|
||||||
|
|
||||||
|
$clone->allow_cid = $allow_cid;
|
||||||
|
$clone->id = null;
|
||||||
|
|
||||||
|
return $clone;
|
||||||
|
}
|
||||||
|
}
|
58
src/Security/PermissionSet/Factory/PermissionSet.php
Normal file
58
src/Security/PermissionSet/Factory/PermissionSet.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Security\PermissionSet\Factory;
|
||||||
|
|
||||||
|
use Friendica\BaseFactory;
|
||||||
|
use Friendica\Capabilities\ICanCreateFromTableRow;
|
||||||
|
use Friendica\Security\PermissionSet\Entity;
|
||||||
|
use Friendica\Util\ACLFormatter;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class PermissionSet extends BaseFactory implements ICanCreateFromTableRow
|
||||||
|
{
|
||||||
|
/** @var ACLFormatter */
|
||||||
|
protected $formatter;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger, ACLFormatter $formatter)
|
||||||
|
{
|
||||||
|
parent::__construct($logger);
|
||||||
|
|
||||||
|
$this->formatter = $formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createFromTableRow(array $row): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
return new Entity\PermissionSet(
|
||||||
|
$row['uid'],
|
||||||
|
$this->formatter->expand($row['allow_cid'] ?? []),
|
||||||
|
$this->formatter->expand($row['allow_gid'] ?? []),
|
||||||
|
$this->formatter->expand($row['deny_cid'] ?? []),
|
||||||
|
$this->formatter->expand($row['deny_gid'] ?? []),
|
||||||
|
$row['id'] ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createFromString(
|
||||||
|
int $uid,
|
||||||
|
string $allow_cid = '',
|
||||||
|
string $allow_gid = '',
|
||||||
|
string $deny_cid = '',
|
||||||
|
string $deny_gid = '')
|
||||||
|
{
|
||||||
|
return new Entity\PermissionSet(
|
||||||
|
$uid,
|
||||||
|
$this->formatter->expand($allow_cid),
|
||||||
|
$this->formatter->expand($allow_gid),
|
||||||
|
$this->formatter->expand($deny_cid),
|
||||||
|
$this->formatter->expand($deny_gid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createPrototypeForUser(int $uid, string $allowCid): Entity\PermissionSet
|
||||||
|
{
|
||||||
|
return new Entity\PermissionSet(
|
||||||
|
$uid,
|
||||||
|
$this->formatter->expand($allowCid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue