* 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
- * 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)
*
* Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
interface ICanCreateFromTableRow
{
/**
- * Returns the correcponding Entity given a table row record
+ * Returns the corresponding Entity given a table row record
*
* @param array $row
* @return BaseEntity
+++ /dev/null
-<?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
-{
-
-}
namespace Friendica\Core;
-use Friendica\App;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
-use Friendica\Model\Contact;
use Friendica\Model\Photo;
use Friendica\Object\Image;
-use Friendica\Repository\PermissionSet;
+use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
DI::profileField()->migrateFromLegacyProfile($profile);
}
- ///@TODO Replace with permissionset import
- $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);
+ $permissionSet = DI::permissionSet()->selectDefaultForUser($newuid);
foreach ($account['profile_fields'] ?? [] as $profile_field) {
$profile_field['uid'] = $newuid;
///@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) {
Logger::info("uimport:insert profile field " . $profile_field['id'] . " : ERROR : " . DBA::errorMessage());
namespace Friendica;
use Dice\Dice;
+use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Psr\Log\LoggerInterface;
/**
}
/**
- * @return Repository\PermissionSet
+ * @return 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);
}
/**
use Friendica\Model\APContact;
use Friendica\Model\Contact;
use Friendica\Network\HTTPException;
-use Friendica\Repository\PermissionSet;
use Friendica\Repository\ProfileField;
+use Friendica\Security\PermissionSet\Depository\PermissionSet;
use ImagickException;
use Psr\Log\LoggerInterface;
}
// Creates or assigns the permission set
- $item['psid'] = PermissionSet::getIdFromACL(
- $item['uid'],
- $item['allow_cid'],
- $item['allow_gid'],
- $item['deny_cid'],
- $item['deny_gid']
- );
+ $item['psid'] = DI::permissionSet()->selectOrCreate(
+ DI::permissionSetFactory()->createFromString(
+ $item['uid'],
+ $item['allow_cid'],
+ $item['allow_gid'],
+ $item['deny_cid'],
+ $item['deny_gid']
+ ))->id;
if (!empty($item['extid'])) {
$item['external-id'] = ItemURI::getIdByURI($item['extid']);
$private = self::PUBLIC;
}
- $psid = PermissionSet::getIdFromACL(
- $user['uid'],
- $user['allow_cid'],
- $user['allow_gid'],
- $user['deny_cid'],
- $user['deny_gid']
- );
+ $permissionSet = DI::permissionSet()->selectOrCreate(
+ DI::permissionSetFactory()->createFromString(
+ $user['uid'],
+ $user['allow_cid'],
+ $user['allow_gid'],
+ $user['deny_cid'],
+ $user['deny_gid']
+ ));
$forum_mode = ($prvgroup ? 2 : 1);
$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']]);
Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, (int)$item['uri-id'], (int)$item['uid']);
$condition = [];
} elseif ($remote_user) {
// Authenticated visitor - fetch the matching permissionsets
- $set = PermissionSet::get($owner_id, $remote_user);
+ $permissionSets = DI::permissionSet()->selectByContactId($remote_user, $owner_id);
if (!empty($set)) {
$condition = ["(`private` != ? OR (`private` = ? AND `wall`
AND `psid` IN (" . implode(', ', array_fill(0, count($set), '?')) . ")))",
self::PRIVATE, self::PRIVATE];
- $condition = array_merge($condition, $set);
+ $condition = array_merge($condition, $permissionSets->column('id'));
}
}
* If pre-verified, the caller is expected to have already
* 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)) {
- $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 {
$sql_set = '';
}
+++ /dev/null
-<?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');
- }
-}
use Friendica\BaseModel;
use Friendica\Database\Database;
-use Friendica\Network\HTTPException;
+use Friendica\Security\PermissionSet\Entity\PermissionSet;
use Psr\Log\LoggerInterface;
/**
/** @var PermissionSet */
private $permissionset;
- /** @var \Friendica\Repository\PermissionSet */
- private $permissionSetRepository;
+ /** @var \Friendica\Security\PermissionSet\Depository\PermissionSet */
+ 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);
- $this->permissionSetRepository = $permissionSetRepository;
+ $this->permissionSetDepository = $permissionSetDepository;
}
public function __get($name)
switch ($name) {
case 'permissionset':
- $this->permissionset =
- $this->permissionset ??
- $this->permissionSetRepository->selectFirst(['id' => $this->psid, 'uid' => $this->uid]);
+ $this->permissionset = $this->permissionset ?? $this->permissionSetDepository->selectOneById($this->psid);
$return = $this->permissionset;
break;
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']);
if (!empty($permissionSets)) {
$psid = array_merge($permissionSets->column('id'),
- [DI::permissionSet()->getIdFromACL($item['uid'], '', '', '', '')]);
+ [DI::permissionSet()->selectEmptyForUser($item['uid'])]);
$validated = in_array($item['psid'], $psid);
}
}
use Friendica\Model\Profile;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException;
-use Friendica\Repository\PermissionSet;
+use Friendica\Security\PermissionSet\Depository\PermissionSet;
/**
* API endpoint: /api/friendica/profile/show
}
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_gid'] = $permissionSet->allow_gid;
$model['deny_cid'] = $permissionSet->deny_cid;
exit;
}
- $aclFormatter = DI::aclFormatter();
-
- $allowed_users = $aclFormatter->expand($model['allow_cid']);
- $allowed_groups = $aclFormatter->expand($model['allow_gid']);
- $deny_users = $aclFormatter->expand($model['deny_cid']);
- $deny_groups = $aclFormatter->expand($model['deny_gid']);
+ $allowed_users = $model['allow_cid'];
+ $allowed_groups = $model['allow_gid'];
+ $deny_users = $model['deny_cid'];
+ $deny_groups = $model['deny_gid'];
$o = DI::l10n()->t('Visible to:') . '<br />';
$l = [];
$permissionSets = DI::permissionSet()->selectByContactId($remote_user, $profile['uid']);
if (!empty($permissionSets)) {
$condition = ['psid' => array_merge($permissionSets->column('id'),
- [DI::permissionSet()->getIdFromACL($profile['uid'], '', '', '', '')])];
+ [DI::permissionSet()->selectEmptyForUser($profile['uid'])])];
}
} elseif ($profile['uid'] == local_user()) {
$condition = [];
use Friendica\Core\Theme;
use Friendica\Database\DBA;
use Friendica\DI;
+use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Model\ProfileField;
use Friendica\Model\User;
$profileFields = DI::profileField()->selectByUserId(local_user());
foreach ($profileFields as $profileField) {
/** @var ProfileField $profileField */
- $defaultPermissions = ACL::getDefaultUserPermissions($profileField->permissionset->toArray());
+ $defaultPermissions = $profileField->permissionset->withAllowedContacts(
+ Contact::pruneUnavailable($profileField->permissionset->allow_cid)
+ );
$custom_fields[] = [
'id' => $profileField->id,
DI::page(),
$a->getLoggedInUserId(),
false,
- $defaultPermissions,
+ $defaultPermissions->toArray(),
['network' => Protocol::DFRN],
'profile_field[' . $profileField->id . ']'
),
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $owner['uid']);
if (!empty($permissionSets)) {
$condition = ['psid' => array_merge($permissionSets->column('id'),
- [DI::permissionSet()->getIdFromACL($owner['uid'], '', '', '', '')])];
+ [DI::permissionSet()->selectEmptyForUser($owner['uid'])])];
}
}
}
+++ /dev/null
-<?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);
- }
-}
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Model;
-use Friendica\Util\ACLFormatter;
+use Friendica\Security\PermissionSet\Depository\PermissionSet;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
/** @var PermissionSet */
private $permissionSet;
- /** @var ACLFormatter */
- private $aclFormatter;
+ /** @var \Friendica\Security\PermissionSet\Factory\PermissionSet */
+ private $permissionSetFactory;
/** @var 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);
- $this->permissionSet = $permissionSet;
- $this->aclFormatter = $aclFormatter;
- $this->l10n = $l10n;
+ $this->permissionSet = $permissionSet;
+ $this->permissionSetFactory = $permissionSetFactory;
+ $this->l10n = $l10n;
}
/**
return parent::update($model);
}
-
+
/**
* @param int $uid User Id
* @param Collection\ProfileFields $profileFields Collection of existing profile fields
// Creation of the new field
if (!empty($profileFieldInputs['new']['label'])) {
- $psid = $this->permissionSet->getIdFromACL(
+ $psid = $this->permissionSet->selectOrCreate($this->permissionSetFactory->createFromString(
$uid,
- $this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs['new']['group_allow'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs['new']['group_deny'] ?? '')
- );
+ $profileFieldInputs['new']['contact_allow'] ?? '',
+ $profileFieldInputs['new']['group_allow'] ?? '',
+ $profileFieldInputs['new']['contact_deny'] ?? '',
+ $profileFieldInputs['new']['group_deny'] ?? ''
+ ))->id;
$newProfileField = $this->insert([
- 'uid' => $uid,
+ 'uid' => $uid,
'label' => $profileFieldInputs['new']['label'],
'value' => $profileFieldInputs['new']['value'],
- 'psid' => $psid,
+ 'psid' => $psid,
'order' => $profileFieldOrder['new'],
]);
$profileFieldInputs[$newProfileField->id] = $profileFieldInputs['new'];
- $profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new'];
+ $profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new'];
$profileFields[] = $newProfileField;
}
// Update existing profile fields from form values
$profileFields = $profileFields->map(function (Model\ProfileField $profileField) use ($uid, &$profileFieldInputs, &$profileFieldOrder) {
if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) {
- $psid = $this->permissionSet->getIdFromACL(
+ $psid = $this->permissionSet->selectOrCreate($this->permissionSetFactory->createFromString(
$uid,
- $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_allow'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_allow'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_deny'] ?? ''),
- $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_deny'] ?? '')
- );
+ $profileFieldInputs[$profileField->id]['contact_allow'] ?? '',
+ $profileFieldInputs[$profileField->id]['group_allow'] ?? '',
+ $profileFieldInputs[$profileField->id]['contact_deny'] ?? '',
+ $profileFieldInputs[$profileField->id]['group_deny'] ?? ''
+ ))->id;
- $profileField->psid = $psid;
+ $profileField->psid = $psid;
$profileField->label = $profileFieldInputs[$profileField->id]['label'];
$profileField->value = $profileFieldInputs[$profileField->id]['value'];
$profileField->order = $profileFieldOrder[$profileField->id];
return;
}
+ $contacts = [];
+
if (!$profile['is-default']) {
$contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'profile-id' => $profile['id']]);
if (!count($contacts)) {
// No contact visibility selected defaults to user-only permission
$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;
foreach ($custom_fields as $field => $label) {
if (!empty($profile[$field]) && $profile[$field] > DBA::NULL_DATE && $profile[$field] > DBA::NULL_DATETIME) {
$this->insert([
- 'uid' => $profile['uid'],
- 'psid' => $psid,
+ 'uid' => $profile['uid'],
+ 'psid' => $psid,
'order' => $order++,
'label' => trim($label, ':'),
'value' => $profile[$field],
if ($profile['is-default']) {
$profile['profile-name'] = null;
- $profile['is-default'] = null;
+ $profile['is-default'] = null;
$this->dba->update('profile', $profile, ['id' => $profile['id']]);
} elseif (!empty($profile['id'])) {
$this->dba->delete('profile', ['id' => $profile['id']]);
--- /dev/null
+<?php
+
+namespace Friendica\Security\PermissionSet\Collection;
+
+use Friendica\BaseCollection;
+
+class PermissionSets extends BaseCollection
+{
+
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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)
+ );
+ }
+}