streams/Zotlabs/Module/Acl.php

366 lines
11 KiB
PHP
Raw Normal View History

2016-04-19 03:38:38 +00:00
<?php
2016-04-19 03:38:38 +00:00
namespace Zotlabs\Module;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\AccessList;
2019-11-21 02:50:05 +00:00
use Zotlabs\Web\Controller;
2018-07-03 23:40:54 +00:00
require_once('include/acl_selectors.php');
/**
* @brief ACL selector json backend.
*
* This module provides JSON lists of connections and local/remote channels
* (xchans) to populate various tools such as the ACL (AccessControlList) popup
* and various auto-complete functions (such as email recipients, search, and
* mention targets.
*
* There are two primary output structural formats. One for the ACL widget and
* the other for auto-completion.
*
* Many of the behaviour variations are triggered on the use of single character
* keys however this functionality has grown in an ad-hoc manner and has gotten
* quite messy over time.
*/
2019-11-21 02:50:05 +00:00
class Acl extends Controller {
2016-04-19 03:38:38 +00:00
function init() {
2019-11-19 23:01:19 +00:00
// logger('mod_acl: ' . print_r($_REQUEST,true),LOGGER_DATA);
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
$search = (x($_REQUEST,'search') ? $_REQUEST['search'] : '');
$type = (x($_REQUEST,'type') ? $_REQUEST['type'] : '');
$noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
// $type =
// '' => standard ACL request
// 'g' => Groups only ACL request
// 'f' => forums only ACL request
// 'c' => Connections only ACL request or editor (textarea) mention request
// $_REQUEST['search'] contains ACL search text.
// $type =
// 'm' => autocomplete private mail recipient (checks post_mail permission)
// 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos)
// 'x' => nav search bar autocomplete (match any xchan)
// 'z' => autocomplete any xchan, but also include abook_alias, requires non-zero local_channel()
// and also contains xid without urlencode, used specifically by activity_filter widget
// $_REQUEST['query'] contains autocomplete search text.
2016-04-19 03:38:38 +00:00
// The different autocomplete libraries use different names for the search text
// parameter. Internally we'll use $search to represent the search text no matter
// what request variable it was attached to.
2016-04-19 03:38:38 +00:00
2019-11-21 02:50:05 +00:00
if (array_key_exists('query',$_REQUEST)) {
2016-04-19 03:38:38 +00:00
$search = $_REQUEST['query'];
}
2019-11-21 02:50:05 +00:00
if ( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ]))) {
killme();
2019-11-21 02:50:05 +00:00
}
2016-07-14 02:53:28 +00:00
$permitted = [];
2020-09-07 05:46:07 +00:00
if (in_array($type, [ 'm', 'a', 'f' ])) {
2016-07-14 02:53:28 +00:00
// These queries require permission checking. We'll create a simple array of xchan_hash for those with
// the requisite permissions which we can check against.
2018-05-26 22:12:02 +00:00
$x = q("select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s'",
2016-07-14 02:53:28 +00:00
intval(local_channel()),
2018-05-24 05:50:33 +00:00
dbesc(($type === 'm') ? '%post_mail%' : '%tag_deliver%')
2016-07-14 02:53:28 +00:00
);
$permitted = ids_to_array($x,'xchan');
}
2019-11-21 02:50:05 +00:00
if ($search) {
2018-09-26 00:47:43 +00:00
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
2020-06-18 00:54:52 +00:00
// sql_extra2 is typically used when we don't have a local_channel - so we are not search abook_alias
$sql_extra2 = " AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
2019-09-19 22:30:17 +00:00
// This horrible mess is needed because position also returns 0 if nothing is found.
// Would be MUCH easier if it instead returned a very large value
// Otherwise we could just
// order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)).
$order_extra2 = "CASE WHEN xchan_name LIKE "
. protect_sprintf( "'%" . dbesc($search) . "%'" )
. " then POSITION('" . protect_sprintf(dbesc($search))
2018-03-15 01:42:07 +00:00
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR abook_alias like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
2019-09-19 22:30:17 +00:00
$sql_extra4 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . " OR abook_alias LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'") . ") ";
}
else {
2019-09-19 22:30:17 +00:00
$sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = "";
2016-04-19 03:38:38 +00:00
}
2019-11-21 02:50:05 +00:00
$groups = [];
$contacts = [];
2016-04-19 03:38:38 +00:00
2019-11-21 02:50:05 +00:00
if ($type == '' || $type == 'g') {
// Normal privacy groups
2018-09-26 00:47:43 +00:00
$r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname
FROM pgrp, pgrp_member
WHERE pgrp.deleted = 0 AND pgrp.uid = %d
AND pgrp_member.gid = pgrp.id
2016-04-19 03:38:38 +00:00
$sql_extra
2018-09-26 00:47:43 +00:00
GROUP BY pgrp.id
ORDER BY pgrp.gname
2016-04-19 03:38:38 +00:00
LIMIT %d OFFSET %d",
intval(local_channel()),
intval($count),
intval($start)
);
2016-06-10 05:07:27 +00:00
2019-11-21 02:50:05 +00:00
if ($r) {
foreach ($r as $g) {
2019-10-02 01:29:39 +00:00
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id']));
2019-11-21 02:50:05 +00:00
$groups[] = [
2016-06-10 05:07:27 +00:00
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
2019-10-02 01:29:39 +00:00
"uids" => AccessList::members_xchan(local_channel(),$g['id']),
2016-06-10 05:07:27 +00:00
"link" => ''
2019-11-21 02:50:05 +00:00
];
2016-06-10 05:07:27 +00:00
}
2016-04-19 03:38:38 +00:00
}
}
2019-11-21 02:50:05 +00:00
if ($type == '' || $type == 'c' || $type === 'f') {
2020-09-07 05:46:07 +00:00
2016-04-19 03:38:38 +00:00
// Getting info from the abook is better for local users because it contains info about permissions
2019-11-21 02:50:05 +00:00
if (local_channel()) {
2016-07-15 03:26:22 +00:00
// add connections
2019-09-19 22:30:17 +00:00
2019-03-06 01:27:16 +00:00
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, xchan_type, abook_flags, abook_self
2016-04-19 03:38:38 +00:00
FROM abook left join xchan on abook_xchan = xchan_hash
2020-09-07 05:46:07 +00:00
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc limit $count" ,
2016-04-19 03:38:38 +00:00
intval(local_channel())
);
2019-09-19 22:30:17 +00:00
2019-11-21 02:50:05 +00:00
if($r && $r2) {
2016-07-15 03:26:22 +00:00
$r = array_merge($r2,$r);
2019-11-21 02:50:05 +00:00
}
2016-04-19 03:38:38 +00:00
}
else { // Visitors
2018-05-24 05:50:33 +00:00
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self
2016-04-19 03:38:38 +00:00
FROM xchan left join xlink on xlink_link = xchan_hash
2020-09-07 05:46:07 +00:00
WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc limit $count" ,
2016-04-19 03:38:38 +00:00
dbesc(get_observer_hash())
);
}
2019-11-21 02:50:05 +00:00
if ((count($r) < 100) && $type == 'c') {
2020-08-26 03:27:06 +00:00
$r2 = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self
2020-09-07 05:46:07 +00:00
FROM xchan WHERE xchan_deleted = 0 and xchan_network != 'unknown' $sql_extra2 order by $order_extra2 xchan_name asc limit $count"
2018-04-26 01:41:19 +00:00
);
2019-11-21 02:50:05 +00:00
if ($r2) {
2018-04-26 01:41:19 +00:00
$r = array_merge($r,$r2);
$r = unique_multidim_array($r,'hash');
}
2016-04-19 03:38:38 +00:00
}
2020-09-07 05:46:07 +00:00
2016-04-19 03:38:38 +00:00
}
2019-11-21 02:50:05 +00:00
elseif ($type == 'm') {
2016-07-20 20:39:10 +00:00
2019-11-21 02:50:05 +00:00
$r = [];
2016-07-20 20:39:10 +00:00
$z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
2016-04-19 03:38:38 +00:00
FROM abook left join xchan on abook_xchan = xchan_hash
2016-07-14 02:53:28 +00:00
WHERE abook_channel = %d
2016-04-19 03:38:38 +00:00
and xchan_deleted = 0
$sql_extra3
2016-07-14 02:53:28 +00:00
ORDER BY xchan_name ASC ",
intval(local_channel())
2016-04-19 03:38:38 +00:00
);
2019-11-21 02:50:05 +00:00
if ($z) {
foreach ($z as $zz) {
if (in_array($zz['hash'],$permitted)) {
2016-07-14 02:53:28 +00:00
$r[] = $zz;
}
}
}
2016-04-19 03:38:38 +00:00
}
2019-11-21 02:50:05 +00:00
elseif ($type == 'a') {
2016-04-19 03:38:38 +00:00
2018-05-24 05:50:33 +00:00
$r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM abook left join xchan on abook_xchan = xchan_hash
2016-04-19 03:38:38 +00:00
WHERE abook_channel = %d
and xchan_deleted = 0
$sql_extra3
ORDER BY xchan_name ASC ",
intval(local_channel())
);
}
elseif ($type == 'z') {
$r = q("SELECT xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM xchan left join abook on xchan_hash = abook_xchan
WHERE ( abook_channel = %d OR abook_channel IS NULL )
and xchan_deleted = 0
$sql_extra3
ORDER BY xchan_name ASC ",
intval(local_channel())
);
}
2019-11-21 02:50:05 +00:00
elseif ($type == 'x') {
$contacts = [];
2019-11-19 23:01:19 +00:00
$r = $this->navbar_complete();
2019-11-21 02:50:05 +00:00
if ($r) {
foreach ($r as $g) {
$contacts[] = [
2016-04-19 03:38:38 +00:00
"photo" => $g['photo'],
"name" => $g['name'],
2019-09-23 03:56:30 +00:00
"nick" => $g['address'],
2020-06-10 03:42:01 +00:00
'link' => (($g['address']) ? $g['address'] : $g['url']),
2020-06-10 04:34:31 +00:00
'xchan' => $g['hash']
2019-11-21 02:50:05 +00:00
];
2016-04-19 03:38:38 +00:00
}
}
2019-11-21 02:50:05 +00:00
$o = [
2016-04-19 03:38:38 +00:00
'start' => $start,
'count' => $count,
'items' => $contacts,
2019-11-21 02:50:05 +00:00
];
json_return_and_die($o);
}
else {
$r = [];
2016-04-19 03:38:38 +00:00
}
2019-11-21 02:50:05 +00:00
if ($r) {
foreach ($r as $g) {
2016-04-19 03:38:38 +00:00
2019-11-21 02:50:05 +00:00
if (in_array($g['network'],['rss','anon','unknown']) && ($type != 'a')) {
continue;
2019-11-21 02:50:05 +00:00
}
// 'z' (activity_filter autocomplete) requires an un-encoded hash to prevent double encoding
if ($type !== 'z') {
$g['hash'] = urlencode($g['hash']);
}
2019-11-21 02:50:05 +00:00
if (! $g['nick']) {
$g['nick'] = $g['url'];
}
2019-11-21 02:50:05 +00:00
if (in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) {
$contacts[] = [
2016-04-19 03:38:38 +00:00
"type" => "c",
"photo" => "images/twopeople.png",
"name" => $g['name'],
"id" => urlencode($g['id']),
2017-10-03 22:43:51 +00:00
"xid" => $g['hash'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
2016-04-19 03:38:38 +00:00
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => 'taggable',
"label" => t('network')
2019-11-21 02:50:05 +00:00
];
2016-04-19 03:38:38 +00:00
}
2019-11-21 02:50:05 +00:00
if ($type !== 'f') {
$contacts[] = [
"type" => "c",
"photo" => $g['micro'],
"name" => $g['name'],
2017-10-03 22:43:51 +00:00
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => '',
"label" => '',
2019-11-21 02:50:05 +00:00
];
}
2016-04-19 03:38:38 +00:00
}
}
$items = array_merge($groups, $contacts);
2019-11-21 02:50:05 +00:00
$o = [
2016-04-19 03:38:38 +00:00
'start' => $start,
'count' => $count,
'items' => $items,
2019-11-21 02:50:05 +00:00
];
2019-11-21 02:50:05 +00:00
json_return_and_die($o);
2016-04-19 03:38:38 +00:00
}
2019-11-19 23:01:19 +00:00
function navbar_complete() {
2016-04-19 03:38:38 +00:00
// logger('navbar_complete');
2019-11-21 02:50:05 +00:00
if (observer_prohibited()) {
2016-04-19 03:38:38 +00:00
return;
}
$dirmode = intval(get_config('system','directory_mode'));
$search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
2019-11-21 02:50:05 +00:00
if (! $search || mb_strlen($search) < 2) {
return [];
}
2016-04-19 03:38:38 +00:00
$star = false;
$address = false;
2019-11-21 02:50:05 +00:00
if (substr($search,0,1) === '@') {
2016-04-19 03:38:38 +00:00
$search = substr($search,1);
2019-11-21 02:50:05 +00:00
}
2016-04-19 03:38:38 +00:00
2019-11-21 02:50:05 +00:00
if (substr($search,0,1) === '*') {
2016-04-19 03:38:38 +00:00
$star = true;
$search = substr($search,1);
}
2019-11-21 02:50:05 +00:00
if (strpos($search,'@') !== false) {
2016-04-19 03:38:38 +00:00
$address = true;
}
2019-09-23 03:56:30 +00:00
2020-09-01 02:24:21 +00:00
$url = z_root() . '/dirsearch';
2020-09-01 02:24:21 +00:00
2019-11-19 23:01:19 +00:00
$results = [];
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
2020-09-01 02:24:21 +00:00
2019-11-21 02:50:05 +00:00
if ($url) {
2020-09-01 02:24:21 +00:00
$query = $url . '?f=';
2018-03-15 01:42:07 +00:00
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
2016-04-19 03:38:38 +00:00
$x = z_fetch_url($query);
2019-11-21 02:50:05 +00:00
if ($x['success']) {
2016-04-19 03:38:38 +00:00
$t = 0;
$j = json_decode($x['body'],true);
2019-11-21 02:50:05 +00:00
if ($j && $j['results']) {
2019-09-23 03:56:30 +00:00
$results = $j['results'];
2016-04-19 03:38:38 +00:00
}
}
}
2019-09-23 03:56:30 +00:00
return $results;
2016-04-19 03:38:38 +00:00
}
}