X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FCore%2FACL.php;h=a2db32afc459c44cc21bcaa6315230d7411cccb6;hb=22e2578b23e8e14f5b341e20e5f06585df6715e7;hp=1757c50d73ff1e7cb949b0ac813c7930b96905ff;hpb=ab8997f9db910ba70c592bf106a7f5fc41a55b2d;p=friendica.git diff --git a/src/Core/ACL.php b/src/Core/ACL.php index 1757c50d73..a2db32afc4 100644 --- a/src/Core/ACL.php +++ b/src/Core/ACL.php @@ -1,7 +1,22 @@ . + * */ namespace Friendica\Core; @@ -11,197 +26,91 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Group; +use Friendica\Model\User; /** * Handle ACL management and display - * - * @author Hypolite Petovan */ class ACL { /** - * Returns a select input tag with all the contact of the local user + * Returns the default lock state for the given user id + * @param int $uid + * @return bool "true" if the default settings are non public + */ + public static function getLockstateForUserId(int $uid) + { + $user = User::getById($uid, ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']); + return !empty($user['allow_cid']) || !empty($user['allow_gid']) || !empty($user['deny_cid']) || !empty($user['deny_gid']); + } + + /** + * Returns a select input tag for private message recipient * - * @param string $selname Name attribute of the select input tag - * @param string $selclass Class attribute of the select input tag - * @param array $options Available options: - * - size: length of the select box - * - mutual_friends: Only used for the hook - * - single: Only used for the hook - * - exclude: Only used for the hook - * @param array $preselected Contact ID that should be already selected + * @param int $selected Existing recipien contact ID * @return string * @throws \Exception */ - public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = []) + public static function getMessageContactSelectHTML(int $selected = null): string { - $a = DI::app(); - - $networks = null; - - $size = ($options['size'] ?? 0) ?: 4; - $mutual = !empty($options['mutual_friends']); - $single = !empty($options['single']) && empty($options['multiple']); - $exclude = $options['exclude'] ?? false; - - switch (($options['networks'] ?? '') ?: Protocol::PHANTOM) { - case 'DFRN_ONLY': - $networks = [Protocol::DFRN]; - break; - - case 'PRIVATE': - $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]; - break; - - case 'TWO_WAY': - if (!empty($a->user['prvnets'])) { - $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]; - } else { - $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA, Protocol::OSTATUS]; - } - break; - - default: /// @TODO Maybe log this call? - break; - } - - $x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks]; - - Hook::callAll('contact_select_options', $x); - $o = ''; - $sql_extra = ''; - - if (!empty($x['mutual'])) { - $sql_extra .= sprintf(" AND `rel` = %d ", intval(Contact::FRIEND)); - } - - if (!empty($x['exclude'])) { - $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude'])); - } - - if (!empty($x['networks'])) { - /// @TODO rewrite to foreach() - array_walk($x['networks'], function (&$value) { - $value = "'" . DBA::escape($value) . "'"; - }); - $str_nets = implode(',', $x['networks']); - $sql_extra .= " AND `network` IN ( $str_nets ) "; - } - - $tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : ''); + $page = DI::page(); - if (!empty($x['single'])) { - $o .= "\r\n"; - } - - $stmt = DBA::p("SELECT `id`, `name`, `url`, `network` FROM `contact` - WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND NOT `deleted` AND `notify` != '' - $sql_extra - ORDER BY `name` ASC ", intval(local_user()) - ); - - $contacts = DBA::toArray($stmt); - - $arr = ['contact' => $contacts, 'entry' => $o]; + $page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js')); + $page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js')); + $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css')); + $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css')); - // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' - Hook::callAll(DI::module()->getName() . '_pre_' . $selname, $arr); + $contacts = self::getValidMessageRecipientsForUser(DI::userSession()->getLocalUserId()); - if (DBA::isResult($contacts)) { - foreach ($contacts as $contact) { - if (in_array($contact['id'], $preselected)) { - $selected = ' selected="selected" '; - } else { - $selected = ''; - } + $tpl = Renderer::getMarkupTemplate('acl/message_recipient.tpl'); + $o = Renderer::replaceMacros($tpl, [ + '$contacts' => $contacts, + '$selected' => $selected, + ]); - $trimmed = mb_substr($contact['name'], 0, 20); + Hook::callAll(DI::args()->getModuleName() . '_post_recipient', $o); - $o .= "\r\n"; - } - } - - $o .= '' . PHP_EOL; + return $o; + } - Hook::callAll(DI::module()->getName() . '_post_' . $selname, $o); + public static function getValidMessageRecipientsForUser(int $uid): array + { + $condition = [ + 'uid' => $uid, + 'self' => false, + 'blocked' => false, + 'pending' => false, + 'archive' => false, + 'deleted' => false, + 'rel' => [Contact::FOLLOWER, Contact::SHARING, Contact::FRIEND], + 'network' => Protocol::SUPPORT_PRIVATE, + ]; - return $o; + return Contact::selectToArray( + ['id', 'name', 'addr', 'micro', 'url', 'nick'], + DBA::mergeConditions($condition, ["`notify` != ''"]) + ); } /** - * Returns a select input tag with all the contact of the local user + * Returns a minimal ACL block for self-only permissions * - * @param string $selname Name attribute of the select input tag - * @param string $selclass Class attribute of the select input tag - * @param array $preselected Contact IDs that should be already selected - * @param int $size Length of the select box - * @param int $tabindex Select input tag tabindex attribute + * @param int $localUserId + * @param string $explanation * @return string - * @throws \Exception + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null) + public static function getSelfOnlyHTML(int $localUserId, string $explanation) { - $a = DI::app(); - - $o = ''; - - // When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector - // to one recipient. By default our selector allows multiple selects amongst all contacts. - $sql_extra = sprintf(" AND `rel` = %d ", intval(Contact::FRIEND)); - $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", Protocol::DFRN, Protocol::DIASPORA); - - $tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : ''; - - $hidepreselected = ''; - if ($preselected) { - $sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")"; - $hidepreselected = ' style="display: none;"'; - } - - $o .= "' . PHP_EOL; - - if ($preselected) { - $o .= implode(', ', $receiverlist); - } - - Hook::callAll(DI::module()->getName() . '_post_' . $selname, $o); + $tpl = Renderer::getMarkupTemplate('acl/self_only.tpl'); + $o = Renderer::replaceMacros($tpl, [ + '$selfPublicContactId' => $selfPublicContactId, + '$explanation' => $explanation, + ]); return $o; } @@ -228,22 +137,38 @@ class ACL /** * Returns the ACL list of contacts for a given user id * - * @param int $user_id + * @param int $user_id + * @param array $condition Additional contact lookup table conditions * @return array * @throws \Exception */ - public static function getContactListByUserId(int $user_id) + public static function getContactListByUserId(int $user_id, array $condition = []) { $fields = ['id', 'name', 'addr', 'micro']; $params = ['order' => ['name']]; - $acl_contacts = Contact::selectToArray($fields, - ['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false, - 'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]], $params + $acl_contacts = Contact::selectToArray( + $fields, + array_merge([ + 'uid' => $user_id, + 'self' => false, + 'blocked' => false, + 'archive' => false, + 'deleted' => false, + 'pending' => false, + 'network' => Protocol::FEDERATED, + 'rel' => [Contact::FOLLOWER, Contact::FRIEND] + ], $condition), + $params ); + $acl_yourself = Contact::selectFirst($fields, ['uid' => $user_id, 'self' => true]); + $acl_yourself['name'] = DI::l10n()->t('Yourself'); + + $acl_contacts[] = $acl_yourself; + $acl_forums = Contact::selectToArray($fields, ['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false, - 'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params + 'network' => Protocol::FEDERATED, 'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params ); $acl_contacts = array_merge($acl_forums, $acl_contacts); @@ -295,26 +220,39 @@ class ACL /** * Return the full jot ACL selector HTML * - * @param Page $page - * @param array $user User array - * @param bool $for_federation - * @param array $default_permissions Static defaults permission array: - * [ + * @param Page $page + * @param int $uid User ID + * @param bool $for_federation + * @param array $default_permissions Static defaults permission array: + * [ * 'allow_cid' => [], * 'allow_gid' => [], * 'deny_cid' => [], - * 'deny_gid' => [], - * 'hidewall' => true/false - * ] + * 'deny_gid' => [] + * ] + * @param array $condition + * @param string $form_prefix * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getFullSelectorHTML(Page $page, array $user = null, bool $for_federation = false, array $default_permissions = []) - { - if (empty($user['uid'])) { + public static function getFullSelectorHTML( + Page $page, + int $uid = null, + bool $for_federation = false, + array $default_permissions = [], + array $condition = [], + $form_prefix = '' + ) { + if (empty($uid)) { return ''; } + static $input_group_id = 0; + + $user = User::getById($uid); + + $input_group_id++; + $page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js')); $page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js')); $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css')); @@ -330,7 +268,6 @@ class ACL 'allow_gid' => $default_permissions['allow_gid'] ?? [], 'deny_cid' => $default_permissions['deny_cid'] ?? [], 'deny_gid' => $default_permissions['deny_gid'] ?? [], - 'hidewall' => $default_permissions['hidewall'] ?? false, ]; if (count($default_permissions['allow_cid']) @@ -346,40 +283,39 @@ class ACL $jotnets_fields = []; if ($for_federation) { - $mail_enabled = false; - $pubmail_enabled = false; - - if (function_exists('imap_open') && !Config::get('system', 'imap_disabled')) { + if (function_exists('imap_open') && !DI::config()->get('system', 'imap_disabled')) { $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', $user['uid']]); if (DBA::isResult($mailacct)) { - $mail_enabled = true; - $pubmail_enabled = !empty($mailacct['pubmail']); - } - } - - if (!$default_permissions['hidewall']) { - if ($mail_enabled) { $jotnets_fields[] = [ 'type' => 'checkbox', 'field' => [ 'pubmail_enable', DI::l10n()->t('Post to Email'), - $pubmail_enabled + !empty($mailacct['pubmail']) ] ]; + } - - Hook::callAll('jot_networks', $jotnets_fields); } + Hook::callAll('jot_networks', $jotnets_fields); } - $acl_contacts = self::getContactListByUserId($user['uid']); + $acl_contacts = self::getContactListByUserId($user['uid'], $condition); $acl_groups = self::getGroupListByUserId($user['uid']); $acl_list = array_merge($acl_groups, $acl_contacts); - $tpl = Renderer::getMarkupTemplate('acl_selector.tpl'); + $input_names = [ + 'visibility' => $form_prefix ? $form_prefix . '[visibility]' : 'visibility', + 'group_allow' => $form_prefix ? $form_prefix . '[group_allow]' : 'group_allow', + 'contact_allow' => $form_prefix ? $form_prefix . '[contact_allow]' : 'contact_allow', + 'group_deny' => $form_prefix ? $form_prefix . '[group_deny]' : 'group_deny', + 'contact_deny' => $form_prefix ? $form_prefix . '[contact_deny]' : 'contact_deny', + 'emailcc' => $form_prefix ? $form_prefix . '[emailcc]' : 'emailcc', + ]; + + $tpl = Renderer::getMarkupTemplate('acl/full_selector.tpl'); $o = Renderer::replaceMacros($tpl, [ '$public_title' => DI::l10n()->t('Public'), '$public_desc' => DI::l10n()->t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'), @@ -390,7 +326,6 @@ class ACL '$emailcc' => DI::l10n()->t('CC: email addresses'), '$emtitle' => DI::l10n()->t('Example: bob@example.com, mary@example.com'), '$jotnets_summary' => DI::l10n()->t('Connectors'), - '$jotnets_disabled_label' => DI::l10n()->t('Connectors disabled, since "%s" is enabled.', DI::l10n()->t('Hide your profile details from unknown viewers?')), '$visibility' => $visibility, '$acl_contacts' => $acl_contacts, '$acl_groups' => $acl_groups, @@ -401,9 +336,68 @@ class ACL '$group_deny' => implode(',', $default_permissions['deny_gid']), '$for_federation' => $for_federation, '$jotnets_fields' => $jotnets_fields, - '$user_hidewall' => $default_permissions['hidewall'], + '$input_names' => $input_names, + '$input_group_id' => $input_group_id, ]); return $o; } + + /** + * Checks the validity of the given ACL string + * + * @param string $acl_string + * @param int $uid + * @return bool + * @throws Exception + */ + public static function isValidContact($acl_string, $uid) + { + if (empty($acl_string)) { + return true; + } + + // split into array of cids + preg_match_all('/<[A-Za-z0-9]+>/', $acl_string, $array); + + // check for each cid if the contact is valid for the given user + $cid_array = $array[0]; + foreach ($cid_array as $cid) { + $cid = str_replace(['<', '>'], ['', ''], $cid); + if (!DBA::exists('contact', ['id' => $cid, 'uid' => $uid])) { + return false; + } + } + + return true; + } + + /** + * Checks the validity of the given ACL string + * + * @param string $acl_string + * @param int $uid + * @return bool + * @throws Exception + */ + public static function isValidGroup($acl_string, $uid) + { + if (empty($acl_string)) { + return true; + } + + // split into array of cids + preg_match_all('/<[A-Za-z0-9]+>/', $acl_string, $array); + + // check for each cid if the contact is valid for the given user + $gid_array = $array[0]; + foreach ($gid_array as $gid) { + $gid = str_replace(['<', '>'], ['', ''], $gid); + if (!DBA::exists('group', ['id' => $gid, 'uid' => $uid, 'deleted' => false])) { + return false; + } + } + + return true; + } }