2018-03-24 18:38:05 +00:00
< ? php
/**
2022-01-02 07:27:47 +00:00
* @ copyright Copyright ( C ) 2010 - 2022 , the Friendica project
2020-02-09 14:45:36 +00:00
*
* @ 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 / >.
*
2018-03-24 18:38:05 +00:00
*/
namespace Friendica\Core ;
2019-11-28 17:42:12 +00:00
use Friendica\App\Page ;
2018-07-20 12:19:26 +00:00
use Friendica\Database\DBA ;
2019-12-15 21:34:11 +00:00
use Friendica\DI ;
2018-03-24 18:38:05 +00:00
use Friendica\Model\Contact ;
2019-11-28 17:33:00 +00:00
use Friendica\Model\Group ;
2021-08-08 10:14:56 +00:00
use Friendica\Model\User ;
2018-03-24 18:38:05 +00:00
/**
* Handle ACL management and display
*/
2019-12-15 22:28:01 +00:00
class ACL
2018-03-24 18:38:05 +00:00
{
2021-08-08 10:14:56 +00:00
/**
* 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' ]);
}
2018-03-24 18:38:05 +00:00
/**
2020-09-03 14:01:58 +00:00
* Returns a select input tag for private message recipient
2018-03-24 18:38:05 +00:00
*
2020-09-03 14:01:58 +00:00
* @ param int $selected Existing recipien contact ID
2018-03-24 18:38:05 +00:00
* @ return string
2019-01-06 21:06:53 +00:00
* @ throws \Exception
2018-03-24 18:38:05 +00:00
*/
2022-02-22 15:44:30 +00:00
public static function getMessageContactSelectHTML ( int $selected = null ) : string
2018-03-24 18:38:05 +00:00
{
$o = '' ;
2020-09-03 14:01:58 +00:00
$page = DI :: page ();
2018-03-24 18:38:05 +00:00
2020-09-03 14:01:58 +00:00
$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' ));
2018-03-24 18:38:05 +00:00
2022-10-19 04:26:41 +00:00
$contacts = self :: getValidMessageRecipientsForUser ( Session :: getLocalUser ());
2018-03-24 18:38:05 +00:00
2020-09-03 14:01:58 +00:00
$tpl = Renderer :: getMarkupTemplate ( 'acl/message_recipient.tpl' );
$o = Renderer :: replaceMacros ( $tpl , [
'$contacts' => $contacts ,
'$selected' => $selected ,
]);
2018-03-24 18:38:05 +00:00
2021-11-19 21:47:49 +00:00
Hook :: callAll ( DI :: args () -> getModuleName () . '_post_recipient' , $o );
2018-03-24 18:38:05 +00:00
return $o ;
}
2022-02-22 15:44:30 +00:00
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 Contact :: selectToArray (
[ 'id' , 'name' , 'addr' , 'micro' , 'url' , 'nick' ],
DBA :: mergeConditions ( $condition , [ " `notify` != '' " ])
);
}
2020-09-07 23:27:32 +00:00
/**
* Returns a minimal ACL block for self - only permissions
*
* @ param int $localUserId
* @ param string $explanation
* @ return string
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function getSelfOnlyHTML ( int $localUserId , string $explanation )
{
$selfPublicContactId = Contact :: getPublicIdByUserId ( $localUserId );
$tpl = Renderer :: getMarkupTemplate ( 'acl/self_only.tpl' );
$o = Renderer :: replaceMacros ( $tpl , [
'$selfPublicContactId' => $selfPublicContactId ,
'$explanation' => $explanation ,
]);
return $o ;
}
2018-03-24 18:38:05 +00:00
/**
* Return the default permission of the provided user array
*
* @ param array $user
* @ return array Hash of contact id lists
2019-01-06 21:06:53 +00:00
* @ throws \Exception
2018-03-24 18:38:05 +00:00
*/
public static function getDefaultUserPermissions ( array $user = null )
{
2020-01-05 22:07:33 +00:00
$aclFormatter = DI :: aclFormatter ();
2018-03-24 18:38:05 +00:00
return [
2020-01-05 22:07:33 +00:00
'allow_cid' => Contact :: pruneUnavailable ( $aclFormatter -> expand ( $user [ 'allow_cid' ] ? ? '' )),
'allow_gid' => $aclFormatter -> expand ( $user [ 'allow_gid' ] ? ? '' ),
'deny_cid' => $aclFormatter -> expand ( $user [ 'deny_cid' ] ? ? '' ),
'deny_gid' => $aclFormatter -> expand ( $user [ 'deny_gid' ] ? ? '' ),
2018-03-24 18:38:05 +00:00
];
}
2019-11-28 17:33:00 +00:00
/**
* Returns the ACL list of contacts for a given user id
*
2020-01-14 02:58:01 +00:00
* @ param int $user_id
* @ param array $condition Additional contact lookup table conditions
2019-11-28 17:33:00 +00:00
* @ return array
* @ throws \Exception
*/
2020-01-14 02:58:01 +00:00
public static function getContactListByUserId ( int $user_id , array $condition = [])
2019-11-28 17:33:00 +00:00
{
2019-12-06 07:25:21 +00:00
$fields = [ 'id' , 'name' , 'addr' , 'micro' ];
$params = [ 'order' => [ 'name' ]];
2020-01-14 02:58:01 +00:00
$acl_contacts = Contact :: selectToArray (
$fields ,
array_merge ([
'uid' => $user_id ,
'self' => false ,
'blocked' => false ,
'archive' => false ,
'deleted' => false ,
'pending' => false ,
2021-02-17 18:59:19 +00:00
'network' => Protocol :: FEDERATED ,
2020-01-14 02:58:01 +00:00
'rel' => [ Contact :: FOLLOWER , Contact :: FRIEND ]
], $condition ),
$params
2019-11-28 17:33:00 +00:00
);
2019-12-06 07:25:21 +00:00
2020-01-14 02:58:01 +00:00
$acl_yourself = Contact :: selectFirst ( $fields , [ 'uid' => $user_id , 'self' => true ]);
2020-01-14 03:20:18 +00:00
$acl_yourself [ 'name' ] = DI :: l10n () -> t ( 'Yourself' );
2020-01-14 02:58:01 +00:00
$acl_contacts [] = $acl_yourself ;
2019-12-06 07:25:21 +00:00
$acl_forums = Contact :: selectToArray ( $fields ,
[ 'uid' => $user_id , 'self' => false , 'blocked' => false , 'archive' => false , 'deleted' => false ,
2021-02-17 18:59:19 +00:00
'network' => Protocol :: FEDERATED , 'pending' => false , 'contact-type' => Contact :: TYPE_COMMUNITY ], $params
2019-12-06 07:25:21 +00:00
);
$acl_contacts = array_merge ( $acl_forums , $acl_contacts );
2019-11-28 17:33:00 +00:00
array_walk ( $acl_contacts , function ( & $value ) {
$value [ 'type' ] = 'contact' ;
});
return $acl_contacts ;
}
/**
* Returns the ACL list of groups ( including meta - groups ) for a given user id
*
* @ param int $user_id
* @ return array
*/
public static function getGroupListByUserId ( int $user_id )
{
$acl_groups = [
[
'id' => Group :: FOLLOWERS ,
2020-01-18 19:52:34 +00:00
'name' => DI :: l10n () -> t ( 'Followers' ),
2019-11-28 17:33:00 +00:00
'addr' => '' ,
'micro' => 'images/twopeople.png' ,
'type' => 'group' ,
],
[
'id' => Group :: MUTUALS ,
2020-01-18 19:52:34 +00:00
'name' => DI :: l10n () -> t ( 'Mutuals' ),
2019-11-28 17:33:00 +00:00
'addr' => '' ,
'micro' => 'images/twopeople.png' ,
'type' => 'group' ,
]
];
foreach ( Group :: getByUserId ( $user_id ) as $group ) {
$acl_groups [] = [
'id' => $group [ 'id' ],
'name' => $group [ 'name' ],
'addr' => '' ,
'micro' => 'images/twopeople.png' ,
'type' => 'group' ,
];
}
return $acl_groups ;
}
2018-03-24 18:38:05 +00:00
/**
* Return the full jot ACL selector HTML
*
2020-01-14 02:58:01 +00:00
* @ param Page $page
2021-08-08 19:30:21 +00:00
* @ param int $uid User ID
2020-01-14 02:58:01 +00:00
* @ param bool $for_federation
* @ param array $default_permissions Static defaults permission array :
* [
2019-11-28 17:42:12 +00:00
* 'allow_cid' => [],
* 'allow_gid' => [],
* 'deny_cid' => [],
2020-02-22 08:54:28 +00:00
* 'deny_gid' => []
2020-01-14 02:58:01 +00:00
* ]
* @ param array $condition
* @ param string $form_prefix
2018-03-24 18:38:05 +00:00
* @ return string
2019-01-06 21:06:53 +00:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-03-24 18:38:05 +00:00
*/
2020-01-14 02:58:01 +00:00
public static function getFullSelectorHTML (
Page $page ,
2021-08-08 19:30:21 +00:00
int $uid = null ,
2020-01-14 02:58:01 +00:00
bool $for_federation = false ,
array $default_permissions = [],
array $condition = [],
$form_prefix = ''
) {
2021-08-08 19:30:21 +00:00
if ( empty ( $uid )) {
2019-12-13 18:29:06 +00:00
return '' ;
}
2020-01-14 02:58:01 +00:00
static $input_group_id = 0 ;
2021-08-08 19:30:21 +00:00
$user = User :: getById ( $uid );
2020-01-14 02:58:01 +00:00
$input_group_id ++ ;
2019-11-28 17:42:12 +00:00
$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' ));
2018-08-14 22:43:27 +00:00
// Defaults user permissions
if ( empty ( $default_permissions )) {
$default_permissions = self :: getDefaultUserPermissions ( $user );
2018-07-20 18:07:54 +00:00
}
2019-12-03 11:59:51 +00:00
$default_permissions = [
'allow_cid' => $default_permissions [ 'allow_cid' ] ? ? [],
'allow_gid' => $default_permissions [ 'allow_gid' ] ? ? [],
'deny_cid' => $default_permissions [ 'deny_cid' ] ? ? [],
'deny_gid' => $default_permissions [ 'deny_gid' ] ? ? [],
];
2019-11-28 17:42:12 +00:00
if ( count ( $default_permissions [ 'allow_cid' ])
+ count ( $default_permissions [ 'allow_gid' ])
+ count ( $default_permissions [ 'deny_cid' ])
+ count ( $default_permissions [ 'deny_gid' ])) {
$visibility = 'custom' ;
} else {
$visibility = 'public' ;
// Default permission display for custom panel
$default_permissions [ 'allow_gid' ] = [ Group :: FOLLOWERS ];
}
2019-03-25 02:40:50 +00:00
$jotnets_fields = [];
2019-11-28 17:42:12 +00:00
if ( $for_federation ) {
2020-01-19 20:21:13 +00:00
if ( function_exists ( 'imap_open' ) && ! DI :: config () -> get ( 'system' , 'imap_disabled' )) {
2019-11-29 20:55:52 +00:00
$mailacct = DBA :: selectFirst ( 'mailacct' , [ 'pubmail' ], [ '`uid` = ? AND `server` != ""' , $user [ 'uid' ]]);
2018-07-21 12:46:04 +00:00
if ( DBA :: isResult ( $mailacct )) {
2019-03-25 02:40:50 +00:00
$jotnets_fields [] = [
'type' => 'checkbox' ,
'field' => [
'pubmail_enable' ,
2020-01-18 19:52:34 +00:00
DI :: l10n () -> t ( 'Post to Email' ),
2020-02-22 08:54:28 +00:00
! empty ( $mailacct [ 'pubmail' ])
2019-03-25 02:40:50 +00:00
]
];
2020-02-22 08:54:28 +00:00
2018-03-24 18:38:05 +00:00
}
}
2020-02-22 08:54:28 +00:00
Hook :: callAll ( 'jot_networks' , $jotnets_fields );
2018-03-24 18:38:05 +00:00
}
2019-03-25 02:40:50 +00:00
2020-01-14 02:58:01 +00:00
$acl_contacts = self :: getContactListByUserId ( $user [ 'uid' ], $condition );
2019-11-28 17:42:12 +00:00
$acl_groups = self :: getGroupListByUserId ( $user [ 'uid' ]);
$acl_list = array_merge ( $acl_groups , $acl_contacts );
2020-01-14 02:58:01 +00:00
$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' ,
];
2020-09-03 13:58:07 +00:00
$tpl = Renderer :: getMarkupTemplate ( 'acl/full_selector.tpl' );
2018-10-31 14:35:50 +00:00
$o = Renderer :: replaceMacros ( $tpl , [
2020-01-18 19:52:34 +00:00
'$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.' ),
'$custom_title' => DI :: l10n () -> t ( 'Limited/Private' ),
'$custom_desc' => DI :: l10n () -> t ( 'This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.' ),
'$allow_label' => DI :: l10n () -> t ( 'Show to:' ),
'$deny_label' => DI :: l10n () -> t ( 'Except to:' ),
'$emailcc' => DI :: l10n () -> t ( 'CC: email addresses' ),
'$emtitle' => DI :: l10n () -> t ( 'Example: bob@example.com, mary@example.com' ),
'$jotnets_summary' => DI :: l10n () -> t ( 'Connectors' ),
2019-11-28 17:42:12 +00:00
'$visibility' => $visibility ,
'$acl_contacts' => $acl_contacts ,
'$acl_groups' => $acl_groups ,
'$acl_list' => $acl_list ,
'$contact_allow' => implode ( ',' , $default_permissions [ 'allow_cid' ]),
'$group_allow' => implode ( ',' , $default_permissions [ 'allow_gid' ]),
'$contact_deny' => implode ( ',' , $default_permissions [ 'deny_cid' ]),
'$group_deny' => implode ( ',' , $default_permissions [ 'deny_gid' ]),
'$for_federation' => $for_federation ,
'$jotnets_fields' => $jotnets_fields ,
2020-01-14 02:58:01 +00:00
'$input_names' => $input_names ,
'$input_group_id' => $input_group_id ,
2018-03-24 18:38:05 +00:00
]);
return $o ;
}
2022-01-06 07:34:16 +00:00
/**
* 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 <x><y><z> 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 <x><y><z> 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 ;
}
2018-03-24 18:38:05 +00:00
}