Merge branch 'dev' of /home/macgirvin/./streams into dev

This commit is contained in:
nobody 2021-12-21 14:22:03 -08:00
commit 550c3414ec
755 changed files with 110032 additions and 105775 deletions

View file

@ -5,5 +5,5 @@ self.addEventListener('install', function(e) {
self.addEventListener('fetch', function(e) {
// nothing here yet
return;
});

View file

@ -12,153 +12,158 @@ namespace Zotlabs\Access;
* and @ref ::Zotlabs::Lib::Permcat "Permcat"s individual content ACLs are evaluated.
* These answer the question "Can Joe view *this* album/photo?".
*/
class AccessControl {
/**
* @brief Allow contacts
* @var string
*/
private $allow_cid;
/**
* @brief Allow groups
* @var string
*/
private $allow_gid;
/**
* @brief Deny contacts
* @var string
*/
private $deny_cid;
/**
* @brief Deny groups
* @var string
*/
private $deny_gid;
/**
* @brief Indicates if we are using the default constructor values or
* values that have been set explicitly.
* @var boolean
*/
private $explicit;
class AccessControl
{
/**
* @brief Allow contacts
* @var string
*/
private $allow_cid;
/**
* @brief Allow groups
* @var string
*/
private $allow_gid;
/**
* @brief Deny contacts
* @var string
*/
private $deny_cid;
/**
* @brief Deny groups
* @var string
*/
private $deny_gid;
/**
* @brief Indicates if we are using the default constructor values or
* values that have been set explicitly.
* @var bool
*/
private $explicit;
/**
* @brief Constructor for AccessList class.
*
* @note The array to pass to the constructor is different from the array
* that you provide to the set() or set_from_array() functions.
*
* @param array $channel A channel array, where these entries are evaluated:
* * \e string \b channel_allow_cid => string of allowed cids
* * \e string \b channel_allow_gid => string of allowed gids
* * \e string \b channel_deny_cid => string of denied cids
* * \e string \b channel_deny_gid => string of denied gids
*/
function __construct($channel) {
if($channel) {
$this->allow_cid = $channel['channel_allow_cid'];
$this->allow_gid = $channel['channel_allow_gid'];
$this->deny_cid = $channel['channel_deny_cid'];
$this->deny_gid = $channel['channel_deny_gid'];
}
else {
$this->allow_cid = '';
$this->allow_gid = '';
$this->deny_cid = '';
$this->deny_gid = '';
}
/**
* @brief Constructor for AccessList class.
*
* @note The array to pass to the constructor is different from the array
* that you provide to the set() or set_from_array() functions.
*
* @param array $channel A channel array, where these entries are evaluated:
* * \e string \b channel_allow_cid => string of allowed cids
* * \e string \b channel_allow_gid => string of allowed gids
* * \e string \b channel_deny_cid => string of denied cids
* * \e string \b channel_deny_gid => string of denied gids
*/
public function __construct($channel)
{
if ($channel) {
$this->allow_cid = $channel['channel_allow_cid'];
$this->allow_gid = $channel['channel_allow_gid'];
$this->deny_cid = $channel['channel_deny_cid'];
$this->deny_gid = $channel['channel_deny_gid'];
} else {
$this->allow_cid = '';
$this->allow_gid = '';
$this->deny_cid = '';
$this->deny_gid = '';
}
$this->explicit = false;
}
$this->explicit = false;
}
/**
* @brief Get if we are using the default constructor values
* or values that have been set explicitly.
*
* @return boolean
*/
function get_explicit() {
return $this->explicit;
}
/**
* @brief Get if we are using the default constructor values
* or values that have been set explicitly.
*
* @return bool
*/
public function get_explicit()
{
return $this->explicit;
}
/**
* @brief Set access list from strings such as those in already
* existing stored data items.
*
* @note The array to pass to this set function is different from the array
* that you provide to the constructor or set_from_array().
*
* @param array $arr
* * \e string \b allow_cid => string of allowed cids
* * \e string \b allow_gid => string of allowed gids
* * \e string \b deny_cid => string of denied cids
* * \e string \b deny_gid => string of denied gids
* @param boolean $explicit (optional) default true
*/
function set($arr, $explicit = true) {
$this->allow_cid = $arr['allow_cid'];
$this->allow_gid = $arr['allow_gid'];
$this->deny_cid = $arr['deny_cid'];
$this->deny_gid = $arr['deny_gid'];
/**
* @brief Set access list from strings such as those in already
* existing stored data items.
*
* @note The array to pass to this set function is different from the array
* that you provide to the constructor or set_from_array().
*
* @param array $arr
* * \e string \b allow_cid => string of allowed cids
* * \e string \b allow_gid => string of allowed gids
* * \e string \b deny_cid => string of denied cids
* * \e string \b deny_gid => string of denied gids
* @param bool $explicit (optional) default true
*/
public function set($arr, $explicit = true)
{
$this->allow_cid = $arr['allow_cid'];
$this->allow_gid = $arr['allow_gid'];
$this->deny_cid = $arr['deny_cid'];
$this->deny_gid = $arr['deny_gid'];
$this->explicit = $explicit;
}
$this->explicit = $explicit;
}
/**
* @brief Return an array consisting of the current access list components
* where the elements are directly storable.
*
* @return array An associative array with:
* * \e string \b allow_cid => string of allowed cids
* * \e string \b allow_gid => string of allowed gids
* * \e string \b deny_cid => string of denied cids
* * \e string \b deny_gid => string of denied gids
*/
function get() {
return [
'allow_cid' => $this->allow_cid,
'allow_gid' => $this->allow_gid,
'deny_cid' => $this->deny_cid,
'deny_gid' => $this->deny_gid,
];
}
/**
* @brief Return an array consisting of the current access list components
* where the elements are directly storable.
*
* @return array An associative array with:
* * \e string \b allow_cid => string of allowed cids
* * \e string \b allow_gid => string of allowed gids
* * \e string \b deny_cid => string of denied cids
* * \e string \b deny_gid => string of denied gids
*/
public function get()
{
return [
'allow_cid' => $this->allow_cid,
'allow_gid' => $this->allow_gid,
'deny_cid' => $this->deny_cid,
'deny_gid' => $this->deny_gid,
];
}
/**
* @brief Set access list components from arrays, such as those provided by
* acl_selector().
*
* For convenience, a string (or non-array) input is assumed to be a
* comma-separated list and auto-converted into an array.
*
* @note The array to pass to this set function is different from the array
* that you provide to the constructor or set().
*
* @param array $arr An associative array with:
* * \e array|string \b contact_allow => array with cids or comma-seperated string
* * \e array|string \b group_allow => array with gids or comma-seperated string
* * \e array|string \b contact_deny => array with cids or comma-seperated string
* * \e array|string \b group_deny => array with gids or comma-seperated string
* @param boolean $explicit (optional) default true
*/
function set_from_array($arr, $explicit = true) {
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
$this->allow_gid = perms2str((is_array($arr['group_allow']))
? $arr['group_allow'] : explode(',', $arr['group_allow']));
$this->deny_cid = perms2str((is_array($arr['contact_deny']))
? $arr['contact_deny'] : explode(',', $arr['contact_deny']));
$this->deny_gid = perms2str((is_array($arr['group_deny']))
? $arr['group_deny'] : explode(',', $arr['group_deny']));
/**
* @brief Set access list components from arrays, such as those provided by
* acl_selector().
*
* For convenience, a string (or non-array) input is assumed to be a
* comma-separated list and auto-converted into an array.
*
* @note The array to pass to this set function is different from the array
* that you provide to the constructor or set().
*
* @param array $arr An associative array with:
* * \e array|string \b contact_allow => array with cids or comma-seperated string
* * \e array|string \b group_allow => array with gids or comma-seperated string
* * \e array|string \b contact_deny => array with cids or comma-seperated string
* * \e array|string \b group_deny => array with gids or comma-seperated string
* @param bool $explicit (optional) default true
*/
public function set_from_array($arr, $explicit = true)
{
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
$this->allow_gid = perms2str((is_array($arr['group_allow']))
? $arr['group_allow'] : explode(',', $arr['group_allow']));
$this->deny_cid = perms2str((is_array($arr['contact_deny']))
? $arr['contact_deny'] : explode(',', $arr['contact_deny']));
$this->deny_gid = perms2str((is_array($arr['group_deny']))
? $arr['group_deny'] : explode(',', $arr['group_deny']));
$this->explicit = $explicit;
}
/**
* @brief Returns true if any access lists component is set.
*
* @return boolean Return true if any of allow_* deny_* values is set.
*/
function is_private() {
return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
}
$this->explicit = $explicit;
}
/**
* @brief Returns true if any access lists component is set.
*
* @return bool Return true if any of allow_* deny_* values is set.
*/
public function is_private()
{
return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
}
}

View file

@ -26,78 +26,83 @@ use Zotlabs\Lib\PConfig;
*
* @see Permissions
*/
class PermissionLimits {
class PermissionLimits
{
/**
* @brief Get standard permission limits.
*
* Viewing permissions and post_comments permission are set to 'anybody',
* other permissions are set to 'those I allow'.
*
* The list of permissions comes from Permissions::Perms().
*
* @return array
*/
static public function Std_Limits() {
$limits = [];
$perms = Permissions::Perms();
/**
* @brief Get standard permission limits.
*
* Viewing permissions and post_comments permission are set to 'anybody',
* other permissions are set to 'those I allow'.
*
* The list of permissions comes from Permissions::Perms().
*
* @return array
*/
public static function Std_Limits()
{
$limits = [];
$perms = Permissions::Perms();
foreach($perms as $k => $v) {
if(strstr($k, 'view'))
$limits[$k] = PERMS_PUBLIC;
else
$limits[$k] = PERMS_SPECIFIC;
}
foreach ($perms as $k => $v) {
if (strstr($k, 'view')) {
$limits[$k] = PERMS_PUBLIC;
} else {
$limits[$k] = PERMS_SPECIFIC;
}
}
return $limits;
}
return $limits;
}
/**
* @brief Sets a permission limit for a channel.
*
* @param int $channel_id
* @param string $perm
* @param int $perm_limit one of PERMS_* constants
*/
static public function Set($channel_id, $perm, $perm_limit) {
PConfig::Set($channel_id, 'perm_limits', $perm, $perm_limit);
}
/**
* @brief Sets a permission limit for a channel.
*
* @param int $channel_id
* @param string $perm
* @param int $perm_limit one of PERMS_* constants
*/
public static function Set($channel_id, $perm, $perm_limit)
{
PConfig::Set($channel_id, 'perm_limits', $perm, $perm_limit);
}
/**
* @brief Get a channel's permission limits.
*
* Return a channel's permission limits from PConfig. If $perm is set just
* return this permission limit, if not set, return an array with all
* permission limits.
*
* @param int $channel_id
* @param string $perm (optional)
* @return
* * \b false if no perm_limits set for this channel
* * \b int if $perm is set, return one of PERMS_* constants for this permission, default 0
* * \b array with all permission limits, if $perm is not set
*/
static public function Get($channel_id, $perm = '') {
/**
* @brief Get a channel's permission limits.
*
* Return a channel's permission limits from PConfig. If $perm is set just
* return this permission limit, if not set, return an array with all
* permission limits.
*
* @param int $channel_id
* @param string $perm (optional)
* @return
* * \b false if no perm_limits set for this channel
* * \b int if $perm is set, return one of PERMS_* constants for this permission, default 0
* * \b array with all permission limits, if $perm is not set
*/
public static function Get($channel_id, $perm = '')
{
if (! intval($channel_id)) {
return false;
}
if (! intval($channel_id)) {
return false;
}
if($perm) {
$x = PConfig::Get($channel_id, 'perm_limits', $perm);
if($x === false) {
$a = [ 'channel_id' => $channel_id, 'permission' => $perm, 'value' => $x ];
call_hooks('permission_limits_get',$a);
return intval($a['value']);
}
return intval($x);
}
if ($perm) {
$x = PConfig::Get($channel_id, 'perm_limits', $perm);
if ($x === false) {
$a = [ 'channel_id' => $channel_id, 'permission' => $perm, 'value' => $x ];
call_hooks('permission_limits_get', $a);
return intval($a['value']);
}
return intval($x);
}
PConfig::Load($channel_id);
if(array_key_exists($channel_id, App::$config) && array_key_exists('perm_limits', App::$config[$channel_id])) {
return App::$config[$channel_id]['perm_limits'];
}
PConfig::Load($channel_id);
if (array_key_exists($channel_id, App::$config) && array_key_exists('perm_limits', App::$config[$channel_id])) {
return App::$config[$channel_id]['perm_limits'];
}
return false;
}
return false;
}
}

View file

@ -7,193 +7,146 @@ namespace Zotlabs\Access;
*
* @see Permissions
*/
class PermissionRoles {
class PermissionRoles
{
/**
* @brief PermissionRoles version.
*
* This must match the version in Permissions.php before permission updates can run.
*
* @return number
*/
static public function version() {
return 3;
}
/**
* @brief PermissionRoles version.
*
* This must match the version in Permissions.php before permission updates can run.
*
* @return number
*/
public static function version()
{
return 3;
}
static function role_perms($role) {
public static function role_perms($role)
{
$ret = [];
$ret = [];
$ret['role'] = $role;
$ret['role'] = $role;
switch($role) {
case 'social':
$ret['perms_auto'] = false;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = true;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
switch ($role) {
case 'social':
$ret['perms_auto'] = false;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = true;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
case 'social_restricted':
$ret['perms_auto'] = false;
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_storage',
'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
break;
case 'social_restricted':
$ret['perms_auto'] = false;
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_storage',
'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
break;
case 'forum':
$ret['perms_auto'] = true;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
case 'forum':
$ret['perms_auto'] = true;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
break;
break;
case 'forum_moderated':
$ret['perms_auto'] = true;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments', 'moderated'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
case 'forum_moderated':
$ret['perms_auto'] = true;
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments', 'moderated'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
break;
break;
case 'forum_restricted':
$ret['perms_auto'] = false;
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['channel_type'] = 'group';
break;
case 'forum_restricted':
$ret['perms_auto'] = false;
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_mail', 'post_wall', 'post_comments'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['channel_type'] = 'group';
break;
default:
break;
}
// case 'collection':
// $ret['perms_auto'] = true;
// $ret['default_collection'] = false;
// $ret['directory_publish'] = true;
// $ret['online'] = false;
// $ret['perms_connect'] = [
// 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
// 'view_pages', 'post_mail', 'post_comments'
// ];
// $ret['limits'] = PermissionLimits::Std_Limits();
// $ret['channel_type'] = 'collection';
//
// break;
//
// case 'collection_restricted':
// $ret['perms_auto'] = false;
// $ret['default_collection'] = true;
// $ret['directory_publish'] = true;
// $ret['online'] = false;
// $ret['perms_connect'] = [
// 'view_stream', 'view_profile', 'view_storage',
// 'view_pages', 'post_mail', 'post_comments'
// ];
// $ret['limits'] = PermissionLimits::Std_Limits();
// $ret['limits']['view_contacts'] = PERMS_SPECIFIC;
// $ret['channel_type'] = 'collection';
// break;
//
// case 'feed':
// $ret['perms_auto'] = true;
// $ret['default_collection'] = false;
// $ret['directory_publish'] = true;
// $ret['online'] = false;
// $ret['perms_connect'] = [
// 'view_stream', 'view_profile', 'view_contacts', 'view_storage',
// 'view_pages', 'send_stream', 'post_wall', 'post_mail', 'post_comments',
// 'republish'
// ];
// $ret['limits'] = PermissionLimits::Std_Limits();
//
// break;
//
// case 'repository':
// //Legacy settings to cover all channel_types previously in Libzot.php
// $ret['channel_type'] = 'group';
default:
break;
}
$x = get_config('system', 'role_perms');
// let system settings over-ride any or all
if ($x && is_array($x) && array_key_exists($role, $x)) {
$ret = array_merge($ret, $x[$role]);
}
/**
* @hooks get_role_perms
* * \e array
*/
$x = ['role' => $role, 'result' => $ret];
call_hooks('get_role_perms', $x);
return $x['result'];
}
$x = get_config('system','role_perms');
// let system settings over-ride any or all
if($x && is_array($x) && array_key_exists($role,$x))
$ret = array_merge($ret,$x[$role]);
/**
* @brief Array with translated role names and grouping.
*
* Return an associative array with grouped role names that can be used
* to create select groups like in \e field_select_grouped.tpl.
*
* @return array
*/
public static function roles()
{
$roles = [
t('Social Networking') => [
'social' => t('Social - Normal'),
'social_restricted' => t('Social - Restricted')
],
/**
* @hooks get_role_perms
* * \e array
*/
$x = [ 'role' => $role, 'result' => $ret ];
t('Community Group') => [
'forum' => t('Group - Normal'),
'forum_restricted' => t('Group - Restricted'),
'forum_moderated' => t('Group - Moderated')
],
];
call_hooks('get_role_perms', $x);
call_hooks('list_permission_roles', $roles);
return $x['result'];
}
/**
* @brief Array with translated role names and grouping.
*
* Return an associative array with grouped role names that can be used
* to create select groups like in \e field_select_grouped.tpl.
*
* @return array
*/
static public function roles() {
$roles = [
t('Social Networking') => [
'social' => t('Social - Normal'),
'social_restricted' => t('Social - Restricted')
],
t('Community Group') => [
'forum' => t('Group - Normal'),
'forum_restricted' => t('Group - Restricted'),
'forum_moderated' => t('Group - Moderated')
],
// t('Collection') => [
// 'collection' => t('Collection - Normal'),
// 'collection_restricted' => t('Collection - Restricted')
// ]
];
call_hooks('list_permission_roles',$roles);
return $roles;
}
return $roles;
}
}

View file

@ -31,252 +31,266 @@ use Zotlabs\Lib as Zlib;
* something different for a specific permission within the given role.
*
*/
class Permissions {
class Permissions
{
/**
* @brief Permissions version.
*
* This must match the version in PermissionRoles.php before permission updates can run.
*
* @return number
*/
static public function version() {
return 3;
}
/**
* @brief Permissions version.
*
* This must match the version in PermissionRoles.php before permission updates can run.
*
* @return number
*/
public static function version()
{
return 3;
}
/**
* @brief Return an array with Permissions.
*
* @param string $filter (optional) only passed to hook permissions_list
* @return array Associative array with permissions and short description.
*/
static public function Perms($filter = '') {
/**
* @brief Return an array with Permissions.
*
* @param string $filter (optional) only passed to hook permissions_list
* @return array Associative array with permissions and short description.
*/
public static function Perms($filter = '')
{
$perms = [
'view_stream' => t('Grant viewing access to and delivery of your channel stream and posts'),
'view_profile' => t('Grant viewing access to your default channel profile'),
'view_contacts' => t('Grant viewing access to your address book (connections)'),
'view_storage' => t('Grant viewing access to your file storage and photos'),
'post_wall' => t('Grant permission to post on your channel (wall) page'),
'post_mail' => t('Accept delivery of direct messages and personal mail'),
'send_stream' => t('Accept delivery of their posts and all comments to their posts'),
'post_comments' => t('Accept delivery of their comments and likes on your posts'),
'write_storage' => t('Grant upload permissions to your file storage and photos'),
'republish' => t('Grant permission to republish/mirror your posts'),
'moderated' => t('Accept comments and wall posts only after approval (moderation)'),
'delegate' => t('Grant channel administration (delegation) permission')
];
$perms = [
'view_stream' => t('Grant viewing access to and delivery of your channel stream and posts'),
'view_profile' => t('Grant viewing access to your default channel profile'),
'view_contacts' => t('Grant viewing access to your address book (connections)'),
'view_storage' => t('Grant viewing access to your file storage and photos'),
'post_wall' => t('Grant permission to post on your channel (wall) page'),
'post_mail' => t('Accept delivery of direct messages and personal mail'),
'send_stream' => t('Accept delivery of their posts and all comments to their posts'),
'post_comments' => t('Accept delivery of their comments and likes on your posts'),
'write_storage' => t('Grant upload permissions to your file storage and photos'),
'republish' => t('Grant permission to republish/mirror your posts'),
'moderated' => t('Accept comments and wall posts only after approval (moderation)'),
'delegate' => t('Grant channel administration (delegation) permission')
];
$x = [
'permissions' => $perms,
'filter' => $filter
];
/**
* @hooks permissions_list
* * \e array \b permissions
* * \e string \b filter
*/
call_hooks('permissions_list', $x);
$x = [
'permissions' => $perms,
'filter' => $filter
];
/**
* @hooks permissions_list
* * \e array \b permissions
* * \e string \b filter
*/
call_hooks('permissions_list', $x);
return($x['permissions']);
}
return($x['permissions']);
}
/**
* @brief Perms from the above list that are blocked from anonymous observers.
*
* e.g. you must be authenticated.
*
* @return array Associative array with permissions and short description.
*/
static public function BlockedAnonPerms() {
/**
* @brief Perms from the above list that are blocked from anonymous observers.
*
* e.g. you must be authenticated.
*
* @return array Associative array with permissions and short description.
*/
public static function BlockedAnonPerms()
{
$res = [];
$perms = PermissionLimits::Std_limits();
foreach($perms as $perm => $limit) {
if($limit != PERMS_PUBLIC) {
$res[] = $perm;
}
}
$res = [];
$perms = PermissionLimits::Std_limits();
foreach ($perms as $perm => $limit) {
if ($limit != PERMS_PUBLIC) {
$res[] = $perm;
}
}
$x = ['permissions' => $res];
/**
* @hooks write_perms
* * \e array \b permissions
*/
call_hooks('write_perms', $x);
$x = ['permissions' => $res];
/**
* @hooks write_perms
* * \e array \b permissions
*/
call_hooks('write_perms', $x);
return($x['permissions']);
}
return($x['permissions']);
}
/**
* @brief Converts indexed perms array to associative perms array.
*
* Converts [ 0 => 'view_stream', ... ]
* to [ 'view_stream' => 1 ] for any permissions in $arr;
* Undeclared permissions which exist in Perms() are added and set to 0.
*
* @param array $arr
* @return array
*/
static public function FilledPerms($arr) {
if(is_null($arr) || (! is_array($arr))) {
btlogger('FilledPerms: ' . print_r($arr,true));
$arr = [];
}
/**
* @brief Converts indexed perms array to associative perms array.
*
* Converts [ 0 => 'view_stream', ... ]
* to [ 'view_stream' => 1 ] for any permissions in $arr;
* Undeclared permissions which exist in Perms() are added and set to 0.
*
* @param array $arr
* @return array
*/
public static function FilledPerms($arr)
{
if (is_null($arr) || (! is_array($arr))) {
btlogger('FilledPerms: ' . print_r($arr, true));
$arr = [];
}
$everything = self::Perms();
$ret = [];
foreach($everything as $k => $v) {
if(in_array($k, $arr))
$ret[$k] = 1;
else
$ret[$k] = 0;
}
$everything = self::Perms();
$ret = [];
foreach ($everything as $k => $v) {
if (in_array($k, $arr)) {
$ret[$k] = 1;
} else {
$ret[$k] = 0;
}
}
return $ret;
}
return $ret;
}
/**
* @brief Convert perms array to indexed array.
*
* Converts [ 'view_stream' => 1 ] for any permissions in $arr
* to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ]
*
* @param array $arr associative perms array 'view_stream' => 1
* @return array Indexed array with elements that look like
* * \e string \b name the perm name (e.g. view_stream)
* * \e int \b value the value of the perm (e.g. 1)
*/
static public function OPerms($arr) {
$ret = [];
if($arr) {
foreach($arr as $k => $v) {
$ret[] = [ 'name' => $k, 'value' => $v ];
}
}
return $ret;
}
/**
* @brief Convert perms array to indexed array.
*
* Converts [ 'view_stream' => 1 ] for any permissions in $arr
* to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ]
*
* @param array $arr associative perms array 'view_stream' => 1
* @return array Indexed array with elements that look like
* * \e string \b name the perm name (e.g. view_stream)
* * \e int \b value the value of the perm (e.g. 1)
*/
public static function OPerms($arr)
{
$ret = [];
if ($arr) {
foreach ($arr as $k => $v) {
$ret[] = [ 'name' => $k, 'value' => $v ];
}
}
return $ret;
}
/**
* @brief
*
* @param int $channel_id
* @return boolean|array
*/
static public function FilledAutoperms($channel_id) {
if(! intval(get_pconfig($channel_id,'system','autoperms')))
return false;
/**
* @brief
*
* @param int $channel_id
* @return bool|array
*/
public static function FilledAutoperms($channel_id)
{
if (! intval(get_pconfig($channel_id, 'system', 'autoperms'))) {
return false;
}
$arr = [];
$r = q("select * from pconfig where uid = %d and cat = 'autoperms'",
intval($channel_id)
);
if($r) {
foreach($r as $rr) {
$arr[$rr['k']] = intval($rr['v']);
}
}
return $arr;
}
$arr = [];
$r = q(
"select * from pconfig where uid = %d and cat = 'autoperms'",
intval($channel_id)
);
if ($r) {
foreach ($r as $rr) {
$arr[$rr['k']] = intval($rr['v']);
}
}
return $arr;
}
/**
* @brief Compares that all Permissions from $p1 exist also in $p2.
*
* @param array $p1 The perms that have to exist in $p2
* @param array $p2 The perms to compare against
* @return boolean true if all perms from $p1 exist also in $p2
*/
static public function PermsCompare($p1, $p2) {
foreach($p1 as $k => $v) {
if(! array_key_exists($k, $p2))
return false;
/**
* @brief Compares that all Permissions from $p1 exist also in $p2.
*
* @param array $p1 The perms that have to exist in $p2
* @param array $p2 The perms to compare against
* @return bool true if all perms from $p1 exist also in $p2
*/
public static function PermsCompare($p1, $p2)
{
foreach ($p1 as $k => $v) {
if (! array_key_exists($k, $p2)) {
return false;
}
if($p1[$k] != $p2[$k])
return false;
}
if ($p1[$k] != $p2[$k]) {
return false;
}
}
return true;
}
return true;
}
/**
* @brief
*
* @param int $channel_id A channel id
* @return array Associative array with
* * \e array \b perms Permission array
* * \e int \b automatic 0 or 1
*/
static public function connect_perms($channel_id) {
/**
* @brief
*
* @param int $channel_id A channel id
* @return array Associative array with
* * \e array \b perms Permission array
* * \e int \b automatic 0 or 1
*/
public static function connect_perms($channel_id)
{
$my_perms = [];
$permcat = null;
$automatic = 0;
$my_perms = [];
$permcat = null;
$automatic = 0;
// If a default permcat exists, use that
// If a default permcat exists, use that
$pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default');
if(! in_array($pc, [ '','default' ])) {
$pcp = new Zlib\Permcat($channel_id);
$permcat = $pcp->fetch($pc);
if($permcat && $permcat['perms']) {
foreach($permcat['perms'] as $p) {
$my_perms[$p['name']] = $p['value'];
}
}
}
$pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default');
if (! in_array($pc, [ '','default' ])) {
$pcp = new Zlib\Permcat($channel_id);
$permcat = $pcp->fetch($pc);
if ($permcat && $permcat['perms']) {
foreach ($permcat['perms'] as $p) {
$my_perms[$p['name']] = $p['value'];
}
}
}
$automatic = intval(get_pconfig($channel_id,'system','autoperms'));
$automatic = intval(get_pconfig($channel_id, 'system', 'autoperms'));
// look up the permission role to see if it specified auto-connect
// and if there was no permcat or a default permcat, set the perms
// from the role
// look up the permission role to see if it specified auto-connect
// and if there was no permcat or a default permcat, set the perms
// from the role
$role = get_pconfig($channel_id,'system','permissions_role');
if($role) {
$xx = PermissionRoles::role_perms($role);
$role = get_pconfig($channel_id, 'system', 'permissions_role');
if ($role) {
$xx = PermissionRoles::role_perms($role);
if((! $my_perms) && ($xx['perms_connect'])) {
$default_perms = $xx['perms_connect'];
$my_perms = Permissions::FilledPerms($default_perms);
}
}
if ((! $my_perms) && ($xx['perms_connect'])) {
$default_perms = $xx['perms_connect'];
$my_perms = Permissions::FilledPerms($default_perms);
}
}
// If we reached this point without having any permission information,
// it is likely a custom permissions role. First see if there are any
// automatic permissions.
// If we reached this point without having any permission information,
// it is likely a custom permissions role. First see if there are any
// automatic permissions.
if(! $my_perms) {
$m = Permissions::FilledAutoperms($channel_id);
if($m) {
$my_perms = $m;
}
}
if (! $my_perms) {
$m = Permissions::FilledAutoperms($channel_id);
if ($m) {
$my_perms = $m;
}
}
// If we reached this point with no permissions, the channel is using
// custom perms but they are not automatic. They will be stored in abconfig with
// the channel's channel_hash (the 'self' connection).
// If we reached this point with no permissions, the channel is using
// custom perms but they are not automatic. They will be stored in abconfig with
// the channel's channel_hash (the 'self' connection).
if(! $my_perms) {
$c = channelx_by_n($channel_id);
if($c) {
$my_perms = Permissions::FilledPerms(explode(',',get_abconfig($channel_id,$c['channel_hash'],'system','my_perms',EMPTY_STR)));
}
}
if (! $my_perms) {
$c = channelx_by_n($channel_id);
if ($c) {
$my_perms = Permissions::FilledPerms(explode(',', get_abconfig($channel_id, $c['channel_hash'], 'system', 'my_perms', EMPTY_STR)));
}
}
return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] );
}
return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] );
}
static public function serialise($p) {
$n = [];
if($p) {
foreach($p as $k => $v) {
if(intval($v)) {
$n[] = $k;
}
}
}
return implode(',',$n);
}
public static function serialise($p)
{
$n = [];
if ($p) {
foreach ($p as $k => $v) {
if (intval($v)) {
$n[] = $k;
}
}
}
return implode(',', $n);
}
}

View file

@ -2,12 +2,12 @@
namespace Zotlabs\Daemon;
class Addon
{
class Addon {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
call_hooks('daemon_addon',$argv);
}
call_hooks('daemon_addon', $argv);
}
}

View file

@ -1,50 +1,54 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
require_once('include/photos.php');
class CacheThumb {
class CacheThumb
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
if (! $argc == 2) {
return;
}
if (! $argc == 2) {
return;
}
$path = 'cache/img/' . substr($argv[1],0,2) . '/' . $argv[1];
$path = 'cache/img/' . substr($argv[1], 0, 2) . '/' . $argv[1];
$is = getimagesize($path);
$is = getimagesize($path);
if (! $is) {
return;
}
if (! $is) {
return;
}
$width = $is[0];
$height = $is[1];
$width = $is[0];
$height = $is[1];
$max_thumb = get_config('system','max_cache_thumbnail',1024);
$max_thumb = get_config('system', 'max_cache_thumbnail', 1024);
if ($width > $max_thumb || $height > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if ($imagick_path && @file_exists($imagick_path)) {
$tmp_name = $path . '-001';
$newsize = photo_calculate_scale(array_merge($is,['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $path) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
if ($width > $max_thumb || $height > $max_thumb) {
$imagick_path = get_config('system', 'imagick_convert_path');
if ($imagick_path && @file_exists($imagick_path)) {
$tmp_name = $path . '-001';
$newsize = photo_calculate_scale(array_merge($is, ['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $path) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
for ($x = 0; $x < 4; $x ++) {
exec($cmd);
if (file_exists($tmp_name)) {
break;
}
continue;
}
for ($x = 0; $x < 4; $x++) {
exec($cmd);
if (file_exists($tmp_name)) {
break;
}
continue;
}
if (! file_exists($tmp_name)) {
return;
}
@rename($tmp_name,$path);
}
}
}
if (! file_exists($tmp_name)) {
return;
}
@rename($tmp_name, $path);
}
}
}
}

View file

@ -2,33 +2,34 @@
namespace Zotlabs\Daemon;
class Cache_embeds
{
class Cache_embeds {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if (! $argc == 2) {
return;
}
if (! $argc == 2) {
return;
}
$c = q(
"select body, html, created from item where id = %d ",
dbesc(intval($argv[1]))
);
$c = q("select body, html, created from item where id = %d ",
dbesc(intval($argv[1]))
);
if (! $c) {
return;
}
if (! $c) {
return;
}
$item = array_shift($c);
$item = array_shift($c);
$cache_expire = intval(get_config('system', 'default_expire_days'));
if ($cache_expire <= 0) {
$cache_expire = 60;
}
$cache_enable = ((($cache_expire) && ($item['created'] < datetime_convert('UTC', 'UTC', 'now - ' . $cache_expire . ' days'))) ? false : true);
$cache_expire = intval(get_config('system', 'default_expire_days'));
if ($cache_expire <= 0) {
$cache_expire = 60;
}
$cache_enable = ((($cache_expire) && ($item['created'] < datetime_convert('UTC','UTC', 'now - ' . $cache_expire . ' days'))) ? false : true);
$s = bbcode($item['body']);
$s = sslify($s, $cache_enable);
}
$s = bbcode($item['body']);
$s = sslify($s, $cache_enable);
}
}

View file

@ -4,15 +4,16 @@ namespace Zotlabs\Daemon;
use Zotlabs\Lib\Img_cache;
class Cache_image {
class Cache_image
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
cli_startup();
logger('caching: ' . $argv[1] . ' to ' . $argv[2]);
if ($argc === 3) {
Img_cache::url_to_cache($argv[1],$argv[2]);
}
}
cli_startup();
logger('caching: ' . $argv[1] . ' to ' . $argv[2]);
if ($argc === 3) {
Img_cache::url_to_cache($argv[1], $argv[2]);
}
}
}

View file

@ -2,32 +2,35 @@
namespace Zotlabs\Daemon;
class Channel_purge
{
class Channel_purge {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
cli_startup();
cli_startup();
$channel_id = intval($argv[1]);
$channel_id = intval($argv[1]);
$channel = q(
"select * from channel where channel_id = %d and channel_removed = 1",
intval($channel_id)
);
$channel = q("select * from channel where channel_id = %d and channel_removed = 1",
intval($channel_id)
);
if (! $channel) {
return;
}
if (! $channel) {
return;
}
do {
$r = q("select id from item where uid = %d and item_deleted = 0 limit 1000",
intval($channel_id)
);
if ($r) {
foreach ($r as $rv) {
drop_item($rv['id'],false);
}
}
} while ($r);
}
do {
$r = q(
"select id from item where uid = %d and item_deleted = 0 limit 1000",
intval($channel_id)
);
if ($r) {
foreach ($r as $rv) {
drop_item($rv['id'], false);
}
}
} while ($r);
}
}

View file

@ -1,54 +1,66 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
require_once('include/hubloc.php');
class Checksites {
class Checksites
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
logger('checksites: start');
logger('checksites: start');
if(($argc > 1) && ($argv[1]))
$site_id = $argv[1];
if (($argc > 1) && ($argv[1])) {
$site_id = $argv[1];
}
if($site_id)
$sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
if ($site_id) {
$sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
}
$days = intval(get_config('system','sitecheckdays'));
if($days < 1)
$days = 30;
$days = intval(get_config('system', 'sitecheckdays'));
if ($days < 1) {
$days = 30;
}
$r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ",
db_utcnow(), db_quoteinterval($days . ' DAY'),
intval(SITE_TYPE_ZOT)
);
$r = q(
"select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ",
db_utcnow(),
db_quoteinterval($days . ' DAY'),
intval(SITE_TYPE_ZOT)
);
if(! $r)
return;
if (! $r) {
return;
}
foreach($r as $rr) {
if(! strcasecmp($rr['site_url'],z_root()))
continue;
foreach ($r as $rr) {
if (! strcasecmp($rr['site_url'], z_root())) {
continue;
}
$x = ping_site($rr['site_url']);
if($x['success']) {
logger('checksites: ' . $rr['site_url']);
q("update site set site_update = '%s' where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($rr['site_url'])
);
}
else {
logger('marking dead site: ' . $x['message']);
q("update site set site_dead = 1 where site_url = '%s' ",
dbesc($rr['site_url'])
);
}
}
$x = ping_site($rr['site_url']);
if ($x['success']) {
logger('checksites: ' . $rr['site_url']);
q(
"update site set site_update = '%s' where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($rr['site_url'])
);
} else {
logger('marking dead site: ' . $x['message']);
q(
"update site set site_dead = 1 where site_url = '%s' ",
dbesc($rr['site_url'])
);
}
}
return;
}
return;
}
}

View file

@ -8,52 +8,55 @@ require_once('include/cli_startup.php');
require_once('include/attach.php');
require_once('include/import.php');
class Content_importer {
class Content_importer
{
static public function run($argc,$argv) {
cli_startup();
public static function run($argc, $argv)
{
cli_startup();
$page = $argv[1];
$since = $argv[2];
$until = $argv[3];
$channel_address = $argv[4];
$hz_server = urldecode($argv[5]);
$page = $argv[1];
$since = $argv[2];
$until = $argv[3];
$channel_address = $argv[4];
$hz_server = urldecode($argv[5]);
$m = parse_url($hz_server);
$m = parse_url($hz_server);
$channel = channelx_by_nick($channel_address);
if(! $channel) {
logger('itemhelper: channel not found');
killme();
}
$channel = channelx_by_nick($channel_address);
if (! $channel) {
logger('itemhelper: channel not found');
killme();
}
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
];
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
];
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]);
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
if(! $x['success']) {
logger('no API response',LOGGER_DEBUG);
killme();
}
if (! $x['success']) {
logger('no API response', LOGGER_DEBUG);
killme();
}
$j = json_decode($x['body'],true);
$j = json_decode($x['body'], true);
if (! $j) {
killme();
}
if (! $j) {
killme();
}
if(! ($j['item'] || count($j['item'])))
killme();
if (! ($j['item'] || count($j['item']))) {
killme();
}
import_items($channel,$j['item'],false,((array_key_exists('relocate',$j)) ? $j['relocate'] : null));
import_items($channel, $j['item'], false, ((array_key_exists('relocate', $j)) ? $j['relocate'] : null));
killme();
}
killme();
}
}

View file

@ -6,53 +6,56 @@ use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\ASCollection;
class Convo {
class Convo
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
logger('convo invoked: ' . print_r($argv,true));
logger('convo invoked: ' . print_r($argv, true));
if($argc != 4) {
killme();
}
if ($argc != 4) {
killme();
}
$id = $argv[1];
$channel_id = intval($argv[2]);
$contact_hash = $argv[3];
$id = $argv[1];
$channel_id = intval($argv[2]);
$contact_hash = $argv[3];
$channel = channelx_by_n($channel_id);
if (! $channel) {
killme();
}
$channel = channelx_by_n($channel_id);
if (! $channel) {
killme();
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
$r = q(
"SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
intval($channel_id),
dbesc($contact_hash)
);
if (! $r) {
killme();
}
intval($channel_id),
dbesc($contact_hash)
);
if (! $r) {
killme();
}
$contact = array_shift($r);
$contact = array_shift($r);
$obj = new ASCollection($id, $channel);
$obj = new ASCollection($id, $channel);
$messages = $obj->get();
$messages = $obj->get();
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message,$channel);
}
// set client flag because comments will probably just be objects and not full blown activities
// and that lets us use implied_create
$AS = new ActivityStreams($message, null, true);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS,true);
Activity::store($channel,$contact['abook_xchan'],$AS,$item,true,true);
}
}
}
}
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $channel);
}
// set client flag because comments will probably just be objects and not full blown activities
// and that lets us use implied_create
$AS = new ActivityStreams($message, null, true);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS, true);
Activity::store($channel, $contact['abook_xchan'], $AS, $item, true, true);
}
}
}
}
}

View file

@ -1,201 +1,221 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libsync;
class Cron {
class Cron
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
$maxsysload = intval(get_config('system','maxloadavg'));
if($maxsysload < 1)
$maxsysload = 50;
if(function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if(intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Cron deferred to next scheduled run.');
return;
}
}
$maxsysload = intval(get_config('system', 'maxloadavg'));
if ($maxsysload < 1) {
$maxsysload = 50;
}
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if (intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Cron deferred to next scheduled run.');
return;
}
}
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'cache/cron';
if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
&& (! get_config('system','override_cron_lockfile'))) {
logger("cron: Already running");
return;
}
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'cache/cron';
if (
(file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
&& (! get_config('system', 'override_cron_lockfile'))
) {
logger("cron: Already running");
return;
}
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
file_put_contents($lockfile, $x);
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
file_put_contents($lockfile, $x);
logger('cron: start');
logger('cron: start');
// run queue delivery process in the background
// run queue delivery process in the background
Run::Summon( [ 'Queue' ] );
Run::Summon([ 'Queue' ]);
Run::Summon( [ 'Poller' ] );
Run::Summon([ 'Poller' ]);
// maintenance for mod sharedwithme - check for updated items and remove them
// maintenance for mod sharedwithme - check for updated items and remove them
require_once('include/sharedwithme.php');
apply_updates();
require_once('include/sharedwithme.php');
apply_updates();
// expire any expired items
// expire any expired items
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
$r = q(
"select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
and item_deleted = 0 ",
db_utcnow()
);
if($r) {
require_once('include/items.php');
foreach($r as $rr) {
drop_item($rr['id'],false,(($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
if($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Run::Summon( [ 'Notifier', 'drop', $rr['id'] ] );
}
}
}
db_utcnow()
);
if ($r) {
require_once('include/items.php');
foreach ($r as $rr) {
drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
if ($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Run::Summon([ 'Notifier', 'drop', $rr['id'] ]);
}
}
}
// delete expired access tokens
// delete expired access tokens
$r = q("select atoken_id from atoken where atoken_expires > '%s' and atoken_expires < %s",
dbesc(NULL_DATE),
db_utcnow()
);
if($r) {
require_once('include/security.php');
foreach($r as $rr) {
atoken_delete($rr['atoken_id']);
}
}
$r = q(
"select atoken_id from atoken where atoken_expires > '%s' and atoken_expires < %s",
dbesc(NULL_DATE),
db_utcnow()
);
if ($r) {
require_once('include/security.php');
foreach ($r as $rr) {
atoken_delete($rr['atoken_id']);
}
}
// Ensure that every channel pings their directory occasionally.
// Ensure that every channel pings their directory occasionally.
$r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s and channel_removed = 0",
db_utcnow(),
db_quoteinterval('7 DAY')
);
if($r) {
foreach($r as $rr) {
Run::Summon( [ 'Directory', $rr['channel_id'], 'force' ] );
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
}
$r = q(
"select channel_id from channel where channel_dirdate < %s - INTERVAL %s and channel_removed = 0",
db_utcnow(),
db_quoteinterval('7 DAY')
);
if ($r) {
foreach ($r as $rr) {
Run::Summon([ 'Directory', $rr['channel_id'], 'force' ]);
if ($interval) {
@time_sleep_until(microtime(true) + (float) $interval);
}
}
}
// publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last
// couple of days to limit the query to something reasonable.
// publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last
// couple of days to limit the query to something reasonable.
$r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
db_utcnow(),
dbesc(datetime_convert('UTC','UTC','now - 2 days'))
);
if($r) {
foreach($r as $rr) {
$x = q("update item set item_delayed = 0 where id = %d",
intval($rr['id'])
);
if($x) {
$z = q("select * from item where id = %d",
intval($message_id)
);
if($z) {
xchan_query($z);
$sync_item = fetch_post_tags($z);
Libsync::build_sync_packet($sync_item[0]['uid'],
[
'item' => [ encode_item($sync_item[0],true) ]
]
);
}
Run::Summon( [ 'Notifier','wall-new',$rr['id'] ] );
}
}
}
$r = q(
"select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
db_utcnow(),
dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days'))
);
if ($r) {
foreach ($r as $rr) {
$x = q(
"update item set item_delayed = 0 where id = %d",
intval($rr['id'])
);
if ($x) {
$z = q(
"select * from item where id = %d",
intval($message_id)
);
if ($z) {
xchan_query($z);
$sync_item = fetch_post_tags($z);
Libsync::build_sync_packet(
$sync_item[0]['uid'],
[
'item' => [ encode_item($sync_item[0], true) ]
]
);
}
Run::Summon([ 'Notifier','wall-new',$rr['id'] ]);
}
}
}
require_once('include/attach.php');
attach_upgrade();
require_once('include/attach.php');
attach_upgrade();
$abandon_days = intval(get_config('system','account_abandon_days'));
if($abandon_days < 1)
$abandon_days = 0;
$abandon_days = intval(get_config('system', 'account_abandon_days'));
if ($abandon_days < 1) {
$abandon_days = 0;
}
// once daily run birthday_updates and then expire in background
// once daily run birthday_updates and then expire in background
// FIXME: add birthday updates, both locally and for xprof for use
// by directory servers
// FIXME: add birthday updates, both locally and for xprof for use
// by directory servers
$d1 = intval(get_config('system','last_expire_day'));
$d2 = intval(datetime_convert('UTC','UTC','now','d'));
$d1 = intval(get_config('system', 'last_expire_day'));
$d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd'));
// Allow somebody to staggger daily activities if they have more than one site on their server,
// or if it happens at an inconvenient (busy) hour.
// Allow somebody to staggger daily activities if they have more than one site on their server,
// or if it happens at an inconvenient (busy) hour.
$h1 = intval(get_config('system','cron_hour'));
$h2 = intval(datetime_convert('UTC','UTC','now','G'));
$h1 = intval(get_config('system', 'cron_hour'));
$h2 = intval(datetime_convert('UTC', 'UTC', 'now', 'G'));
if(($d2 != $d1) && ($h1 == $h2)) {
Run::Summon( [ 'Cron_daily' ] );
}
if (($d2 != $d1) && ($h1 == $h2)) {
Run::Summon([ 'Cron_daily' ]);
}
// update any photos which didn't get imported properly
// This should be rare
// update any photos which didn't get imported properly
// This should be rare
$r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
$r = q(
"select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
and xchan_photo_date < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('1 DAY')
);
if($r) {
require_once('include/photo_factory.php');
foreach($r as $rr) {
$photos = import_remote_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
if ($photos) {
$x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
db_utcnow(),
db_quoteinterval('1 DAY')
);
if ($r) {
require_once('include/photo_factory.php');
foreach ($r as $rr) {
$photos = import_remote_xchan_photo($rr['xchan_photo_l'], $rr['xchan_hash']);
if ($photos) {
$x = q(
"update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
where xchan_hash = '%s'",
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($rr['xchan_hash'])
);
}
}
}
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($rr['xchan_hash'])
);
}
}
}
$generation = 0;
$generation = 0;
$restart = false;
$restart = false;
if(($argc > 1) && ($argv[1] == 'restart')) {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
return;
}
if (($argc > 1) && ($argv[1] == 'restart')) {
$restart = true;
$generation = intval($argv[2]);
if (! $generation) {
return;
}
}
reload_plugins();
reload_plugins();
$d = datetime_convert();
$d = datetime_convert();
// TODO check to see if there are any cronhooks before wasting a process
// TODO check to see if there are any cronhooks before wasting a process
if(! $restart)
Run::Summon( [ 'Cronhooks' ] );
if (! $restart) {
Run::Summon([ 'Cronhooks' ]);
}
set_config('system','lastcron',datetime_convert());
set_config('system', 'lastcron', datetime_convert());
//All done - clear the lockfile
@unlink($lockfile);
//All done - clear the lockfile
@unlink($lockfile);
return;
}
return;
}
}

View file

@ -1,110 +1,122 @@
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\Libzot;
class Cron_daily {
class Cron_daily
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
logger('cron_daily: start');
logger('cron_daily: start');
/**
* Cron Daily
*
*/
/**
* Cron Daily
*
*/
// make sure our own site record is up to date
Libzot::import_site(Libzot::site_info(true));
// make sure our own site record is up to date
Libzot::import_site(Libzot::site_info(true));
// Fire off the Cron_weekly process if it's the correct day.
// Fire off the Cron_weekly process if it's the correct day.
$d3 = intval(datetime_convert('UTC','UTC','now','N'));
if ($d3 == 7) {
Run::Summon( [ 'Cron_weekly' ] );
}
$d3 = intval(datetime_convert('UTC', 'UTC', 'now', 'N'));
if ($d3 == 7) {
Run::Summon([ 'Cron_weekly' ]);
}
// once daily run birthday_updates and then expire in background
// once daily run birthday_updates and then expire in background
// FIXME: add birthday updates, both locally and for xprof for use
// by directory servers
// FIXME: add birthday updates, both locally and for xprof for use
// by directory servers
update_birthdays();
update_birthdays();
// expire any read notifications over a month old
// expire any read notifications over a month old
q("delete from notify where seen = 1 and created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('60 DAY')
);
q(
"delete from notify where seen = 1 and created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('60 DAY')
);
// expire any unread notifications over a year old
// expire any unread notifications over a year old
q("delete from notify where seen = 0 and created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('1 YEAR')
);
q(
"delete from notify where seen = 0 and created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('1 YEAR')
);
//update statistics in config
require_once('include/statistics_fns.php');
update_channels_total_stat();
update_channels_active_halfyear_stat();
update_channels_active_monthly_stat();
update_local_posts_stat();
update_local_comments_stat();
//update statistics in config
require_once('include/statistics_fns.php');
update_channels_total_stat();
update_channels_active_halfyear_stat();
update_channels_active_monthly_stat();
update_local_posts_stat();
update_local_comments_stat();
// expire old delivery reports
// expire old delivery reports
$keep_reports = intval(get_config('system','expire_delivery_reports'));
if($keep_reports === 0)
$keep_reports = 10;
$keep_reports = intval(get_config('system', 'expire_delivery_reports'));
if ($keep_reports === 0) {
$keep_reports = 10;
}
q("delete from dreport where dreport_time < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval($keep_reports . ' DAY')
);
q(
"delete from dreport where dreport_time < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval($keep_reports . ' DAY')
);
// delete accounts that did not submit email verification within 3 days
// delete accounts that did not submit email verification within 3 days
$r = q("select * from register where password = 'verify' and created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('3 DAY')
);
if ($r) {
foreach ($r as $rv) {
q("DELETE FROM account WHERE account_id = %d",
intval($rv['uid'])
);
$r = q(
"select * from register where password = 'verify' and created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('3 DAY')
);
if ($r) {
foreach ($r as $rv) {
q(
"DELETE FROM account WHERE account_id = %d",
intval($rv['uid'])
);
q("DELETE FROM register WHERE id = %d",
intval($rv['id'])
);
}
}
q(
"DELETE FROM register WHERE id = %d",
intval($rv['id'])
);
}
}
// expire any expired accounts
downgrade_accounts();
// expire any expired accounts
downgrade_accounts();
Run::Summon( [ 'Expire' ] );
Run::Summon([ 'Expire' ]);
// remove xchan photos that were stored in the DB ine earlier versions
// and were migrated to filesystem storage.
// eventually this will do nothing but waste cpu cycles checking to see if anything remains.
// remove xchan photos that were stored in the DB ine earlier versions
// and were migrated to filesystem storage.
// eventually this will do nothing but waste cpu cycles checking to see if anything remains.
cleanup_xchan_photos();
cleanup_xchan_photos();
remove_obsolete_hublocs();
remove_obsolete_hublocs();
call_hooks('cron_daily',datetime_convert());
call_hooks('cron_daily', datetime_convert());
set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d')));
set_config('system', 'last_expire_day', intval(datetime_convert('UTC', 'UTC', 'now', 'd')));
/**
* End Cron Daily
*/
}
/**
* End Cron Daily
*/
}
}

View file

@ -2,77 +2,83 @@
namespace Zotlabs\Daemon;
class Cron_weekly {
class Cron_weekly
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
/**
* Cron Weekly
*
* Actions in the following block are executed once per day only on Sunday (once per week).
*
*/
/**
* Cron Weekly
*
* Actions in the following block are executed once per day only on Sunday (once per week).
*
*/
call_hooks('cron_weekly',datetime_convert());
call_hooks('cron_weekly', datetime_convert());
z_check_cert();
z_check_cert();
prune_hub_reinstalls();
prune_hub_reinstalls();
mark_orphan_hubsxchans();
mark_orphan_hubsxchans();
// Find channels that were removed in the last three weeks, but
// haven't been finally cleaned up. These should be older than 10
// days to ensure that "purgeall" messages have gone out or bounced
// or timed out.
// Find channels that were removed in the last three weeks, but
// haven't been finally cleaned up. These should be older than 10
// days to ensure that "purgeall" messages have gone out or bounced
// or timed out.
$r = q("select channel_id from channel where channel_removed = 1 and
$r = q(
"select channel_id from channel where channel_removed = 1 and
channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('21 DAY'),
db_utcnow(), db_quoteinterval('10 DAY')
);
if($r) {
foreach($r as $rv) {
channel_remove_final($rv['channel_id']);
}
}
db_utcnow(),
db_quoteinterval('21 DAY'),
db_utcnow(),
db_quoteinterval('10 DAY')
);
if ($r) {
foreach ($r as $rv) {
channel_remove_final($rv['channel_id']);
}
}
// get rid of really old poco records
// get rid of really old poco records
q("delete from xlink where xlink_updated < %s - INTERVAL %s and xlink_static = 0 ",
db_utcnow(), db_quoteinterval('14 DAY')
);
q(
"delete from xlink where xlink_updated < %s - INTERVAL %s and xlink_static = 0 ",
db_utcnow(),
db_quoteinterval('14 DAY')
);
// Check for dead sites
Run::Summon( ['Checksites' ] );
// Check for dead sites
Run::Summon(['Checksites' ]);
// clean up image cache - use site expiration or 60 days if not set or zero
// clean up image cache - use site expiration or 60 days if not set or zero
$files = glob('cache/img/*/*');
$expire_days = intval(get_config('system','default_expire_days'));
if ($expire_days <= 0) {
$expire_days = 60;
}
$now = time();
$maxage = 86400 * $expire_days;
if ($files) {
foreach ($files as $file) {
if (is_file($file)) {
if ($now - filemtime($file) >= $maxage) {
unlink($file);
}
}
}
}
$files = glob('cache/img/*/*');
$expire_days = intval(get_config('system', 'default_expire_days'));
if ($expire_days <= 0) {
$expire_days = 60;
}
$now = time();
$maxage = 86400 * $expire_days;
if ($files) {
foreach ($files as $file) {
if (is_file($file)) {
if ($now - filemtime($file) >= $maxage) {
unlink($file);
}
}
}
}
// update searchable doc indexes
// update searchable doc indexes
Run::Summon( [ 'Importdoc'] );
Run::Summon([ 'Importdoc']);
/**
* End Cron Weekly
*/
}
/**
* End Cron Weekly
*/
}
}

View file

@ -1,17 +1,21 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
class Cronhooks {
class Cronhooks
{
static public function run($argc,$argv){
public static function run($argc, $argv)
{
logger('cronhooks: start');
logger('cronhooks: start');
$d = datetime_convert();
$d = datetime_convert();
call_hooks('cron', $d);
call_hooks('cron', $d);
return;
}
return;
}
}

View file

@ -8,48 +8,53 @@ namespace Zotlabs\Daemon;
// Handles expiration of stale cookies currently by deleting them and rewriting the file.
class CurlAuth {
use App;
static public function run($argc,$argv) {
class CurlAuth
{
if($argc != 2)
return;
public static function run($argc, $argv)
{
\App::$session->start();
if ($argc != 2) {
return;
}
$_SESSION['authenticated'] = 1;
$_SESSION['uid'] = $argv[1];
App::$session->start();
$x = session_id();
$_SESSION['authenticated'] = 1;
$_SESSION['uid'] = $argv[1];
$f = 'cache/cookie_' . $argv[1];
$c = 'cache/cookien_' . $argv[1];
$x = session_id();
$e = file_exists($f);
$f = 'cache/cookie_' . $argv[1];
$c = 'cache/cookien_' . $argv[1];
$output = '';
$e = file_exists($f);
if($e) {
$lines = file($f);
if($lines) {
foreach($lines as $line) {
if(strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) {
$tokens = explode("\t", $line);
$tokens = array_map('trim', $tokens);
if($tokens[4] > time()) {
$output .= $line . "\n";
}
}
else
$output .= $line;
}
}
}
$t = time() + (24 * 3600);
file_put_contents($f, $output . 'HttpOnly_' . \App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0));
$output = '';
file_put_contents($c,$x);
if ($e) {
$lines = file($f);
if ($lines) {
foreach ($lines as $line) {
if (strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) {
$tokens = explode("\t", $line);
$tokens = array_map('trim', $tokens);
if ($tokens[4] > time()) {
$output .= $line . "\n";
}
} else {
$output .= $line;
}
}
}
}
$t = time() + (24 * 3600);
file_put_contents($f, $output . 'HttpOnly_' . App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0));
return;
}
file_put_contents($c, $x);
return;
}
}

View file

@ -1,31 +1,36 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Queue;
class Deliver
{
class Deliver {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if ($argc < 2) {
return;
}
if($argc < 2)
return;
logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
logger('deliver: invoked: ' . print_r($argv,true), LOGGER_DATA);
for ($x = 1; $x < $argc; $x++) {
if (! $argv[$x]) {
continue;
}
for($x = 1; $x < $argc; $x ++) {
if(! $argv[$x])
continue;
$r = q("select * from outq where outq_hash = '%s' limit 1",
dbesc($argv[$x])
);
if($r) {
Queue::deliver($r[0],true);
}
}
}
$r = q(
"select * from outq where outq_hash = '%s' limit 1",
dbesc($argv[$x])
);
if ($r) {
Queue::deliver($r[0], true);
}
}
}
}

View file

@ -2,22 +2,23 @@
namespace Zotlabs\Daemon;
class Deliver_hooks
{
class Deliver_hooks {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if($argc < 2)
return;
if ($argc < 2) {
return;
}
$r = q("select * from item where id = '%d'",
intval($argv[1])
);
if($r)
call_hooks('notifier_normal',$r[0]);
}
$r = q(
"select * from item where id = '%d'",
intval($argv[1])
);
if ($r) {
call_hooks('notifier_normal', $r[0]);
}
}
}

View file

@ -6,18 +6,20 @@ namespace Zotlabs\Daemon;
* Daemon to remove 'item' resources in the background from a removed connection
*/
class Delxitems {
class Delxitems
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
cli_startup();
cli_startup();
if($argc != 3) {
return;
}
if ($argc != 3) {
return;
}
remove_abook_items($argv[1],$argv[2]);
remove_abook_items($argv[1], $argv[2]);
return;
}
return;
}
}

View file

@ -2,52 +2,52 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\Queue;
class Directory
{
public static function run($argc, $argv)
{
class Directory {
if ($argc < 2) {
return;
}
static public function run($argc,$argv) {
$force = false;
$pushall = true;
if ($argc < 2) {
return;
}
if ($argc > 2) {
if ($argv[2] === 'force') {
$force = true;
}
if ($argv[2] === 'nopush') {
$pushall = false;
}
}
$force = false;
$pushall = true;
logger('directory update', LOGGER_DEBUG);
if ($argc > 2) {
if ($argv[2] === 'force') {
$force = true;
}
if ($argv[2] === 'nopush') {
$pushall = false;
}
}
$channel = channelx_by_n($argv[1]);
if (! $channel) {
return;
}
logger('directory update', LOGGER_DEBUG);
// update the local directory - was optional, but now done regardless
$channel = channelx_by_n($argv[1]);
if (! $channel) {
return;
}
Libzotdir::local_dir_update($argv[1], $force);
// update the local directory - was optional, but now done regardless
q(
"update channel set channel_dirdate = '%s' where channel_id = %d",
dbesc(datetime_convert()),
intval($channel['channel_id'])
);
Libzotdir::local_dir_update($argv[1],$force);
q("update channel set channel_dirdate = '%s' where channel_id = %d",
dbesc(datetime_convert()),
intval($channel['channel_id'])
);
// Now update all the connections
if ($pushall) {
Run::Summon( [ 'Notifier','refresh_all',$channel['channel_id'] ] );
}
}
// Now update all the connections
if ($pushall) {
Run::Summon([ 'Notifier','refresh_all',$channel['channel_id'] ]);
}
}
}

View file

@ -2,90 +2,94 @@
namespace Zotlabs\Daemon;
class Expire
{
class Expire {
public static function run($argc, $argv)
{
static public function run($argc,$argv){
cli_startup();
cli_startup();
// perform final cleanup on previously delete items
// perform final cleanup on previously delete items
$r = q(
"select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('10 DAY')
);
if ($r) {
foreach ($r as $rr) {
drop_item($rr['id'], false, DROPITEM_PHASE2);
}
}
$r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('10 DAY')
);
if ($r) {
foreach ($r as $rr) {
drop_item($rr['id'], false, DROPITEM_PHASE2);
}
}
// physically remove anything that has been deleted for more than two months
/** @FIXME - this is a wretchedly inefficient query */
// physically remove anything that has been deleted for more than two months
/** @FIXME - this is a wretchedly inefficient query */
$r = q(
"delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('36 DAY')
);
$r = q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('36 DAY')
);
logger('expire: start', LOGGER_DEBUG);
logger('expire: start', LOGGER_DEBUG);
$site_expire = intval(get_config('system', 'default_expire_days'));
$commented_days = intval(get_config('system', 'active_expire_days'));
$site_expire = intval(get_config('system', 'default_expire_days'));
$commented_days = intval(get_config('system','active_expire_days'));
logger('site_expire: ' . $site_expire);
logger('site_expire: ' . $site_expire);
$r = q("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true");
$r = q("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true");
if ($r) {
foreach ($r as $rr) {
// expire the sys channel separately
if (intval($rr['channel_system'])) {
continue;
}
if ($r) {
foreach ($r as $rr) {
// service class default (if non-zero) over-rides the site default
// expire the sys channel separately
if (intval($rr['channel_system']))
continue;
$service_class_expire = service_class_fetch($rr['channel_id'], 'expire_days');
if (intval($service_class_expire)) {
$channel_expire = $service_class_expire;
} else {
$channel_expire = $site_expire;
}
// service class default (if non-zero) over-rides the site default
if (
intval($channel_expire) && (intval($channel_expire) < intval($rr['channel_expire_days'])) ||
intval($rr['channel_expire_days'] == 0)
) {
$expire_days = $channel_expire;
} else {
$expire_days = $rr['channel_expire_days'];
}
$service_class_expire = service_class_fetch($rr['channel_id'], 'expire_days');
if (intval($service_class_expire)) {
$channel_expire = $service_class_expire;
}
else {
$channel_expire = $site_expire;
}
// if the site or service class expiration is non-zero and less than person expiration, use that
logger('Expire: ' . $rr['channel_address'] . ' interval: ' . $expire_days, LOGGER_DEBUG);
item_expire($rr['channel_id'], $expire_days, $commented_days);
}
}
if (intval($channel_expire) && (intval($channel_expire) < intval($rr['channel_expire_days'])) ||
intval($rr['channel_expire_days'] == 0)) {
$expire_days = $channel_expire;
}
else {
$expire_days = $rr['channel_expire_days'];
}
$x = get_sys_channel();
if ($x) {
// this should probably just fetch the channel_expire_days from the sys channel,
// but there's no convenient way to set it.
// if the site or service class expiration is non-zero and less than person expiration, use that
logger('Expire: ' . $rr['channel_address'] . ' interval: ' . $expire_days, LOGGER_DEBUG);
item_expire($rr['channel_id'], $expire_days, $commented_days);
}
}
$expire_days = get_config('system', 'sys_expire_days', 30);
$x = get_sys_channel();
if ($x) {
if (intval($site_expire) && (intval($site_expire) < intval($expire_days))) {
$expire_days = $site_expire;
}
// this should probably just fetch the channel_expire_days from the sys channel,
// but there's no convenient way to set it.
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
$expire_days = get_config('system', 'sys_expire_days',30);
if ($expire_days) {
item_expire($x['channel_id'], $expire_days, $commented_days);
}
if (intval($site_expire) && (intval($site_expire) < intval($expire_days))) {
$expire_days = $site_expire;
}
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
if ($expire_days) {
item_expire($x['channel_id'], $expire_days, $commented_days);
}
logger('Expire: sys: done', LOGGER_DEBUG);
}
}
logger('Expire: sys: done', LOGGER_DEBUG);
}
}
}

View file

@ -8,43 +8,45 @@ require_once('include/cli_startup.php');
require_once('include/attach.php');
require_once('include/import.php');
class File_importer {
class File_importer
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
cli_startup();
cli_startup();
$attach_id = $argv[1];
$channel_address = $argv[2];
$hz_server = urldecode($argv[3]);
$attach_id = $argv[1];
$channel_address = $argv[2];
$hz_server = urldecode($argv[3]);
$m = parse_url($hz_server);
$m = parse_url($hz_server);
$channel = channelx_by_nick($channel_address);
if(! $channel) {
logger('filehelper: channel not found');
killme();
}
$channel = channelx_by_nick($channel_address);
if (! $channel) {
logger('filehelper: channel not found');
killme();
}
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,
];
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,
];
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,false,$redirects,[ 'headers' => $headers ]);
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id, false, $redirects, [ 'headers' => $headers ]);
if(! $x['success']) {
logger('no API response',LOGGER_DEBUG);
return;
}
if (! $x['success']) {
logger('no API response', LOGGER_DEBUG);
return;
}
$j = json_decode($x['body'],true);
$j = json_decode($x['body'], true);
$r = sync_files($channel,[$j]);
$r = sync_files($channel, [$j]);
killme();
}
killme();
}
}

View file

@ -1,4 +1,6 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
@ -8,55 +10,57 @@ use Zotlabs\Lib\Zotfinger;
// performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress
class Gprobe {
class Gprobe
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
if ($argc != 2) {
return;
}
if ($argc != 2) {
return;
}
$url = hex2bin($argv[1]);
$protocols = [];
$url = hex2bin($argv[1]);
$protocols = [];
if (! strpos($url,'@')) {
return;
}
if (! strpos($url, '@')) {
return;
}
$r = q("select * from hubloc where hubloc_addr = '%s'",
dbesc($url)
);
$r = q(
"select * from hubloc where hubloc_addr = '%s'",
dbesc($url)
);
if ($r) {
foreach ($r as $rv) {
if ($rv['hubloc_network'] === 'activitypub') {
$protocols[] = 'activitypub';
continue;
}
if ($r) {
foreach ($r as $rv) {
if ($rv['hubloc_network'] === 'activitypub') {
$protocols[] = 'activitypub';
continue;
}
if ($rv['hubloc_network'] === 'nomad') {
$protocols[] = 'nomad';
$protocols[] = 'zot6';
continue;
}
if ($rv['hubloc_network'] === 'zot6') {
$protocols[] = 'zot6';
continue;
}
}
}
if (! in_array('zot6',$protocols)) {
$href = Webfinger::zot_url(punify($url));
if ($href) {
$zf = Zotfinger::exec($href,$channel);
if ($rv['hubloc_network'] === 'zot6') {
$protocols[] = 'zot6';
continue;
}
}
if (is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid']) && isset($zf['data']) && $zf['data']) {
$xc = Libzot::import_xchan($zf['data']);
}
}
}
return;
}
if (! in_array('zot6', $protocols)) {
$href = Webfinger::zot_url(punify($url));
if ($href) {
$zf = Zotfinger::exec($href, $channel);
}
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid']) && isset($zf['data']) && $zf['data']) {
$xc = Libzot::import_xchan($zf['data']);
}
}
return;
}
}

View file

@ -2,50 +2,50 @@
namespace Zotlabs\Daemon;
class Importdoc
{
class Importdoc {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
require_once('include/help.php');
require_once('include/help.php');
self::update_docs_dir('doc/*');
}
self::update_docs_dir('doc/*');
}
static public function update_docs_dir($s) {
$f = basename($s);
$d = dirname($s);
if($s === 'doc/html')
return;
$files = glob("$d/$f");
if($files) {
foreach($files as $fi) {
if($fi === 'doc/html') {
continue;
}
if(is_dir($fi)) {
self::update_docs_dir("$fi/*");
}
else {
// don't update media content
if(strpos(z_mime_content_type($fi),'text') === 0) {
store_doc_file($fi);
}
}
}
}
// remove old files that weren't updated (indicates they were most likely deleted).
$i = q("select * from item where item_type = 5 and edited < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('14 DAY')
);
if ($i) {
foreach ($i as $iv) {
drop_item($iv['id'],false,DROPITEM_NORMAL,true);
}
}
}
public static function update_docs_dir($s)
{
$f = basename($s);
$d = dirname($s);
if ($s === 'doc/html') {
return;
}
$files = glob("$d/$f");
if ($files) {
foreach ($files as $fi) {
if ($fi === 'doc/html') {
continue;
}
if (is_dir($fi)) {
self::update_docs_dir("$fi/*");
} else {
// don't update media content
if (strpos(z_mime_content_type($fi), 'text') === 0) {
store_doc_file($fi);
}
}
}
}
// remove old files that weren't updated (indicates they were most likely deleted).
$i = q(
"select * from item where item_type = 5 and edited < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('14 DAY')
);
if ($i) {
foreach ($i as $iv) {
drop_item($iv['id'], false, DROPITEM_NORMAL, true);
}
}
}
}

View file

@ -1,49 +1,57 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libsync;
class Importfile {
class Importfile
{
static public function run($argc,$argv){
public static function run($argc, $argv)
{
logger('Importfile: ' . print_r($argv,true));
logger('Importfile: ' . print_r($argv, true));
if($argc < 3)
return;
if ($argc < 3) {
return;
}
$channel = channelx_by_n($argv[1]);
if(! $channel)
return;
$channel = channelx_by_n($argv[1]);
if (! $channel) {
return;
}
$srcfile = $argv[2];
$folder = (($argc > 3) ? $argv[3] : '');
$dstname = (($argc > 4) ? $argv[4] : '');
$srcfile = $argv[2];
$folder = (($argc > 3) ? $argv[3] : '');
$dstname = (($argc > 4) ? $argv[4] : '');
$hash = random_string();
$hash = random_string();
$arr = [
'src' => $srcfile,
'filename' => (($dstname) ? $dstname : basename($srcfile)),
'hash' => $hash,
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid'],
'preserve_original' => true,
'replace' => true
];
$arr = [
'src' => $srcfile,
'filename' => (($dstname) ? $dstname : basename($srcfile)),
'hash' => $hash,
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid'],
'preserve_original' => true,
'replace' => true
];
if($folder)
$arr['folder'] = $folder;
if ($folder) {
$arr['folder'] = $folder;
}
attach_store($channel,$channel['channel_hash'],'import',$arr);
attach_store($channel, $channel['channel_hash'], 'import', $arr);
$sync = attach_export_data($channel,$hash);
if($sync)
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
$sync = attach_export_data($channel, $hash);
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync)));
}
return;
}
return;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,75 +1,87 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzotdir;
class Onedirsync
{
class Onedirsync {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
logger('onedirsync: start ' . intval($argv[1]));
logger('onedirsync: start ' . intval($argv[1]));
if (($argc > 1) && (intval($argv[1]))) {
$update_id = intval($argv[1]);
}
if(($argc > 1) && (intval($argv[1])))
$update_id = intval($argv[1]);
if (! $update_id) {
logger('onedirsync: no update');
return;
}
if(! $update_id) {
logger('onedirsync: no update');
$r = q(
"select * from updates where ud_id = %d limit 1",
intval($update_id)
);
if (! $r) {
return;
}
if (($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr'])) {
return;
}
// Have we probed this channel more recently than the other directory server
// (where we received this update from) ?
// If we have, we don't need to do anything except mark any older entries updated
$x = q(
"select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d )>0 order by ud_date desc limit 1",
dbesc($r[0]['ud_addr']),
dbesc($r[0]['ud_date']),
intval(UPDATE_FLAGS_UPDATED)
);
if ($x) {
$y = q(
"update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
intval(UPDATE_FLAGS_UPDATED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED),
dbesc($x[0]['ud_date'])
);
return;
}
// ignore doing an update if this ud_addr refers to a known dead hubloc
$h = q(
"select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($r[0]['ud_addr'])
);
if (($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) {
$y = q(
"update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
intval(UPDATE_FLAGS_UPDATED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED)
);
return;
}
// we might have to pull this out some day, but for now update_directory_entry()
// runs zot_finger() and is kind of zot specific
if ($h && in_array($h[0]['hubloc_network'],['nomad','zot6'])) {
return;
}
$r = q("select * from updates where ud_id = %d limit 1",
intval($update_id)
);
Libzotdir::update_directory_entry($r[0]);
if(! $r)
return;
if(($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr']))
return;
// Have we probed this channel more recently than the other directory server
// (where we received this update from) ?
// If we have, we don't need to do anything except mark any older entries updated
$x = q("select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d ) > 0 order by ud_date desc limit 1",
dbesc($r[0]['ud_addr']),
dbesc($r[0]['ud_date']),
intval(UPDATE_FLAGS_UPDATED)
);
if($x) {
$y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
intval(UPDATE_FLAGS_UPDATED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED),
dbesc($x[0]['ud_date'])
);
return;
}
// ignore doing an update if this ud_addr refers to a known dead hubloc
$h = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($r[0]['ud_addr'])
);
if(($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) {
$y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
intval(UPDATE_FLAGS_UPDATED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED)
);
return;
}
// we might have to pull this out some day, but for now update_directory_entry()
// runs zot_finger() and is kind of zot specific
if($h && in_array($h[0]['hubloc_network'],['nomad','zot6']))
return;
Libzotdir::update_directory_entry($r[0]);
return;
}
return;
}
}

View file

@ -1,4 +1,6 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
@ -7,164 +9,171 @@ use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ASCollection;
require_once('include/socgraph.php');
class Onepoll {
class Onepoll
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
logger('onepoll: start');
logger('onepoll: start');
if(($argc > 1) && (intval($argv[1])))
$contact_id = intval($argv[1]);
if (($argc > 1) && (intval($argv[1]))) {
$contact_id = intval($argv[1]);
}
if(! $contact_id) {
logger('onepoll: no contact');
return;
}
if (! $contact_id) {
logger('onepoll: no contact');
return;
}
$d = datetime_convert();
$d = datetime_convert();
$contacts = q("SELECT abook.*, xchan.*, account.*
$contacts = q(
"SELECT abook.*, xchan.*, account.*
FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
where abook_id = %d
and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
intval($contact_id),
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED)
);
intval($contact_id),
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED)
);
if(! $contacts) {
logger('onepoll: abook_id not found: ' . $contact_id);
return;
}
if (! $contacts) {
logger('onepoll: abook_id not found: ' . $contact_id);
return;
}
$contact = array_shift($contacts);
$contact = array_shift($contacts);
$t = $contact['abook_updated'];
$t = $contact['abook_updated'];
$importer_uid = $contact['abook_channel'];
$importer_uid = $contact['abook_channel'];
$r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
intval($importer_uid)
);
$r = q(
"SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
intval($importer_uid)
);
if(! $r)
return;
if (! $r) {
return;
}
$importer = $r[0];
$importer = $r[0];
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
? datetime_convert('UTC','UTC','now - 7 days')
: datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days')
);
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
? datetime_convert('UTC', 'UTC', 'now - 7 days')
: datetime_convert('UTC', 'UTC', $contact['abook_updated'] . ' - 2 days')
);
if(in_array($contact['xchan_network'],['nomad']['zot6'])) {
if (in_array($contact['xchan_network'],['nomad']['zot6'])) {
// update permissions
// update permissions
$x = Libzot::refresh($contact, $importer);
$x = Libzot::refresh($contact,$importer);
$responded = false;
$updated = datetime_convert();
$connected = datetime_convert();
if (! $x) {
// mark for death by not updating abook_connected, this is caught in include/poller.php
q(
"update abook set abook_updated = '%s' where abook_id = %d",
dbesc($updated),
intval($contact['abook_id'])
);
} else {
q(
"update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
dbesc($updated),
dbesc($connected),
intval($contact['abook_id'])
);
$responded = true;
}
$responded = false;
$updated = datetime_convert();
$connected = datetime_convert();
if(! $x) {
// mark for death by not updating abook_connected, this is caught in include/poller.php
q("update abook set abook_updated = '%s' where abook_id = %d",
dbesc($updated),
intval($contact['abook_id'])
);
}
else {
q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
dbesc($updated),
dbesc($connected),
intval($contact['abook_id'])
);
$responded = true;
}
if (! $responded) {
return;
}
}
if (! $responded) {
return;
}
}
$fetch_feed = true;
$fetch_feed = true;
// They haven't given us permission to see their stream
// They haven't given us permission to see their stream
$can_view_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'their_perms', 'view_stream'));
$can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream'));
if (! $can_view_stream) {
$fetch_feed = false;
}
if (! $can_view_stream) {
$fetch_feed = false;
}
// we haven't given them permission to send us their stream
// we haven't given them permission to send us their stream
$can_send_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'my_perms', 'send_stream'));
$can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream'));
if (! $can_send_stream) {
$fetch_feed = false;
}
if (! $can_send_stream) {
$fetch_feed = false;
}
if ($contact['abook_created'] < datetime_convert('UTC', 'UTC', 'now - 1 week')) {
$fetch_feed = false;
}
if ($contact['abook_created'] < datetime_convert('UTC','UTC', 'now - 1 week')) {
$fetch_feed = false;
}
// In previous releases there was a mechanism to fetch 'external' or public stream posts from a site
// (as opposed to a channel). This mechanism was deprecated as there is no reliable/scalable method
// for informing downstream publishers when/if the content has expired or been deleted.
// We can use the ThreadListener interface to implement this on the owner's outbox, however this is still a
// work in progress and may present scaling issues. Making this work correctly with third-party fetches is
// prohibitive as deletion requests would need to be relayed over potentially hostile networks.
// In previous releases there was a mechanism to fetch 'external' or public stream posts from a site
// (as opposed to a channel). This mechanism was deprecated as there is no reliable/scalable method
// for informing downstream publishers when/if the content has expired or been deleted.
// We can use the ThreadListener interface to implement this on the owner's outbox, however this is still a
// work in progress and may present scaling issues. Making this work correctly with third-party fetches is
// prohibitive as deletion requests would need to be relayed over potentially hostile networks.
if ($fetch_feed) {
$max = intval(get_config('system', 'max_imported_posts', 20));
if (intval($max)) {
$cl = get_xconfig($xchan, 'activitypub', 'collections');
if (is_array($cl) && $cl) {
$url = ((array_key_exists('outbox', $cl)) ? $cl['outbox'] : '');
if ($url) {
logger('fetching outbox');
$url = $url . '?date_begin=' . urlencode($last_update);
$obj = new ASCollection($url, $importer, 0, $max);
$messages = $obj->get();
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $importer);
}
if (is_array($message)) {
$AS = new ActivityStreams($message, null, true);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS, true);
if ($item) {
Activity::store($importer, $contact['abook_xchan'], $AS, $item, true, true);
}
}
}
}
}
}
}
}
}
if($fetch_feed) {
$max = intval(get_config('system','max_imported_posts',20));
if (intval($max)) {
$cl = get_xconfig($xchan,'activitypub','collections');
if (is_array($cl) && $cl) {
$url = ((array_key_exists('outbox',$cl)) ? $cl['outbox'] : '');
if ($url) {
logger('fetching outbox');
$url = $url . '?date_begin=' . urlencode($last_update);
$obj = new ASCollection($url, $importer, 0, $max);
$messages = $obj->get();
if ($messages) {
foreach($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message,$importer);
}
if (is_array($message)) {
$AS = new ActivityStreams($message,null,true);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS,true);
if ($item) {
Activity::store($importer,$contact['abook_xchan'],$AS, $item, true, true);
}
}
}
}
}
}
}
}
}
// update the poco details for this connection
// update the poco details for this connection
$r = q("SELECT xlink_id from xlink
$r = q(
"SELECT xlink_id from xlink
where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1",
intval($contact['xchan_hash']),
db_utcnow(), db_quoteinterval('7 DAY')
);
if(! $r) {
poco_load($contact['xchan_hash'],$contact['xchan_connurl']);
}
return;
}
intval($contact['xchan_hash']),
db_utcnow(),
db_quoteinterval('7 DAY')
);
if (! $r) {
poco_load($contact['xchan_hash'], $contact['xchan_connurl']);
}
return;
}
}

View file

@ -1,79 +1,90 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
class Poller {
class Poller
{
static public function run($argc,$argv) {
public static function run($argc, $argv)
{
$maxsysload = intval(get_config('system','maxloadavg'));
if($maxsysload < 1)
$maxsysload = 50;
if(function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if(intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
return;
}
}
$maxsysload = intval(get_config('system', 'maxloadavg'));
if ($maxsysload < 1) {
$maxsysload = 50;
}
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if (intval($load[0]) > $maxsysload) {
logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
return;
}
}
$interval = intval(get_config('system','poll_interval'));
if(! $interval)
$interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
$interval = intval(get_config('system', 'poll_interval'));
if (! $interval) {
$interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval')));
}
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'cache/poller';
if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
&& (! get_config('system','override_poll_lockfile'))) {
logger("poller: Already running");
return;
}
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'cache/poller';
if (
(file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
&& (! get_config('system', 'override_poll_lockfile'))
) {
logger("poller: Already running");
return;
}
// Create a lockfile.
file_put_contents($lockfile, EMPTY_STR);
// Create a lockfile.
file_put_contents($lockfile, EMPTY_STR);
logger('poller: start');
logger('poller: start');
$manual_id = 0;
$generation = 0;
$manual_id = 0;
$generation = 0;
$force = false;
$restart = false;
$force = false;
$restart = false;
if(($argc > 1) && ($argv[1] == 'force'))
$force = true;
if (($argc > 1) && ($argv[1] == 'force')) {
$force = true;
}
if(($argc > 1) && ($argv[1] == 'restart')) {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
return;
}
if (($argc > 1) && ($argv[1] == 'restart')) {
$restart = true;
$generation = intval($argv[2]);
if (! $generation) {
return;
}
}
if(($argc > 1) && intval($argv[1])) {
$manual_id = intval($argv[1]);
$force = true;
}
if (($argc > 1) && intval($argv[1])) {
$manual_id = intval($argv[1]);
$force = true;
}
$sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : "");
$sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : "");
reload_plugins();
reload_plugins();
$d = datetime_convert();
$d = datetime_convert();
// Only poll from those with suitable relationships
// Only poll from those with suitable relationships
// $abandon_sql = (($abandon_days)
// ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY'))
// : ''
// );
// $abandon_sql = (($abandon_days)
// ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY'))
// : ''
// );
$abandon_sql = EMPTY_STR;
$abandon_sql = EMPTY_STR;
$randfunc = db_getfunc('RAND');
$randfunc = db_getfunc('RAND');
$contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
$contacts = q(
"SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
abook.abook_channel, abook.abook_id, abook.abook_archived, abook.abook_pending,
abook.abook_ignored, abook.abook_blocked,
xchan.xchan_network,
@ -83,109 +94,115 @@ class Poller {
where abook_self = 0
$sql_extra
AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED) // FIXME
);
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED) // FIXME
);
if($contacts) {
if ($contacts) {
foreach ($contacts as $contact) {
$update = false;
foreach($contacts as $contact) {
$t = $contact['abook_updated'];
$c = $contact['abook_connected'];
$update = false;
if (intval($contact['abook_feed'])) {
$min = service_class_fetch($contact['abook_channel'], 'minimum_feedcheck_minutes');
if (! $min) {
$min = intval(get_config('system', 'minimum_feedcheck_minutes'));
}
if (! $min) {
$min = 60;
}
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
if ($c < $x) {
Run::Summon([ 'Onepoll', $contact['abook_id'] ]);
if ($interval) {
@time_sleep_until(microtime(true) + (float) $interval);
}
}
continue;
}
$t = $contact['abook_updated'];
$c = $contact['abook_connected'];
if(intval($contact['abook_feed'])) {
$min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes');
if(! $min)
$min = intval(get_config('system','minimum_feedcheck_minutes'));
if(! $min)
$min = 60;
$x = datetime_convert('UTC','UTC',"now - $min minutes");
if($c < $x) {
Run::Summon( [ 'Onepoll', $contact['abook_id'] ] );
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
if (! in_array($contact['xchan_network'],['nomad','zot6'])) {
continue;
}
if ($c == $t) {
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
$update = true;
}
} else {
// if we've never connected with them, start the mark for death countdown from now
if(! in_array($contact['xchan_network'],['nomad','zot6']))
continue;
if ($c <= NULL_DATE) {
$r = q(
"update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
$c = datetime_convert();
$update = true;
}
if($c == $t) {
if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
$update = true;
}
else {
// He's dead, Jim
// if we've never connected with them, start the mark for death countdown from now
if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 30 day")) > 0) {
$r = q(
"update abook set abook_archived = 1 where abook_id = %d",
intval($contact['abook_id'])
);
$update = false;
continue;
}
if($c <= NULL_DATE) {
$r = q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
$c = datetime_convert();
$update = true;
}
if (intval($contact['abook_archived'])) {
$update = false;
continue;
}
// He's dead, Jim
// might be dead, so maybe don't poll quite so often
if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) {
$r = q("update abook set abook_archived = 1 where abook_id = %d",
intval($contact['abook_id'])
);
$update = false;
continue;
}
// recently deceased, so keep up the regular schedule for 3 days
if(intval($contact['abook_archived'])) {
$update = false;
continue;
}
if (
(strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $c . " + 3 day")) > 0)
&& (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 1 day")) > 0)
) {
$update = true;
}
// might be dead, so maybe don't poll quite so often
// After that back off and put them on a morphine drip
// recently deceased, so keep up the regular schedule for 3 days
if (strcmp(datetime_convert('UTC', 'UTC', 'now'), datetime_convert('UTC', 'UTC', $t . " + 2 day")) > 0) {
$update = true;
}
}
if((strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 3 day")) > 0)
&& (strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 1 day")) > 0))
$update = true;
if (intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked'])) {
continue;
}
// After that back off and put them on a morphine drip
if ((! $update) && (! $force)) {
continue;
}
if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 2 day")) > 0) {
$update = true;
}
Run::Summon([ 'Onepoll',$contact['abook_id'] ]);
if ($interval) {
@time_sleep_until(microtime(true) + (float) $interval);
}
}
}
}
// migrate a few photos - eventually we'll migrate them all but without killing somebody's site
// trying to do them all at once
if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked']))
continue;
migrate_xchan_photos(5);
if((! $update) && (! $force))
continue;
set_config('system', 'lastpoll', datetime_convert());
Run::Summon( [ 'Onepoll',$contact['abook_id'] ] );
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
//All done - clear the lockfile
@unlink($lockfile);
}
}
// migrate a few photos - eventually we'll migrate them all but without killing somebody's site
// trying to do them all at once
migrate_xchan_photos(5);
set_config('system','lastpoll',datetime_convert());
//All done - clear the lockfile
@unlink($lockfile);
return;
}
return;
}
}

View file

@ -1,82 +1,94 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
use Zotlabs\Lib as Zlib;
class Queue
{
class Queue {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if ($argc > 1) {
$queue_id = $argv[1];
} else {
$queue_id = EMPTY_STR;
}
if($argc > 1)
$queue_id = $argv[1];
else
$queue_id = EMPTY_STR;
logger('queue: start');
logger('queue: start');
// delete all queue items more than 3 days old
// but first mark these sites dead if we haven't heard from them in a month
// delete all queue items more than 3 days old
// but first mark these sites dead if we haven't heard from them in a month
$r = q(
"select outq_posturl from outq where outq_created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('3 DAY')
);
if ($r) {
foreach ($r as $rr) {
$site_url = '';
$h = parse_url($rr['outq_posturl']);
$desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
q(
"update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
dbesc($desturl),
db_utcnow(),
db_quoteinterval('1 MONTH')
);
}
}
$r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('3 DAY')
);
if($r) {
foreach($r as $rr) {
$site_url = '';
$h = parse_url($rr['outq_posturl']);
$desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
dbesc($desturl),
db_utcnow(), db_quoteinterval('1 MONTH')
);
}
}
$r = q(
"DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('3 DAY')
);
$r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('3 DAY')
);
if ($queue_id) {
$r = q(
"SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
dbesc($queue_id)
);
} else {
// For the first 12 hours we'll try to deliver every 15 minutes
// After that, we'll only attempt delivery once per hour.
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
// so that we don't start off a thousand deliveries for a couple of dead hubs.
// The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
// Other drivers will have to do something different here and may need their own query.
if($queue_id) {
$r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
dbesc($queue_id)
);
}
else {
// For the first 12 hours we'll try to deliver every 15 minutes
// After that, we'll only attempt delivery once per hour.
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
// so that we don't start off a thousand deliveries for a couple of dead hubs.
// The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
// Other drivers will have to do something different here and may need their own query.
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
// "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
// or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
// or twice a day.
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
// "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
// or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
// or twice a day.
$sqlrandfunc = db_getfunc('rand');
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
db_utcnow()
);
while ($r) {
foreach($r as $rv) {
Zlib\Queue::deliver($rv);
}
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
db_utcnow()
);
}
}
if(! $r)
return;
$r = q(
"SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
db_utcnow()
);
while ($r) {
foreach ($r as $rv) {
Zlib\Queue::deliver($rv);
}
$r = q(
"SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
db_utcnow()
);
}
}
if (! $r) {
return;
}
foreach($r as $rv) {
Zlib\Queue::deliver($rv);
}
}
foreach ($r as $rv) {
Zlib\Queue::deliver($rv);
}
}
}

View file

@ -2,74 +2,76 @@
namespace Zotlabs\Daemon;
if (array_search( __file__ , get_included_files()) === 0) {
if (array_search(__file__, get_included_files()) === 0) {
require_once('include/cli_startup.php');
array_shift($argv);
$argc = count($argv);
require_once('include/cli_startup.php');
array_shift($argv);
$argc = count($argv);
if ($argc) {
Run::Release($argc,$argv);
}
return;
if ($argc) {
Run::Release($argc, $argv);
}
return;
}
class Run {
class Run
{
// These processes should be ignored by addons which enforce timeouts (e.g. queueworker)
// as it could result in corrupt data. Please add additional long running tasks to this list as they arise.
// Ideally the queueworker should probably be provided an allow list rather than a deny list as it will be easier
// to maintain. This was a quick hack to fix truncation of very large synced files when the queueworker addon is installed.
// These processes should be ignored by addons which enforce timeouts (e.g. queueworker)
// as it could result in corrupt data. Please add additional long running tasks to this list as they arise.
// Ideally the queueworker should probably be provided an allow list rather than a deny list as it will be easier
// to maintain. This was a quick hack to fix truncation of very large synced files when the queueworker addon is installed.
public static $long_running = [ 'Addon', 'Channel_purge', 'Checksites', 'Content_importer', 'Convo',
'Cron', 'Cron_daily', 'Cron_weekly', 'Delxitems', 'Expire', 'File_importer', 'Importfile'
];
public static $long_running = [ 'Addon', 'Channel_purge', 'Checksites', 'Content_importer', 'Convo',
'Cron', 'Cron_daily', 'Cron_weekly', 'Delxitems', 'Expire', 'File_importer', 'Importfile'
];
static public function Summon($arr) {
if (file_exists('maintenance_lock') || file_exists('cache/maintenance_lock')) {
return;
}
public static function Summon($arr)
{
if (file_exists('maintenance_lock') || file_exists('cache/maintenance_lock')) {
return;
}
$hookinfo = [
'argv' => $arr,
'long_running' => self::$long_running
];
$hookinfo = [
'argv' => $arr,
'long_running' => self::$long_running
];
call_hooks('daemon_summon', $hookinfo);
call_hooks('daemon_summon', $hookinfo);
$arr = $hookinfo['argv'];
$argc = count($arr);
$arr = $hookinfo['argv'];
$argc = count($arr);
if ((! is_array($arr) || ($argc < 1))) {
logger("Summon handled by hook.", LOGGER_DEBUG);
return;
}
if ((! is_array($arr) || ($argc < 1))) {
logger("Summon handled by hook.", LOGGER_DEBUG);
return;
}
proc_run('php','Zotlabs/Daemon/Run.php',$arr);
}
proc_run('php', 'Zotlabs/Daemon/Run.php', $arr);
}
static public function Release($argc,$argv) {
cli_startup();
public static function Release($argc, $argv)
{
cli_startup();
$hookinfo = [
'argv' => $argv,
'long_running' => self::$long_running
];
$hookinfo = [
'argv' => $argv,
'long_running' => self::$long_running
];
call_hooks('daemon_release', $hookinfo);
call_hooks('daemon_release', $hookinfo);
$argv = $hookinfo['argv'];
$argc = count($argv);
$argv = $hookinfo['argv'];
$argc = count($argv);
if ((! is_array($argv) || ($argc < 1))) {
logger("Release handled by hook.", LOGGER_DEBUG);
return;
}
if ((! is_array($argv) || ($argc < 1))) {
logger("Release handled by hook.", LOGGER_DEBUG);
return;
}
logger('Run: release: ' . print_r($argv,true), LOGGER_ALL,LOG_DEBUG);
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
$cls::run($argc,$argv);
}
logger('Run: release: ' . print_r($argv, true), LOGGER_ALL, LOG_DEBUG);
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
$cls::run($argc, $argv);
}
}

View file

@ -1,79 +1,85 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
class Thumbnail
{
class Thumbnail {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if (! ($argc == 2)) {
return;
}
if (! ($argc == 2)) {
return;
}
$c = q(
"select * from attach where hash = '%s' ",
dbesc($argv[1])
);
$c = q("select * from attach where hash = '%s' ",
dbesc($argv[1])
);
if (! $c) {
return;
}
if (! $c) {
return;
}
$attach = $c[0];
$attach = $c[0];
$preview_style = intval(get_config('system', 'thumbnail_security', 0));
$preview_width = intval(get_config('system', 'thumbnail_width', 300));
$preview_height = intval(get_config('system', 'thumbnail_height', 300));
$preview_style = intval(get_config('system','thumbnail_security',0));
$preview_width = intval(get_config('system','thumbnail_width',300));
$preview_height = intval(get_config('system','thumbnail_height',300));
$p = [
'attach' => $attach,
'preview_style' => $preview_style,
'preview_width' => $preview_width,
'preview_height' => $preview_height,
'thumbnail' => null
];
$p = [
'attach' => $attach,
'preview_style' => $preview_style,
'preview_width' => $preview_width,
'preview_height' => $preview_height,
'thumbnail' => null
];
/**
* @hooks thumbnail
* * \e array \b attach
* * \e int \b preview_style
* * \e int \b preview_width
* * \e int \b preview_height
* * \e string \b thumbnail
*/
/**
* @hooks thumbnail
* * \e array \b attach
* * \e int \b preview_style
* * \e int \b preview_width
* * \e int \b preview_height
* * \e string \b thumbnail
*/
call_hooks('thumbnail', $p);
if ($p['thumbnail']) {
return;
}
call_hooks('thumbnail',$p);
if ($p['thumbnail']) {
return;
}
$default_controller = null;
$default_controller = null;
$files = glob('Zotlabs/Thumbs/*.php');
if ($files) {
foreach ($files as $f) {
$clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f,'.php'));
if (class_exists($clsname)) {
$x = new $clsname();
if (method_exists($x,'Match')) {
$matched = $x->Match($attach['filetype']);
if ($matched) {
$x->Thumb($attach,$preview_style,$preview_width,$preview_height);
}
}
if (method_exists($x,'MatchDefault')) {
$default_matched = $x->MatchDefault(substr($attach['filetype'],0,strpos($attach['filetype'],'/')));
if ($default_matched) {
$default_controller = $x;
}
}
}
}
}
if (($default_controller)
&& ((! file_exists(dbunescbin($attach['content']) . '.thumb'))
|| (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) {
$default_controller->Thumb($attach,$preview_style,$preview_width,$preview_height);
}
}
$files = glob('Zotlabs/Thumbs/*.php');
if ($files) {
foreach ($files as $f) {
$clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f, '.php'));
if (class_exists($clsname)) {
$x = new $clsname();
if (method_exists($x, 'Match')) {
$matched = $x->Match($attach['filetype']);
if ($matched) {
$x->Thumb($attach, $preview_style, $preview_width, $preview_height);
}
}
if (method_exists($x, 'MatchDefault')) {
$default_matched = $x->MatchDefault(substr($attach['filetype'], 0, strpos($attach['filetype'], '/')));
if ($default_matched) {
$default_controller = $x;
}
}
}
}
}
if (
($default_controller)
&& ((! file_exists(dbunescbin($attach['content']) . '.thumb'))
|| (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))
) {
$default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height);
}
}
}

View file

@ -1,35 +1,39 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Daemon;
class Xchan_photo
{
class Xchan_photo {
public static function run($argc, $argv)
{
static public function run($argc,$argv) {
if ($argc != 3) {
return;
}
if ($argc != 3) {
return;
}
$url = hex2bin($argv[1]);
$xchan = hex2bin($argv[2]);
$url = hex2bin($argv[1]);
$xchan = hex2bin($argv[2]);
// Some photo sources hang after connect and aren't caught by curl timeout
// Some photo sources hang after connect and aren't caught by curl timeout
set_time_limit(90);
set_time_limit(90);
$photos = import_remote_xchan_photo($url, $xchan);
if ($photos) {
$r = q(
"update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
dbescdate(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($xchan)
);
}
$photos = import_remote_xchan_photo($url,$xchan);
if ($photos) {
$r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
dbescdate(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($xchan)
);
}
return;
}
return;
}
}

View file

@ -8,118 +8,129 @@ use App;
* @brief Hook class.
*
*/
class Hook {
class Hook
{
static public function register($hook,$file,$function,$version = 1,$priority = 0) {
if (is_array($function)) {
$function = serialize($function);
}
public static function register($hook, $file, $function, $version = 1, $priority = 0)
{
if (is_array($function)) {
$function = serialize($function);
}
$r = q("SELECT * FROM hook WHERE hook = '%s' AND file = '%s' AND fn = '%s' and priority = %d and hook_version = %d LIMIT 1",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
if ($r) {
return true;
}
$r = q(
"SELECT * FROM hook WHERE hook = '%s' AND file = '%s' AND fn = '%s' and priority = %d and hook_version = %d LIMIT 1",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
if ($r) {
return true;
}
// To aid in upgrade and transition, remove old settings for any registered hooks that match in all respects except
// for priority or hook_version
// To aid in upgrade and transition, remove old settings for any registered hooks that match in all respects except
// for priority or hook_version
$r = q("DELETE FROM hook where hook = '%s' and file = '%s' and fn = '%s'",
dbesc($hook),
dbesc($file),
dbesc($function)
);
$r = q(
"DELETE FROM hook where hook = '%s' and file = '%s' and fn = '%s'",
dbesc($hook),
dbesc($file),
dbesc($function)
);
$r = q("INSERT INTO hook (hook, file, fn, priority, hook_version) VALUES ( '%s', '%s', '%s', %d, %d )",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
$r = q(
"INSERT INTO hook (hook, file, fn, priority, hook_version) VALUES ( '%s', '%s', '%s', %d, %d )",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
return $r;
}
return $r;
}
static public function register_array($file,$arr) {
if ($arr) {
foreach ($arr as $k => $v) {
self::register($k,$file,$v);
}
}
}
public static function register_array($file, $arr)
{
if ($arr) {
foreach ($arr as $k => $v) {
self::register($k, $file, $v);
}
}
}
static public function unregister($hook,$file,$function,$version = 1,$priority = 0) {
if (is_array($function)) {
$function = serialize($function);
}
$r = q("DELETE FROM hook WHERE hook = '%s' AND file = '%s' AND fn = '%s' and priority = %d and hook_version = %d",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
public static function unregister($hook, $file, $function, $version = 1, $priority = 0)
{
if (is_array($function)) {
$function = serialize($function);
}
$r = q(
"DELETE FROM hook WHERE hook = '%s' AND file = '%s' AND fn = '%s' and priority = %d and hook_version = %d",
dbesc($hook),
dbesc($file),
dbesc($function),
intval($priority),
intval($version)
);
return $r;
}
return $r;
}
/**
* @brief Unregister all hooks with this file component.
*
* Useful for addon upgrades where you want to clean out old interfaces.
*
* @param string $file
*/
/**
* @brief Unregister all hooks with this file component.
*
* Useful for addon upgrades where you want to clean out old interfaces.
*
* @param string $file
*/
static public function unregister_by_file($file) {
$r = q("DELETE FROM hook WHERE file = '%s' ",
dbesc($file)
);
public static function unregister_by_file($file)
{
$r = q(
"DELETE FROM hook WHERE file = '%s' ",
dbesc($file)
);
return $r;
}
return $r;
}
/**
* @brief Inserts a hook into a page request.
*
* Insert a short-lived hook into the running page request.
* Hooks are normally persistent so that they can be called
* across asynchronous processes such as delivery and poll
* processes.
*
* insert_hook lets you attach a hook callback immediately
* which will not persist beyond the life of this page request
* or the current process.
*
* @param string $hook
* name of hook to attach callback
* @param string $fn
* function name of callback handler
* @param int $version
* hook interface version, 0 uses two callback params, 1 uses one callback param
* @param int $priority
* currently not implemented in this function, would require the hook array to be resorted
*/
static public function insert($hook, $fn, $version = 0, $priority = 0) {
if (is_array($fn)) {
$fn = serialize($fn);
}
/**
* @brief Inserts a hook into a page request.
*
* Insert a short-lived hook into the running page request.
* Hooks are normally persistent so that they can be called
* across asynchronous processes such as delivery and poll
* processes.
*
* insert_hook lets you attach a hook callback immediately
* which will not persist beyond the life of this page request
* or the current process.
*
* @param string $hook
* name of hook to attach callback
* @param string $fn
* function name of callback handler
* @param int $version
* hook interface version, 0 uses two callback params, 1 uses one callback param
* @param int $priority
* currently not implemented in this function, would require the hook array to be resorted
*/
public static function insert($hook, $fn, $version = 0, $priority = 0)
{
if (is_array($fn)) {
$fn = serialize($fn);
}
if (! is_array(App::$hooks)) {
App::$hooks = [];
}
if (! is_array(App::$hooks)) {
App::$hooks = [];
}
if (! array_key_exists($hook, App::$hooks)) {
App::$hooks[$hook] = [];
}
if (! array_key_exists($hook, App::$hooks)) {
App::$hooks[$hook] = [];
}
App::$hooks[$hook][] = [ '', $fn, $priority, $version ];
}
App::$hooks[$hook][] = [ '', $fn, $priority, $version ];
}
}

View file

@ -2,47 +2,51 @@
namespace Zotlabs\Extend;
class Route
{
class Route {
public static function register($file, $modname)
{
$rt = self::get();
$rt[] = [$file, $modname];
self::set($rt);
}
static function register($file,$modname) {
$rt = self::get();
$rt[] = [ $file, $modname ];
self::set($rt);
}
public static function unregister($file, $modname)
{
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file && $r[1] !== $modname) {
$n[] = $r;
}
}
self::set($n);
}
}
static function unregister($file,$modname) {
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file && $r[1] !== $modname) {
$n[] = $r;
}
}
self::set($n);
}
}
public static function unregister_by_file($file)
{
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file) {
$n[] = $r;
}
}
self::set($n);
}
}
static function unregister_by_file($file) {
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file) {
$n[] = $r;
}
}
self::set($n);
}
}
public static function get()
{
return get_config('system', 'routes', []);
}
static function get() {
return get_config('system','routes',[]);
}
static function set($r) {
return set_config('system','routes',$r);
}
public static function set($r)
{
return set_config('system', 'routes', $r);
}
}

View file

@ -2,46 +2,51 @@
namespace Zotlabs\Extend;
class Widget
{
class Widget {
public static function register($file, $widget)
{
$rt = self::get();
$rt[] = [$file, $widget];
self::set($rt);
}
static function register($file,$widget) {
$rt = self::get();
$rt[] = [ $file, $widget ];
self::set($rt);
}
public static function unregister($file, $widget)
{
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file && $r[1] !== $widget) {
$n[] = $r;
}
}
self::set($n);
}
}
static function unregister($file,$widget) {
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file && $r[1] !== $widget) {
$n[] = $r;
}
}
self::set($n);
}
}
public static function unregister_by_file($file)
{
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file) {
$n[] = $r;
}
}
self::set($n);
}
}
static function unregister_by_file($file) {
$rt = self::get();
if ($rt) {
$n = [];
foreach ($rt as $r) {
if ($r[0] !== $file) {
$n[] = $r;
}
}
self::set($n);
}
}
public static function get()
{
return get_config('system', 'widgets', []);
}
static function get() {
return get_config('system','widgets',[]);
}
static function set($r) {
return set_config('system','widgets',$r);
}
public static function set($r)
{
return set_config('system', 'widgets', $r);
}
}

View file

@ -8,37 +8,38 @@ use OAuth2\Storage\Memory;
use OAuth2\GrantType\ClientCredentials;
use OAuth2\OpenID\GrantType\AuthorizationCode;
class OAuth2Server extends Server {
class OAuth2Server extends Server
{
public function __construct(OAuth2Storage $storage, $config = null) {
public function __construct(OAuth2Storage $storage, $config = null)
{
if (! is_array($config)) {
$config = [
// 'use_openid_connect' => true,
'issuer' => System::get_site_name(),
// 'use_jwt_access_tokens' => true,
// 'enforce_state' => false
];
}
if (! is_array($config)) {
$config = [
// 'use_openid_connect' => true,
'issuer' => System::get_site_name(),
// 'use_jwt_access_tokens' => true,
// 'enforce_state' => false
];
}
parent::__construct($storage, $config);
parent::__construct($storage, $config);
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$this->addGrantType(new ClientCredentials($storage));
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$this->addGrantType(new ClientCredentials($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
// Need to use OpenID\GrantType to return id_token
// (see:https://github.com/bshaffer/oauth2-server-php/issues/443)
$this->addGrantType(new AuthorizationCode($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
// Need to use OpenID\GrantType to return id_token
// (see:https://github.com/bshaffer/oauth2-server-php/issues/443)
$this->addGrantType(new AuthorizationCode($storage));
$keyStorage = new Memory( [
'keys' => [
'public_key' => get_config('system', 'pubkey'),
'private_key' => get_config('system', 'prvkey')
]
]);
$this->addStorage($keyStorage, 'public_key');
}
$keyStorage = new Memory([
'keys' => [
'public_key' => get_config('system', 'pubkey'),
'private_key' => get_config('system', 'prvkey')
]
]);
$this->addStorage($keyStorage, 'public_key');
}
}

View file

@ -2,8 +2,10 @@
namespace Zotlabs\Identity;
use OAuth2\Storage\Pdo;
class OAuth2Storage extends \OAuth2\Storage\Pdo {
class OAuth2Storage extends Pdo
{
/**
* @param string $username
@ -38,9 +40,8 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
protected function checkPassword($user, $password)
{
$x = account_verify_password($user,$password);
return((array_key_exists('channel',$x) && ! empty($x['channel'])) ? true : false);
$x = account_verify_password($user, $password);
return((array_key_exists('channel', $x) && ! empty($x['channel'])) ? true : false);
}
/**
@ -50,76 +51,79 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
public function getUser($username)
{
$x = channelx_by_n($username);
if (! $x) {
return false;
}
$x = channelx_by_n($username);
if (! $x) {
return false;
}
$a = q("select * from account where account_id = %d",
intval($x['channel_account_id'])
);
$a = q(
"select * from account where account_id = %d",
intval($x['channel_account_id'])
);
$n = explode(' ', $x['channel_name']);
$n = explode(' ', $x['channel_name']);
return( [
'webfinger' => channel_reddress($x),
'portable_id' => $x['channel_hash'],
'email' => $a[0]['account_email'],
'username' => $x['channel_address'],
'user_id' => $x['channel_id'],
'name' => $x['channel_name'],
'firstName' => ((count($n) > 1) ? $n[1] : $n[0]),
'lastName' => ((count($n) > 2) ? $n[count($n) - 1] : ''),
'picture' => $x['xchan_photo_l']
] );
return( [
'webfinger' => channel_reddress($x),
'portable_id' => $x['channel_hash'],
'email' => $a[0]['account_email'],
'username' => $x['channel_address'],
'user_id' => $x['channel_id'],
'name' => $x['channel_name'],
'firstName' => ((count($n) > 1) ? $n[1] : $n[0]),
'lastName' => ((count($n) > 2) ? $n[count($n) - 1] : ''),
'picture' => $x['xchan_photo_l']
] );
}
public function scopeExists($scope) {
public function scopeExists($scope)
{
// Report that the scope is valid even if it's not.
// We will only return a very small subset no matter what.
// @TODO: Truly validate the scope
// see vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php and
// vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php
// for more info.
return true;
return true;
}
public function getDefaultScope($client_id=null) {
public function getDefaultScope($client_id = null)
{
// Do not REQUIRE a scope
// see vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/ScopeInterface.php and
// for more info.
return null;
return null;
}
public function getUserClaims ($user_id, $claims) {
// Populate the CLAIMS requested (if any).
// @TODO: create a more reasonable/comprehensive list.
// @TODO: present claims on the AUTHORIZATION screen
public function getUserClaims($user_id, $claims)
{
// Populate the CLAIMS requested (if any).
// @TODO: create a more reasonable/comprehensive list.
// @TODO: present claims on the AUTHORIZATION screen
$userClaims = [];
$claims = explode (' ', trim($claims));
$claims = explode(' ', trim($claims));
$validclaims = [ "name", "preferred_username", "webfinger", "portable_id", "email", "picture", "firstName", "lastName" ];
$claimsmap = [
"webfinger" => 'webfinger',
"portable_id" => 'portable_id',
"name" => 'name',
"email" => 'email',
"preferred_username" => 'username',
"picture" => 'picture',
"given_name" => 'firstName',
"family_name" => 'lastName'
];
"webfinger" => 'webfinger',
"portable_id" => 'portable_id',
"name" => 'name',
"email" => 'email',
"preferred_username" => 'username',
"picture" => 'picture',
"given_name" => 'firstName',
"family_name" => 'lastName'
];
$userinfo = $this->getUser($user_id);
foreach ($validclaims as $validclaim) {
if (in_array($validclaim,$claims)) {
$claimkey = $claimsmap[$validclaim];
$userClaims[$validclaim] = $userinfo[$claimkey];
}
else {
$userClaims[$validclaim] = $validclaim;
if (in_array($validclaim, $claims)) {
$claimkey = $claimsmap[$validclaim];
$userClaims[$validclaim] = $userinfo[$claimkey];
} else {
$userClaims[$validclaim] = $validclaim;
}
}
$userClaims["sub"]=$user_id;
$userClaims["sub"] = $user_id;
return $userClaims;
}
@ -163,5 +167,4 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
// if grant_types are not defined, then none are restricted
return true;
}
}

View file

@ -1,4 +1,5 @@
<?php
namespace Zotlabs\Import;
use App;
@ -11,353 +12,354 @@ use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Run;
class Friendica
{
class Friendica {
private $data;
private $settings;
private $data;
private $settings;
private $default_group = null;
private $default_group = null;
private $groups = null;
private $members = null;
private $contacts = null;
function __construct($data, $settings) {
$this->data = $data;
$this->settings = $settings;
$this->extract();
}
function extract() {
// channel stuff
$channel = [
'channel_name' => escape_tags($this->data['user']['username']),
'channel_address' => escape_tags($this->data['user']['nickname']),
'channel_guid' => escape_tags($this->data['user']['guid']),
'channel_guid_sig' => Libzot::sign($this->data['user']['guid'],$this->data['user']['prvkey']),
'channel_hash' => Libzot::make_xchan_hash($this->data['user']['guid'],$this->data['user']['pubkey']),
'channel_prvkey' => $this->data['user']['prvkey'],
'channel_pubkey' => $this->data['user']['pubkey'],
'channel_pageflags' => PAGE_NORMAL,
'channel_expire_days' => intval($this->data['user']['expire']),
'channel_timezone' => escape_tags($this->data['user']['timezone']),
'channel_location' => escape_tags($this->data['user']['default-location'])
];
$account_id = $this->settings['account_id'];
$max_identities = account_service_class_fetch($account_id,'total_identities');
if ($max_identities !== false) {
$r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ",
intval($account_id)
);
if ($r && count($r) > $max_identities) {
notice( sprintf( t('Your service plan only allows %d channels.'), $max_identities) . EOL);
return;
}
}
// save channel or die
$channel = import_channel($channel,$this->settings['account_id'],$this->settings['sieze'],$this->settings['newname']);
if (! $channel) {
logger('no channel');
return;
}
// figure out channel permission roles
$permissions_role = 'social';
$pageflags = ((isset($this->data['user']['page-flags'])) ? intval($this->data['user']['page-flags']) : 0);
if ($pageflags === 2) {
$permissions_role = 'forum';
}
if ($pageflags === 5) {
$permissions_role = 'forum_restricted';
}
if ($pageflags === 0 && isset($this->data['user']['allow_gid']) && $this->data['user']['allow_gid']) {
$permissions_role = 'social_restricted';
}
// Friendica folks only have PERMS_AUTHED and "just me"
$post_comments = (($pageflags === 1) ? 0 : PERMS_AUTHED);
PermissionLimits::Set(local_channel(),'post_comments',$post_comments);
PConfig::Set($channel['channel_id'],'system','permissions_role',$permissions_role);
PConfig::Set($channel['channel_id'],'system','use_browser_location', (string) intval($this->data['user']['allow_location']));
// find the self contact
$self_contact = null;
if (isset($this->data['contact']) && is_array($this->data['contact'])) {
foreach ($this->data['contact'] as $contact) {
if (isset($contact['self']) && intval($contact['self'])) {
$self_contact = $contact;
break;
}
}
}
if (! is_array($self_contact)) {
logger('self contact not found.');
return;
}
// Create a verified hub location pointing to this site.
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $channel['channel_guid'],
'hubloc_guid_sig' => $channel['channel_guid_sig'],
'hubloc_id_url' => channel_url($channel),
'hubloc_hash' => $channel['channel_hash'],
'hubloc_addr' => channel_reddress($channel),
'hubloc_primary' => 1,
'hubloc_url' => z_root(),
'hubloc_url_sig' => Libzot::sign(z_root(),$channel['channel_prvkey']),
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')),
'hubloc_host' => App::get_hostname(),
'hubloc_callback' => z_root() . '/zot',
'hubloc_sitekey' => get_config('system','pubkey'),
'hubloc_network' => 'nomad',
'hubloc_updated' => datetime_convert()
]
);
if (! $r) {
logger('Unable to store hub location');
}
if ($self_contact['avatar']) {
$p = z_fetch_url($self_contact['avatar'],true);
if ($p['success']) {
$h = explode("\n",$p['header']);
foreach ($h as $l) {
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[strtolower($k)] = $v;
}
if (array_key_exists('content-type', $hdrs)) {
$phototype = $hdrs['content-type'];
}
else {
$phototype = 'image/jpeg';
}
import_channel_photo($p['body'],$phototype,$account_id,$channel['channel_id']);
}
}
$newuid = $channel['channel_id'];
$r = xchan_store_lowlevel(
[
'xchan_hash' => $channel['channel_hash'],
'xchan_guid' => $channel['channel_guid'],
'xchan_guid_sig' => $channel['channel_guid_sig'],
'xchan_pubkey' => $channel['channel_pubkey'],
'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}",
'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}",
'xchan_addr' => channel_reddress($channel),
'xchan_url' => channel_url($channel),
'xchan_follow' => z_root() . '/follow?f=&url=%s',
'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
'xchan_name' => $channel['channel_name'],
'xchan_network' => 'nomad',
'xchan_updated' => datetime_convert(),
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert(),
'xchan_system' => 0
]
);
$r = profile_store_lowlevel(
[
'aid' => intval($channel['channel_account_id']),
'uid' => intval($newuid),
'profile_guid' => new_uuid(),
'profile_name' => t('Default Profile'),
'is_default' => 1,
'publish' => ((isset($this->data['profile']['publish'])) ? $this->data['profile']['publish'] : 1),
'fullname' => $channel['channel_name'],
'photo' => z_root() . "/photo/profile/l/{$newuid}",
'thumb' => z_root() . "/photo/profile/m/{$newuid}",
'homepage' => ((isset($this->data['profile']['homepage'])) ? $this->data['profile']['homepage'] : EMPTY_STR),
]
);
if($role_permissions) {
$myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : [] );
}
else {
$x = PermissionRoles::role_perms('social');
$myperms = $x['perms_connect'];
}
$r = abook_store_lowlevel(
[
'abook_account' => intval($channel['channel_account_id']),
'abook_channel' => intval($newuid),
'abook_xchan' => $channel['channel_hash'],
'abook_closeness' => 0,
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_self' => 1
]
);
$x = Permissions::serialise(Permissions::FilledPerms($myperms));
set_abconfig($newuid,$channel['channel_hash'],'system','my_perms',$x);
if(intval($channel['channel_account_id'])) {
// Save our permissions role so we can perhaps call it up and modify it later.
if($role_permissions) {
if(array_key_exists('online',$role_permissions))
set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online']));
if(array_key_exists('perms_auto',$role_permissions)) {
$autoperms = intval($role_permissions['perms_auto']);
set_pconfig($newuid,'system','autoperms',$autoperms);
}
}
// Create a group with yourself as a member. This allows somebody to use it
// right away as a default group for new contacts.
AccessList::add($newuid, t('Friends'));
AccessList::member_add($newuid,t('Friends'),$ret['channel']['channel_hash']);
// if our role_permissions indicate that we're using a default collection ACL, add it.
if(is_array($role_permissions) && $role_permissions['default_collection']) {
$r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1",
intval($newuid),
dbesc( t('Friends') )
);
if($r) {
q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d",
dbesc($r[0]['hash']),
dbesc('<' . $r[0]['hash'] . '>'),
intval($newuid)
);
}
}
set_pconfig($channel['channel_id'],'system','photo_path', '%Y/%Y-%m');
set_pconfig($channel['channel_id'],'system','attach_path','%Y/%Y-%m');
// auto-follow any of the hub's pre-configured channel choices.
// Only do this if it's the first channel for this account;
// otherwise it could get annoying. Don't make this list too big
// or it will impact registration time.
$accts = get_config('system','auto_follow');
if(($accts) && (! $total_identities)) {
if(! is_array($accts))
$accts = array($accts);
foreach($accts as $acct) {
if(trim($acct)) {
$f = connect_and_sync($channel,trim($acct));
if($f['success']) {
$can_view_stream = their_perms_contains($channel['channel_id'],$f['abook']['abook_xchan'],'view_stream');
// If we can view their stream, pull in some posts
if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) {
Run::Summon([ 'Onepoll',$f['abook']['abook_id'] ]);
}
}
}
}
}
call_hooks('create_identity', $newuid);
}
$this->groups = ((isset($this->data['group'])) ? $this->data['group'] : null);
$this->members = ((isset($this->data['group_member'])) ? $this->data['group_member'] : null);
// import contacts
if (isset($this->data['contact']) && is_array($this->data['contact'])) {
foreach ($this->data['contact'] as $contact) {
if (isset($contact['self']) && intval($contact['self'])) {
continue;
}
logger('connecting: ' . $contact['url'], LOGGER_DEBUG);
$result = Connect::connect($channel,(($contact['addr']) ? $contact['addr'] : $contact['url']));
if ($result['success'] && isset($result['abook'])) {
$contact['xchan_hash'] = $result['abook']['abook_xchan'];
$this->contacts[] = $contact;
}
}
}
// import pconfig
// it is unlikely we can make use of these unless we recongise them.
if (isset($this->data['pconfig']) && is_array($this->data['pconfig'])) {
foreach ($this->data['pconfig'] as $pc) {
$entry = [
'cat' => escape_tags(str_replace('.','__',$pc['cat'])),
'k' => escape_tags(str_replace('.','__',$pc['k'])),
'v' => ((preg_match('|^a:[0-9]+:{.*}$|s', $pc['v'])) ? serialise(unserialize($pc['v'])) : $pc['v']),
];
PConfig::Set($channel['channel_id'],$entry['cat'],$entry['k'],$entry['v']);
}
}
// The default 'Friends' group is already created and possibly populated.
// So some of the following code is redundant in that regard.
// Mostly this is used to create and populate any other groups.
if ($this->groups) {
foreach ($this->groups as $group) {
if (! intval($group['deleted'])) {
AccessList::add($channel['channel_id'], $group['name'], intval($group['visible']));
if ($this->members) {
foreach ($this->members as $member) {
if (intval($member['gid']) === intval(AccessList::byname($channel['channel_id'],$group['name']))) {
$contact_id = $member['contact-id'];
if ($this->contacts) {
foreach ($this->contacts as $contact) {
if (intval($contact['id']) === intval($contact_id)) {
AccessList::member_add($channel['channel_id'],$group['name'],$contact['xchan_hash']);
break;
}
}
}
}
}
}
}
}
}
change_channel($channel['channel_id']);
notice( t('Import complete.') . EOL);
goaway(z_root() . '/stream' );
}
private $groups = null;
private $members = null;
private $contacts = null;
public function __construct($data, $settings)
{
$this->data = $data;
$this->settings = $settings;
$this->extract();
}
public function extract()
{
// channel stuff
$channel = [
'channel_name' => escape_tags($this->data['user']['username']),
'channel_address' => escape_tags($this->data['user']['nickname']),
'channel_guid' => escape_tags($this->data['user']['guid']),
'channel_guid_sig' => Libzot::sign($this->data['user']['guid'], $this->data['user']['prvkey']),
'channel_hash' => Libzot::make_xchan_hash($this->data['user']['guid'], $this->data['user']['pubkey']),
'channel_prvkey' => $this->data['user']['prvkey'],
'channel_pubkey' => $this->data['user']['pubkey'],
'channel_pageflags' => PAGE_NORMAL,
'channel_expire_days' => intval($this->data['user']['expire']),
'channel_timezone' => escape_tags($this->data['user']['timezone']),
'channel_location' => escape_tags($this->data['user']['default-location'])
];
$account_id = $this->settings['account_id'];
$max_identities = account_service_class_fetch($account_id, 'total_identities');
if ($max_identities !== false) {
$r = q(
"select channel_id from channel where channel_account_id = %d and channel_removed = 0 ",
intval($account_id)
);
if ($r && count($r) > $max_identities) {
notice(sprintf(t('Your service plan only allows %d channels.'), $max_identities) . EOL);
return;
}
}
// save channel or die
$channel = import_channel($channel, $this->settings['account_id'], $this->settings['sieze'], $this->settings['newname']);
if (!$channel) {
logger('no channel');
return;
}
// figure out channel permission roles
$permissions_role = 'social';
$pageflags = ((isset($this->data['user']['page-flags'])) ? intval($this->data['user']['page-flags']) : 0);
if ($pageflags === 2) {
$permissions_role = 'forum';
}
if ($pageflags === 5) {
$permissions_role = 'forum_restricted';
}
if ($pageflags === 0 && isset($this->data['user']['allow_gid']) && $this->data['user']['allow_gid']) {
$permissions_role = 'social_restricted';
}
// Friendica folks only have PERMS_AUTHED and "just me"
$post_comments = (($pageflags === 1) ? 0 : PERMS_AUTHED);
PermissionLimits::Set(local_channel(), 'post_comments', $post_comments);
PConfig::Set($channel['channel_id'], 'system', 'permissions_role', $permissions_role);
PConfig::Set($channel['channel_id'], 'system', 'use_browser_location', (string)intval($this->data['user']['allow_location']));
// find the self contact
$self_contact = null;
if (isset($this->data['contact']) && is_array($this->data['contact'])) {
foreach ($this->data['contact'] as $contact) {
if (isset($contact['self']) && intval($contact['self'])) {
$self_contact = $contact;
break;
}
}
}
if (!is_array($self_contact)) {
logger('self contact not found.');
return;
}
// Create a verified hub location pointing to this site.
$r = hubloc_store_lowlevel(
[
'hubloc_guid' => $channel['channel_guid'],
'hubloc_guid_sig' => $channel['channel_guid_sig'],
'hubloc_id_url' => channel_url($channel),
'hubloc_hash' => $channel['channel_hash'],
'hubloc_addr' => channel_reddress($channel),
'hubloc_primary' => 1,
'hubloc_url' => z_root(),
'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']),
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), get_config('system', 'pubkey')),
'hubloc_host' => App::get_hostname(),
'hubloc_callback' => z_root() . '/zot',
'hubloc_sitekey' => get_config('system', 'pubkey'),
'hubloc_network' => 'nomad',
'hubloc_updated' => datetime_convert()
]
);
if (!$r) {
logger('Unable to store hub location');
}
if ($self_contact['avatar']) {
$p = z_fetch_url($self_contact['avatar'], true);
if ($p['success']) {
$h = explode("\n", $p['header']);
foreach ($h as $l) {
list($k, $v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[strtolower($k)] = $v;
}
if (array_key_exists('content-type', $hdrs)) {
$phototype = $hdrs['content-type'];
} else {
$phototype = 'image/jpeg';
}
import_channel_photo($p['body'], $phototype, $account_id, $channel['channel_id']);
}
}
$newuid = $channel['channel_id'];
$r = xchan_store_lowlevel(
[
'xchan_hash' => $channel['channel_hash'],
'xchan_guid' => $channel['channel_guid'],
'xchan_guid_sig' => $channel['channel_guid_sig'],
'xchan_pubkey' => $channel['channel_pubkey'],
'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}",
'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}",
'xchan_addr' => channel_reddress($channel),
'xchan_url' => channel_url($channel),
'xchan_follow' => z_root() . '/follow?f=&url=%s',
'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'],
'xchan_name' => $channel['channel_name'],
'xchan_network' => 'nomad',
'xchan_updated' => datetime_convert(),
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert(),
'xchan_system' => 0
]
);
$r = profile_store_lowlevel(
[
'aid' => intval($channel['channel_account_id']),
'uid' => intval($newuid),
'profile_guid' => new_uuid(),
'profile_name' => t('Default Profile'),
'is_default' => 1,
'publish' => ((isset($this->data['profile']['publish'])) ? $this->data['profile']['publish'] : 1),
'fullname' => $channel['channel_name'],
'photo' => z_root() . "/photo/profile/l/{$newuid}",
'thumb' => z_root() . "/photo/profile/m/{$newuid}",
'homepage' => ((isset($this->data['profile']['homepage'])) ? $this->data['profile']['homepage'] : EMPTY_STR),
]
);
if ($role_permissions) {
$myperms = ((array_key_exists('perms_connect', $role_permissions)) ? $role_permissions['perms_connect'] : []);
} else {
$x = PermissionRoles::role_perms('social');
$myperms = $x['perms_connect'];
}
$r = abook_store_lowlevel(
[
'abook_account' => intval($channel['channel_account_id']),
'abook_channel' => intval($newuid),
'abook_xchan' => $channel['channel_hash'],
'abook_closeness' => 0,
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_self' => 1
]
);
$x = Permissions::serialise(Permissions::FilledPerms($myperms));
set_abconfig($newuid, $channel['channel_hash'], 'system', 'my_perms', $x);
if (intval($channel['channel_account_id'])) {
// Save our permissions role so we can perhaps call it up and modify it later.
if ($role_permissions) {
if (array_key_exists('online', $role_permissions)) {
set_pconfig($newuid, 'system', 'hide_presence', 1 - intval($role_permissions['online']));
}
if (array_key_exists('perms_auto', $role_permissions)) {
$autoperms = intval($role_permissions['perms_auto']);
set_pconfig($newuid, 'system', 'autoperms', $autoperms);
}
}
// Create a group with yourself as a member. This allows somebody to use it
// right away as a default group for new contacts.
AccessList::add($newuid, t('Friends'));
AccessList::member_add($newuid, t('Friends'), $ret['channel']['channel_hash']);
// if our role_permissions indicate that we're using a default collection ACL, add it.
if (is_array($role_permissions) && $role_permissions['default_collection']) {
$r = q(
"select hash from pgrp where uid = %d and gname = '%s' limit 1",
intval($newuid),
dbesc(t('Friends'))
);
if ($r) {
q(
"update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d",
dbesc($r[0]['hash']),
dbesc('<' . $r[0]['hash'] . '>'),
intval($newuid)
);
}
}
set_pconfig($channel['channel_id'], 'system', 'photo_path', '%Y/%Y-%m');
set_pconfig($channel['channel_id'], 'system', 'attach_path', '%Y/%Y-%m');
// auto-follow any of the hub's pre-configured channel choices.
// Only do this if it's the first channel for this account;
// otherwise it could get annoying. Don't make this list too big
// or it will impact registration time.
$accts = get_config('system', 'auto_follow');
if (($accts) && (!$total_identities)) {
if (!is_array($accts)) {
$accts = array($accts);
}
foreach ($accts as $acct) {
if (trim($acct)) {
$f = connect_and_sync($channel, trim($acct));
if ($f['success']) {
$can_view_stream = their_perms_contains($channel['channel_id'], $f['abook']['abook_xchan'], 'view_stream');
// If we can view their stream, pull in some posts
if (($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) {
Run::Summon(['Onepoll', $f['abook']['abook_id']]);
}
}
}
}
}
call_hooks('create_identity', $newuid);
}
$this->groups = ((isset($this->data['group'])) ? $this->data['group'] : null);
$this->members = ((isset($this->data['group_member'])) ? $this->data['group_member'] : null);
// import contacts
if (isset($this->data['contact']) && is_array($this->data['contact'])) {
foreach ($this->data['contact'] as $contact) {
if (isset($contact['self']) && intval($contact['self'])) {
continue;
}
logger('connecting: ' . $contact['url'], LOGGER_DEBUG);
$result = Connect::connect($channel, (($contact['addr']) ? $contact['addr'] : $contact['url']));
if ($result['success'] && isset($result['abook'])) {
$contact['xchan_hash'] = $result['abook']['abook_xchan'];
$this->contacts[] = $contact;
}
}
}
// import pconfig
// it is unlikely we can make use of these unless we recongise them.
if (isset($this->data['pconfig']) && is_array($this->data['pconfig'])) {
foreach ($this->data['pconfig'] as $pc) {
$entry = [
'cat' => escape_tags(str_replace('.', '__', $pc['cat'])),
'k' => escape_tags(str_replace('.', '__', $pc['k'])),
'v' => ((preg_match('|^a:[0-9]+:{.*}$|s', $pc['v'])) ? serialise(unserialize($pc['v'])) : $pc['v']),
];
PConfig::Set($channel['channel_id'], $entry['cat'], $entry['k'], $entry['v']);
}
}
// The default 'Friends' group is already created and possibly populated.
// So some of the following code is redundant in that regard.
// Mostly this is used to create and populate any other groups.
if ($this->groups) {
foreach ($this->groups as $group) {
if (!intval($group['deleted'])) {
AccessList::add($channel['channel_id'], $group['name'], intval($group['visible']));
if ($this->members) {
foreach ($this->members as $member) {
if (intval($member['gid']) === intval(AccessList::byname($channel['channel_id'], $group['name']))) {
$contact_id = $member['contact-id'];
if ($this->contacts) {
foreach ($this->contacts as $contact) {
if (intval($contact['id']) === intval($contact_id)) {
AccessList::member_add($channel['channel_id'], $group['name'], $contact['xchan_hash']);
break;
}
}
}
}
}
}
}
}
}
change_channel($channel['channel_id']);
notice(t('Import complete.') . EOL);
goaway(z_root() . '/stream');
}
}

View file

@ -4,22 +4,26 @@ namespace Zotlabs\Lib;
// account configuration storage is built on top of the under-utilised xconfig
class AConfig {
class AConfig
{
static public function Load($account_id) {
return XConfig::Load('a_' . $account_id);
}
public static function Load($account_id)
{
return XConfig::Load('a_' . $account_id);
}
static public function Get($account_id,$family,$key,$default = false) {
return XConfig::Get('a_' . $account_id,$family,$key, $default);
}
public static function Get($account_id, $family, $key, $default = false)
{
return XConfig::Get('a_' . $account_id, $family, $key, $default);
}
static public function Set($account_id,$family,$key,$value) {
return XConfig::Set('a_' . $account_id,$family,$key,$value);
}
static public function Delete($account_id,$family,$key) {
return XConfig::Delete('a_' . $account_id,$family,$key);
}
public static function Set($account_id, $family, $key, $value)
{
return XConfig::Set('a_' . $account_id, $family, $key, $value);
}
public static function Delete($account_id, $family, $key)
{
return XConfig::Delete('a_' . $account_id, $family, $key);
}
}

View file

@ -12,147 +12,140 @@ use Zotlabs\Lib\Activity;
* An optional limit to the number of records returned may also be specified.
* Use $class->get() to return an array of collection members.
*/
class ASCollection
{
private $channel = null;
private $nextpage = null;
private $limit = 0;
private $direction = 0; // 0 = forward, 1 = reverse
private $data = [];
private $history = [];
public function __construct($obj, $channel = null, $direction = 0, $limit = 0)
{
$this->channel = $channel;
$this->direction = $direction;
$this->limit = $limit;
class ASCollection {
if (is_array($obj)) {
$data = $obj;
}
private $channel = null;
private $nextpage = null;
private $limit = 0;
private $direction = 0; // 0 = forward, 1 = reverse
private $data = [];
private $history = [];
if (is_string($obj)) {
$data = Activity::fetch($obj, $channel);
$this->history[] = $obj;
}
if (!is_array($data)) {
return;
}
function __construct($obj, $channel = null, $direction = 0, $limit = 0) {
if (!in_array($data['type'], ['Collection', 'OrderedCollection'])) {
return false;
}
$this->channel = $channel;
$this->direction = $direction;
$this->limit = $limit;
if ($this->direction) {
if (array_key_exists('last', $data) && $data['last']) {
$this->nextpage = $data['last'];
}
} else {
if (array_key_exists('first', $data) && $data['first']) {
$this->nextpage = $data['first'];
}
}
if (is_array($obj)) {
$data = $obj;
}
if (isset($data['items']) && is_array($data['items'])) {
$this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']);
} elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
$this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']);
}
if (is_string($obj)) {
$data = Activity::fetch($obj,$channel);
$this->history[] = $obj;
}
if ($limit) {
if (count($this->data) > $limit) {
$this->data = array_slice($this->data, 0, $limit);
return;
}
}
if (! is_array($data)) {
return;
}
do {
$x = $this->next();
} while ($x);
}
if (! in_array($data['type'], ['Collection','OrderedCollection'])) {
return false;
}
public function get()
{
return $this->data;
}
if ($this->direction) {
if (array_key_exists('last',$data) && $data['last']) {
$this->nextpage = $data['last'];
}
}
else {
if (array_key_exists('first',$data) && $data['first']) {
$this->nextpage = $data['first'];
}
}
public function next()
{
if (isset($data['items']) && is_array($data['items'])) {
$this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']);
}
elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
$this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']);
}
if (!$this->nextpage) {
return false;
}
if ($limit) {
if (count($this->data) > $limit) {
$this->data = array_slice($this->data,0,$limit);
return;
}
}
if (is_array($this->nextpage)) {
$data = $this->nextpage;
}
do {
$x = $this->next();
} while ($x);
}
if (is_string($this->nextpage)) {
if (in_array($this->nextpage, $this->history)) {
// recursion detected
return false;
}
$data = Activity::fetch($this->nextpage, $this->channel);
$this->history[] = $this->nextpage;
}
function get() {
return $this->data;
}
if (!is_array($data)) {
return false;
}
function next() {
if (!in_array($data['type'], ['CollectionPage', 'OrderedCollectionPage'])) {
return false;
}
if (! $this->nextpage) {
return false;
}
$this->setnext($data);
if (is_array($this->nextpage)) {
$data = $this->nextpage;
}
if (isset($data['items']) && is_array($data['items'])) {
$this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['items']) : $data['items']));
} elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
$this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']));
}
if (is_string($this->nextpage)) {
if (in_array($this->nextpage,$this->history)) {
// recursion detected
return false;
}
$data = Activity::fetch($this->nextpage,$this->channel);
$this->history[] = $this->nextpage;
}
if ($limit) {
if (count($this->data) > $limit) {
$this->data = array_slice($this->data, 0, $limit);
$this->nextpage = false;
return true;
}
}
if (! is_array($data)) {
return false;
}
return true;
}
if (! in_array($data['type'], ['CollectionPage','OrderedCollectionPage'])) {
return false;
}
$this->setnext($data);
if (isset($data['items']) && is_array($data['items'])) {
$this->data = array_merge($this->data,(($this->direction) ? array_reverse($data['items']) : $data['items']));
}
elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) {
$this->data = array_merge($this->data,(($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']));
}
if ($limit) {
if (count($this->data) > $limit) {
$this->data = array_slice($this->data,0,$limit);
$this->nextpage = false;
return true;
}
}
return true;
}
function setnext($data) {
if ($this->direction) {
if (array_key_exists('prev',$data) && $data['prev']) {
$this->nextpage = $data['prev'];
}
elseif (array_key_exists('first',$data) && $data['first']) {
$this->nextpage = $data['first'];
}
else {
$this->nextpage = false;
}
}
else {
if (array_key_exists('next',$data) && $data['next']) {
$this->nextpage = $data['next'];
}
elseif (array_key_exists('last',$data) && $data['last']) {
$this->nextpage = $data['last'];
}
else {
$this->nextpage = false;
}
}
logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG);
}
public function setnext($data)
{
if ($this->direction) {
if (array_key_exists('prev', $data) && $data['prev']) {
$this->nextpage = $data['prev'];
} elseif (array_key_exists('first', $data) && $data['first']) {
$this->nextpage = $data['first'];
} else {
$this->nextpage = false;
}
} else {
if (array_key_exists('next', $data) && $data['next']) {
$this->nextpage = $data['next'];
} elseif (array_key_exists('last', $data) && $data['last']) {
$this->nextpage = $data['last'];
} else {
$this->nextpage = false;
}
}
logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG);
}
}

View file

@ -2,74 +2,83 @@
namespace Zotlabs\Lib;
class AbConfig
{
class AbConfig {
static public function Load($chan,$xhash,$family = '') {
if($family)
$where = sprintf(" and cat = '%s' ",dbesc($family));
$r = q("select * from abconfig where chan = %d and xchan = '%s' $where",
intval($chan),
dbesc($xhash)
);
return $r;
}
public static function Load($chan, $xhash, $family = '')
{
if ($family) {
$where = sprintf(" and cat = '%s' ", dbesc($family));
}
$r = q(
"select * from abconfig where chan = %d and xchan = '%s' $where",
intval($chan),
dbesc($xhash)
);
return $r;
}
static public function Get($chan,$xhash,$family,$key, $default = false) {
$r = q("select * from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' limit 1",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
if($r) {
return unserialise($r[0]['v']);
}
return $default;
}
public static function Get($chan, $xhash, $family, $key, $default = false)
{
$r = q(
"select * from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' limit 1",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
if ($r) {
return unserialise($r[0]['v']);
}
return $default;
}
static public function Set($chan,$xhash,$family,$key,$value) {
public static function Set($chan, $xhash, $family, $key, $value)
{
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($chan,$xhash,$family,$key) === false) {
$r = q("insert into abconfig ( chan, xchan, cat, k, v ) values ( %d, '%s', '%s', '%s', '%s' ) ",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
}
else {
$r = q("update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
dbesc($dbvalue),
dbesc($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
}
if (self::Get($chan, $xhash, $family, $key) === false) {
$r = q(
"insert into abconfig ( chan, xchan, cat, k, v ) values ( %d, '%s', '%s', '%s', '%s' ) ",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
} else {
$r = q(
"update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
dbesc($dbvalue),
dbesc($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
}
if($r)
return $value;
return false;
}
if ($r) {
return $value;
}
return false;
}
static public function Delete($chan,$xhash,$family,$key) {
public static function Delete($chan, $xhash, $family, $key)
{
$r = q("delete from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
return $r;
}
$r = q(
"delete from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
return $r;
}
}

View file

@ -4,461 +4,489 @@ namespace Zotlabs\Lib;
use Zotlabs\Lib\Libsync;
class AccessList
{
class AccessList {
public static function add($uid, $name, $public = 0)
{
static function add($uid,$name,$public = 0) {
$ret = false;
if ($uid && $name) {
$r = self::byname($uid, $name); // check for dups
if ($r !== false) {
// This could be a problem.
// Let's assume we've just created a list which we once deleted
// all the old members are gone, but the list remains so we don't break any security
// access lists. What we're doing here is reviving the dead list, but old content which
// was restricted to this list may now be seen by the new list members.
$ret = false;
if ($uid && $name) {
$r = self::byname($uid,$name); // check for dups
if ($r !== false) {
$z = q(
"SELECT * FROM pgrp WHERE id = %d LIMIT 1",
intval($r)
);
if (($z) && $z[0]['deleted']) {
q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
notice(t('A deleted list with this name was revived. Existing item permissions <strong>may</strong> apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL);
}
$hash = self::by_id($uid, $r);
return $hash;
}
// This could be a problem.
// Let's assume we've just created a list which we once deleted
// all the old members are gone, but the list remains so we don't break any security
// access lists. What we're doing here is reviving the dead list, but old content which
// was restricted to this list may now be seen by the new list members.
$hash = new_uuid();
$z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1",
intval($r)
);
if(($z) && $z[0]['deleted']) {
q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
notice( t('A deleted list with this name was revived. Existing item permissions <strong>may</strong> apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL);
}
$hash = self::by_id($uid,$r);
return $hash;
}
$hash = new_uuid();
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname, rule )
$r = q(
"INSERT INTO pgrp ( hash, uid, visible, gname, rule )
VALUES( '%s', %d, %d, '%s', '' ) ",
dbesc($hash),
intval($uid),
intval($public),
dbesc($name)
);
$ret = $r;
}
dbesc($hash),
intval($uid),
intval($public),
dbesc($name)
);
$ret = $r;
}
Libsync::build_sync_packet($uid,null,true);
Libsync::build_sync_packet($uid, null, true);
return (($ret) ? $hash : $ret);
}
return (($ret) ? $hash : $ret);
}
static function remove($uid,$name) {
$ret = false;
if ($uid && $name) {
$r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if ($r) {
$group_id = $r[0]['id'];
$group_hash = $r[0]['hash'];
}
else {
return false;
}
public static function remove($uid, $name)
{
$ret = false;
if ($uid && $name) {
$r = q(
"SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if ($r) {
$group_id = $r[0]['id'];
$group_hash = $r[0]['hash'];
} else {
return false;
}
// remove group from default posting lists
$r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
if ($r) {
$user_info = array_shift($r);
$change = false;
// remove group from default posting lists
$r = q(
"SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
if ($r) {
$user_info = array_shift($r);
$change = false;
if ($user_info['channel_default_group'] == $group_hash) {
$user_info['channel_default_group'] = '';
$change = true;
}
if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
$change = true;
}
if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
$change = true;
}
if ($user_info['channel_default_group'] == $group_hash) {
$user_info['channel_default_group'] = '';
$change = true;
}
if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
$change = true;
}
if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
$change = true;
}
if ($change) {
q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
if ($change) {
q(
"UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
WHERE channel_id = %d",
intval($user_info['channel_default_group']),
dbesc($user_info['channel_allow_gid']),
dbesc($user_info['channel_deny_gid']),
intval($uid)
);
}
}
intval($user_info['channel_default_group']),
dbesc($user_info['channel_allow_gid']),
dbesc($user_info['channel_deny_gid']),
intval($uid)
);
}
}
// remove all members
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ",
intval($uid),
intval($group_id)
);
// remove all members
$r = q(
"DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ",
intval($uid),
intval($group_id)
);
// remove group
$r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'",
intval($uid),
dbesc($name)
);
// remove group
$r = q(
"UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'",
intval($uid),
dbesc($name)
);
$ret = $r;
$ret = $r;
}
}
Libsync::build_sync_packet($uid, null, true);
Libsync::build_sync_packet($uid,null,true);
return $ret;
}
return $ret;
}
// returns the integer id of an access group owned by $uid and named $name
// or false.
// returns the integer id of an access group owned by $uid and named $name
// or false.
public static function byname($uid, $name)
{
if (!($uid && $name)) {
return false;
}
$r = q(
"SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if ($r) {
return $r[0]['id'];
}
return false;
}
static function byname($uid,$name) {
if (! ($uid && $name)) {
return false;
}
$r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if ($r) {
return $r[0]['id'];
}
return false;
}
public static function by_id($uid, $id)
{
if (!($uid && $id)) {
return false;
}
static function by_id($uid,$id) {
if (! ($uid && $id)) {
return false;
}
$r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0",
intval($uid),
intval($id)
);
if ($r) {
return array_shift($r);
}
return false;
}
$r = q(
"SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0",
intval($uid),
intval($id)
);
if ($r) {
return array_shift($r);
}
return false;
}
static function rec_byhash($uid,$hash) {
if (! ( $uid && $hash)) {
return false;
}
$r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($uid),
dbesc($hash)
);
if ($r) {
return array_shift($r);
}
return false;
}
public static function rec_byhash($uid, $hash)
{
if (!($uid && $hash)) {
return false;
}
$r = q(
"SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($uid),
dbesc($hash)
);
if ($r) {
return array_shift($r);
}
return false;
}
static function member_remove($uid,$name,$member) {
$gid = self::byname($uid,$name);
if (! $gid) {
return false;
}
if (! ($uid && $gid && $member)) {
return false;
}
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
intval($uid),
intval($gid),
dbesc($member)
);
public static function member_remove($uid, $name, $member)
{
$gid = self::byname($uid, $name);
if (!$gid) {
return false;
}
if (!($uid && $gid && $member)) {
return false;
}
$r = q(
"DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
intval($uid),
intval($gid),
dbesc($member)
);
Libsync::build_sync_packet($uid,null,true);
Libsync::build_sync_packet($uid, null, true);
return $r;
}
return $r;
}
static function member_add($uid,$name,$member,$gid = 0) {
if (! $gid) {
$gid = self::byname($uid,$name);
}
if (! ($gid && $uid && $member)) {
return false;
}
public static function member_add($uid, $name, $member, $gid = 0)
{
if (!$gid) {
$gid = self::byname($uid, $name);
}
if (!($gid && $uid && $member)) {
return false;
}
$r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
intval($uid),
intval($gid),
dbesc($member)
);
if ($r) {
return true; // You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
}
else {
$r = q("INSERT INTO pgrp_member (uid, gid, xchan)
$r = q(
"SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
intval($uid),
intval($gid),
dbesc($member)
);
if ($r) {
return true; // You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
} else {
$r = q(
"INSERT INTO pgrp_member (uid, gid, xchan)
VALUES( %d, %d, '%s' ) ",
intval($uid),
intval($gid),
dbesc($member)
);
}
Libsync::build_sync_packet($uid,null,true);
return $r;
}
intval($uid),
intval($gid),
dbesc($member)
);
}
Libsync::build_sync_packet($uid, null, true);
return $r;
}
static function members($uid, $gid, $total = false, $start = 0, $records = 0) {
$ret = [];
if ($records) {
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start));
}
public static function members($uid, $gid, $total = false, $start = 0, $records = 0)
{
$ret = [];
if ($records) {
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start));
}
// process virtual groups
if (strpos($gid,':') === 0) {
$vg = substr($gid,1);
switch ($vg) {
case '1':
$sql_extra = EMPTY_STR;
break;
case '2':
// process virtual groups
if (strpos($gid, ':') === 0) {
$vg = substr($gid, 1);
switch ($vg) {
case '1':
$sql_extra = EMPTY_STR;
break;
case '2':
$sql_extra = " and xchan_network in ('nomad','zot6') ";
break;
case '3':
$sql_extra = " and xchan_network = 'activitypub' ";
break;
default:
break;
}
if ($total) {
$r = q("SELECT count(*) FROM abook left join xchan on xchan_hash = abook_xchan WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql",
intval($uid)
);
return ($r) ? $r[0]['total'] : false;
}
break;
case '3':
$sql_extra = " and xchan_network = 'activitypub' ";
break;
default:
break;
}
if ($total) {
$r = q(
"SELECT count(*) FROM abook left join xchan on xchan_hash = abook_xchan WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql",
intval($uid)
);
return ($r) ? $r[0]['total'] : false;
}
$r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan
$r = q(
"SELECT * FROM abook left join xchan on xchan_hash = abook_xchan
WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql",
intval($uid)
);
if ($r) {
for($x = 0; $x < count($r); $x ++) {
$r[$x]['xchan'] = $r[$x]['abook_xchan'];
}
}
return $r;
}
intval($uid)
);
if ($r) {
for ($x = 0; $x < count($r); $x++) {
$r[$x]['xchan'] = $r[$x]['abook_xchan'];
}
}
return $r;
}
if (intval($gid)) {
if ($total) {
$r = q("SELECT count(xchan) as total FROM pgrp_member
if (intval($gid)) {
if ($total) {
$r = q(
"SELECT count(xchan) as total FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0
and abook_blocked = 0 and abook_pending = 0",
intval($gid),
intval($uid),
intval($uid)
);
if ($r) {
return $r[0]['total'];
}
}
intval($gid),
intval($uid),
intval($uid)
);
if ($r) {
return $r[0]['total'];
}
}
$r = q("SELECT * FROM pgrp_member
$r = q(
"SELECT * FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC $pager_sql",
intval($gid),
intval($uid),
intval($uid)
);
if ($r) {
$ret = $r;
}
}
return $ret;
}
intval($gid),
intval($uid),
intval($uid)
);
if ($r) {
$ret = $r;
}
}
return $ret;
}
static function members_xchan($uid,$gid) {
$ret = [];
if (intval($gid)) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
intval($gid),
intval($uid)
);
if ($r) {
foreach ($r as $rv) {
$ret[] = $rv['xchan'];
}
}
}
return $ret;
}
public static function members_xchan($uid, $gid)
{
$ret = [];
if (intval($gid)) {
$r = q(
"SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
intval($gid),
intval($uid)
);
if ($r) {
foreach ($r as $rv) {
$ret[] = $rv['xchan'];
}
}
}
return $ret;
}
static function select($uid,$group = '') {
public static function select($uid, $group = '')
{
$grps = [];
$grps = [];
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($uid)
);
$grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ];
if ($r) {
foreach ($r as $rr) {
$grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ];
}
$r = q(
"SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($uid)
);
$grps[] = ['name' => '', 'hash' => '0', 'selected' => ''];
if ($r) {
foreach ($r as $rr) {
$grps[] = ['name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '')];
}
}
}
return replace_macros(get_markup_template('group_selection.tpl'), [
'$label' => t('Add new connections to this access list'),
'$groups' => $grps
]);
}
return replace_macros(get_markup_template('group_selection.tpl'), [
'$label' => t('Add new connections to this access list'),
'$groups' => $grps
]);
}
static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
public static function widget($every = "connections", $each = "lists", $edit = false, $group_id = 0, $cid = '', $mode = 1)
{
$o = '';
$o = '';
$groups = [];
$groups = [];
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($_SESSION['uid'])
);
$member_of = [];
if ($cid) {
$member_of = self::containing(local_channel(),$cid);
}
$r = q(
"SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($_SESSION['uid'])
);
$member_of = [];
if ($cid) {
$member_of = self::containing(local_channel(), $cid);
}
if ($r) {
foreach ($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($r) {
foreach ($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($edit) {
$groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ];
}
else {
$groupedit = null;
}
if ($edit) {
$groupedit = ['href' => "lists/" . $rr['id'], 'title' => t('edit')];
} else {
$groupedit = null;
}
$groups[] = [
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
'ismember' => in_array($rr['id'],$member_of),
];
}
}
$groups[] = [
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each . '?f=&gid=' . $rr['id'] : $each . "/" . $rr['id']) . ((x($_GET, 'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET, 'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
'ismember' => in_array($rr['id'], $member_of),
];
}
}
return replace_macros(get_markup_template('group_side.tpl'), [
'$title' => t('Lists'),
'$edittext' => t('Edit list'),
'$createtext' => t('Create new list'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),
'$groups' => $groups,
'$add' => t('add'),
]);
}
return replace_macros(get_markup_template('group_side.tpl'), [
'$title' => t('Lists'),
'$edittext' => t('Edit list'),
'$createtext' => t('Create new list'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),
'$groups' => $groups,
'$add' => t('add'),
]);
}
static function expand($g) {
if (! (is_array($g) && count($g))) {
return [];
}
public static function expand($g)
{
if (!(is_array($g) && count($g))) {
return [];
}
$ret = [];
$x = [];
$ret = [];
$x = [];
foreach ($g as $gv) {
foreach ($g as $gv) {
// virtual access lists
// connections:abc is all the connection sof the channel with channel_hash abc
// zot:abc is all of abc's zot6 connections
// activitypub:abc is all of abc's activitypub connections
// virtual access lists
// connections:abc is all the connection sof the channel with channel_hash abc
// zot:abc is all of abc's zot6 connections
// activitypub:abc is all of abc's activitypub connections
if (strpos($gv,'connections:') === 0 || strpos($gv,'zot:') === 0 || strpos($gv,'activitypub:') === 0) {
$sql_extra = EMPTY_STR;
$channel_hash = substr($gv,strpos($gv,':') + 1);
if (strpos($gv,'zot:') === 0) {
if (strpos($gv, 'connections:') === 0 || strpos($gv, 'zot:') === 0 || strpos($gv, 'activitypub:') === 0) {
$sql_extra = EMPTY_STR;
$channel_hash = substr($gv, strpos($gv, ':') + 1);
if (strpos($gv, 'zot:') === 0) {
$sql_extra = " and xchan_network in ('nomad','zot6') ";
}
if (strpos($gv,'activitypub:') === 0) {
$sql_extra = " and xchan_network = 'activitypub' ";
}
$r = q("select channel_id from channel where channel_hash = '%s' ",
dbesc($channel_hash)
);
if ($r) {
foreach ($r as $rv) {
$y = q("select abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 $sql_extra",
intval($rv['channel_id'])
);
if ($y) {
foreach ($y as $yv) {
$ret[] = $yv['abook_xchan'];
}
}
}
}
}
else {
$x[] = $gv;
}
}
}
if (strpos($gv, 'activitypub:') === 0) {
$sql_extra = " and xchan_network = 'activitypub' ";
}
$r = q(
"select channel_id from channel where channel_hash = '%s' ",
dbesc($channel_hash)
);
if ($r) {
foreach ($r as $rv) {
$y = q(
"select abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 $sql_extra",
intval($rv['channel_id'])
);
if ($y) {
foreach ($y as $yv) {
$ret[] = $yv['abook_xchan'];
}
}
}
}
} else {
$x[] = $gv;
}
}
if ($x) {
stringify_array_elms($x,true);
$groups = implode(',', $x);
if ($groups) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
if ($r) {
foreach ($r as $rv) {
$ret[] = $rv['xchan'];
}
}
}
}
return $ret;
}
if ($x) {
stringify_array_elms($x, true);
$groups = implode(',', $x);
if ($groups) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
if ($r) {
foreach ($r as $rv) {
$ret[] = $rv['xchan'];
}
}
}
}
return $ret;
}
static function member_of($c) {
$r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
public static function member_of($c)
{
$r = q(
"SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ",
dbesc($c)
);
dbesc($c)
);
return $r;
}
return $r;
}
static function containing($uid,$c) {
public static function containing($uid, $c)
{
$r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
intval($uid),
dbesc($c)
);
$r = q(
"SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
intval($uid),
dbesc($c)
);
$ret = [];
if ($r) {
foreach ($r as $rv)
$ret[] = $rv['gid'];
}
$ret = [];
if ($r) {
foreach ($r as $rv) {
$ret[] = $rv['gid'];
}
}
return $ret;
}
return $ret;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,463 +4,489 @@ namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig;
/**
* @brief ActivityStreams class.
*
* Parses an ActivityStream JSON string.
*/
class ActivityStreams
{
class ActivityStreams {
public $raw = null;
public $data = null;
public $hub = null;
public $valid = false;
public $deleted = false;
public $id = '';
public $parent_id = '';
public $type = '';
public $actor = null;
public $obj = null;
public $tgt = null;
public $replyto = null;
public $origin = null;
public $owner = null;
public $signer = null;
public $ldsig = null;
public $sigok = false;
public $recips = null;
public $raw_recips = null;
public $implied_create = false;
public $raw = null;
public $data = null;
public $hub = null;
public $valid = false;
public $deleted = false;
public $id = '';
public $parent_id = '';
public $type = '';
public $actor = null;
public $obj = null;
public $tgt = null;
public $replyto = null;
public $origin = null;
public $owner = null;
public $signer = null;
public $ldsig = null;
public $sigok = false;
public $recips = null;
public $raw_recips = null;
public $implied_create = false;
/**
* @brief Constructor for ActivityStreams.
*
* Takes a JSON string or previously decode activity array as parameter,
* decodes it and sets up this object/activity, fetching any required attributes
* which were only referenced by @id/URI.
*
* @param string $string
*/
public function __construct($string, $hub = null, $client = null)
{
/**
* @brief Constructor for ActivityStreams.
*
* Takes a JSON string or previously decode activity array as parameter,
* decodes it and sets up this object/activity, fetching any required attributes
* which were only referenced by @id/URI.
*
* @param string $string
*/
function __construct($string,$hub = null,$client = null) {
$this->raw = $string;
$this->hub = $hub;
$this->raw = $string;
$this->hub = $hub;
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
} else {
$this->data = json_decode($string, true);
}
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string,JSON_UNESCAPED_SLASHES);
}
else {
$this->data = json_decode($string, true);
}
if ($this->data) {
// verify and unpack JSalmon signature if present
// This will only be the case for Zot6 packets
if ($this->data) {
if (is_array($this->data) && array_key_exists('signed', $this->data)) {
$ret = JSalmon::verify($this->data);
$tmp = JSalmon::unpack($this->data['data']);
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG);
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
}
}
}
}
// verify and unpack JSalmon signature if present
// This will only be the case for Zot6 packets
// This indicates only that we have sucessfully decoded JSON.
$this->valid = true;
if (is_array($this->data) && array_key_exists('signed',$this->data)) {
$ret = JSalmon::verify($this->data);
$tmp = JSalmon::unpack($this->data['data']);
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG);
$saved = json_encode($this->data,JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
}
}
}
}
// Special handling for Mastodon "delete actor" activities which will often fail to verify
// because the key cannot be fetched. We will catch this condition elsewhere.
// This indicates only that we have sucessfully decoded JSON.
$this->valid = true;
if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
$this->deleted = $this->data['actor'];
$this->valid = false;
}
}
}
// Special handling for Mastodon "delete actor" activities which will often fail to verify
// because the key cannot be fetched. We will catch this condition elsewhere.
// Attempt to assemble an Activity from what we were given.
if (array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
$this->deleted = $this->data['actor'];
$this->valid = false;
}
}
if ($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor', '', '');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->replyto = $this->get_property_obj('replyTo');
}
$this->ldsig = $this->get_compound_property('signature');
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator', $this->ldsig);
if (
$this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer)
&& is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']
) {
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
}
}
// Attempt to assemble an Activity from what we were given.
// Implied create activity required by C2S specification if no object is present
if ($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->replyto = $this->get_property_obj('replyTo');
if (!$this->obj) {
if (!$client) {
$this->implied_create = true;
}
$this->obj = $this->data;
$this->type = 'Create';
if (!$this->actor) {
$this->actor = $this->get_actor('attributedTo', $this->obj);
}
}
$this->ldsig = $this->get_compound_property('signature');
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator',$this->ldsig);
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer)
&& is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
$this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
}
}
// fetch recursive or embedded activities
// Implied create activity required by C2S specification if no object is present
if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) {
$this->obj['object'] = $this->get_compound_property($this->obj['object']);
}
if (! $this->obj) {
if (! $client) {
$this->implied_create = true;
}
$this->obj = $this->data;
$this->type = 'Create';
if (! $this->actor) {
$this->actor = $this->get_actor('attributedTo',$this->obj);
}
}
// Enumerate and store actors in referenced objects
// fetch recursive or embedded activities
if ($this->obj && is_array($this->obj) && $this->obj['actor']) {
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
}
if ($this->tgt && is_array($this->tgt) && $this->tgt['actor']) {
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
}
if ($this->obj && is_array($this->obj) && array_key_exists('object',$this->obj)) {
$this->obj['object'] = $this->get_compound_property($this->obj['object']);
}
// Determine if this is a followup or response activity
// Enumerate and store actors in referenced objects
$this->parent_id = $this->get_property_obj('inReplyTo');
if ($this->obj && is_array($this->obj) && $this->obj['actor']) {
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
}
if ($this->tgt && is_array($this->tgt) && $this->tgt['actor']) {
$this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
}
if ((!$this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['inReplyTo'];
}
if ((!$this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['id'];
}
}
}
// Determine if this is a followup or response activity
/**
* @brief Return if instantiated ActivityStream is valid.
*
* @return bool Return true if the JSON string could be decoded.
*/
$this->parent_id = $this->get_property_obj('inReplyTo');
public function is_valid()
{
return $this->valid;
}
if ((! $this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['inReplyTo'];
}
if ((! $this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['id'];
}
}
}
public function set_recips($arr)
{
$this->saved_recips = $arr;
}
/**
* @brief Return if instantiated ActivityStream is valid.
*
* @return boolean Return true if the JSON string could be decoded.
*/
/**
* @brief Collects all recipients.
*
* @param string $base
* @param string $namespace (optional) default empty
* @return array
*/
public function collect_recips($base = '', $namespace = '')
{
$x = [];
function is_valid() {
return $this->valid;
}
function set_recips($arr) {
$this->saved_recips = $arr;
}
/**
* @brief Collects all recipients.
*
* @param string $base
* @param string $namespace (optional) default empty
* @return array
*/
function collect_recips($base = '', $namespace = '') {
$x = [];
$fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
foreach ($fields as $f) {
// don't expand these yet
$y = $this->get_property_obj($f, $base, $namespace);
if ($y) {
if (! is_array($this->raw_recips)) {
$this->raw_recips = [];
}
if (! is_array($y)) {
$y = [ $y ];
}
$this->raw_recips[$f] = $y;
$x = array_merge($x, $y);
}
}
$fields = ['to', 'cc', 'bto', 'bcc', 'audience'];
foreach ($fields as $f) {
// don't expand these yet
$y = $this->get_property_obj($f, $base, $namespace);
if ($y) {
if (!is_array($this->raw_recips)) {
$this->raw_recips = [];
}
if (!is_array($y)) {
$y = [$y];
}
$this->raw_recips[$f] = $y;
$x = array_merge($x, $y);
}
}
// not yet ready for prime time
// $x = $this->expand($x,$base,$namespace);
return $x;
}
// $x = $this->expand($x,$base,$namespace);
return $x;
}
function expand($arr,$base = '',$namespace = '') {
$ret = [];
public function expand($arr, $base = '', $namespace = '')
{
$ret = [];
// right now use a hardwired recursion depth of 5
// right now use a hardwired recursion depth of 5
for ($z = 0; $z < 5; $z ++) {
if (is_array($arr) && $arr) {
foreach ($arr as $a) {
if (is_array($a)) {
$ret[] = $a;
}
else {
$x = $this->get_compound_property($a,$base,$namespace);
if ($x) {
$ret = array_merge($ret,$x);
}
}
}
}
}
for ($z = 0; $z < 5; $z++) {
if (is_array($arr) && $arr) {
foreach ($arr as $a) {
if (is_array($a)) {
$ret[] = $a;
} else {
$x = $this->get_compound_property($a, $base, $namespace);
if ($x) {
$ret = array_merge($ret, $x);
}
}
}
}
}
/// @fixme de-duplicate
/// @fixme de-duplicate
return $ret;
}
return $ret;
}
/**
* @brief
/**
* @brief
*
* @param array $base
* @param string $namespace if not set return empty string
* @return string|NULL
*/
public function get_namespace($base, $namespace)
{
if (!$namespace) {
return EMPTY_STR;
}
$key = null;
foreach ([$this->data, $base] as $b) {
if (!$b) {
continue;
}
if (array_key_exists('@context', $b)) {
if (is_array($b['@context'])) {
foreach ($b['@context'] as $ns) {
if (is_array($ns)) {
foreach ($ns as $k => $v) {
if ($namespace === $v) {
$key = $k;
}
}
} else {
if ($namespace === $ns) {
$key = '';
}
}
}
} else {
if ($namespace === $b['@context']) {
$key = '';
}
}
}
}
return $key;
}
/**
* @brief
*
* @param string $property
* @param array $base (optional)
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
public function get_property_obj($property, $base = '', $namespace = '')
{
$prefix = $this->get_namespace($base, $namespace);
if ($prefix === null) {
return null;
}
$base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property;
if (!is_array($base)) {
btlogger('not an array: ' . print_r($base, true));
return null;
}
return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
}
/**
* @brief Fetches a property from an URL.
*
* @param string $url
* @param array $channel (signing channel, default system channel)
* @return NULL|mixed
*/
public function fetch_property($url, $channel = null, $hub = null)
{
return Activity::fetch($url, $channel, $hub);
}
/**
* @brief given a type, determine if this object represents an actor
*
* @param array $base
* @param string $namespace if not set return empty string
* @return string|NULL
*/
function get_namespace($base, $namespace) {
if (! $namespace) {
return EMPTY_STR;
}
$key = null;
foreach ( [ $this->data, $base ] as $b ) {
if (! $b) {
continue;
}
if (array_key_exists('@context', $b)) {
if (is_array($b['@context'])) {
foreach ($b['@context'] as $ns) {
if (is_array($ns)) {
foreach ($ns as $k => $v) {
if ($namespace === $v) {
$key = $k;
}
}
}
else {
if ($namespace === $ns) {
$key = '';
}
}
}
}
else {
if ($namespace === $b['@context']) {
$key = '';
}
}
}
}
return $key;
}
/**
* @brief
* If $type is an array, recurse through each element and return true if any
* of the elements are a known actor type
*
* @param string $property
* @param array $base (optional)
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_property_obj($property, $base = '', $namespace = '') {
$prefix = $this->get_namespace($base, $namespace);
if ($prefix === null) {
return null;
}
$base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property;
if (! is_array($base)) {
btlogger('not an array: ' . print_r($base,true));
return null;
}
return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
}
/**
* @brief Fetches a property from an URL.
*
* @param string $url
* @param array $channel (signing channel, default system channel)
* @return NULL|mixed
*/
function fetch_property($url,$channel = null,$hub = null) {
return Activity::fetch($url,$channel,$hub);
}
static function is_an_actor($s) {
if (! $s) {
return false;
}
return (in_array($s,[ 'Application','Group','Organization','Person','Service' ]));
}
static function is_response_activity($s) {
if (! $s) {
return false;
}
return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ]));
}
/**
* @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_actor($property,$base='',$namespace = '') {
$x = $this->get_property_obj($property, $base, $namespace);
if (self::is_url($x)) {
$y = Activity::get_cached_actor($x);
if ($y) {
return $y;
}
}
$actor = $this->get_compound_property($property,$base,$namespace,true);
if (is_array($actor) && self::is_an_actor($actor['type'])) {
if (array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
$actor = $this->fetch_property($actor['id']);
}
return $actor;
}
return null;
}
/**
* @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
* @param boolean $first (optional) default false, if true and result is a sequential array return only the first element
* @return NULL|mixed
*/
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
$x = $this->get_property_obj($property, $base, $namespace);
if (self::is_url($x)) {
$y = $this->fetch_property($x);
if (is_array($y)) {
$x = $y;
}
}
// verify and unpack JSalmon signature if present
// This may be present in Zot6 packets
if (is_array($x) && array_key_exists('signed',$x)) {
$ret = JSalmon::verify($x);
$tmp = JSalmon::unpack($x['data']);
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG);
$saved = json_encode($x,JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
}
}
}
}
if ($first && is_array($x) && array_key_exists(0,$x)) {
return $x[0];
}
return $x;
}
/**
* @brief Check if string starts with http.
*
* @param string $url
* @param string|array $type
* @return boolean
*/
static public function is_url($url) {
if (($url) && (! is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url,'x-zot') === 0) || (strpos($url,'bear') === 0))) {
return true;
}
return false;
}
/**
* @brief Gets the type property.
*
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_primary_type($base = '', $namespace = '') {
if (! $base) {
$base = $this->data;
}
$x = $this->get_property_obj('type', $base, $namespace);
if (is_array($x)) {
foreach ($x as $y) {
if (strpos($y, ':') === false) {
return $y;
public static function is_an_actor($type)
{
if (!$type) {
return false;
}
if (is_array($type)) {
foreach ($type as $x) {
if (self::is_an_actor($x)) {
return true;
}
}
return false;
}
return (in_array($type, ['Application', 'Group', 'Organization', 'Person', 'Service']));
}
return $x;
}
function debug() {
$x = var_export($this, true);
return $x;
}
public static function is_response_activity($s)
{
if (!$s) {
return false;
}
return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
}
static function is_as_request() {
/**
* @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
$x = getBestSupportedMimeType([
'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
'application/activity+json',
'application/ld+json;profile="http://www.w3.org/ns/activitystreams"',
'application/ld+json', // required for Friendica ~2021-09, can possibly be removed after next release of that project
'application/x-zot-activity+json'
]);
public function get_actor($property, $base = '', $namespace = '')
{
$x = $this->get_property_obj($property, $base, $namespace);
if (self::is_url($x)) {
$y = Activity::get_cached_actor($x);
if ($y) {
return $y;
}
}
return(($x) ? true : false);
}
$actor = $this->get_compound_property($property, $base, $namespace, true);
if (is_array($actor) && self::is_an_actor($actor['type'])) {
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
$actor = $this->fetch_property($actor['id']);
}
return $actor;
}
return null;
}
/**
* @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
* @param bool $first (optional) default false, if true and result is a sequential array return only the first element
* @return NULL|mixed
*/
public function get_compound_property($property, $base = '', $namespace = '', $first = false)
{
$x = $this->get_property_obj($property, $base, $namespace);
if (self::is_url($x)) {
$y = $this->fetch_property($x);
if (is_array($y)) {
$x = $y;
}
}
// verify and unpack JSalmon signature if present
// This may be present in Zot6 packets
if (is_array($x) && array_key_exists('signed', $x)) {
$ret = JSalmon::verify($x);
$tmp = JSalmon::unpack($x['data']);
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG);
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
}
}
}
}
if ($first && is_array($x) && array_key_exists(0, $x)) {
return $x[0];
}
return $x;
}
/**
* @brief Check if string starts with http.
*
* @param string $url
* @return bool
*/
public static function is_url($url)
{
if (($url) && (!is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url, 'x-zot') === 0) || (strpos($url, 'bear') === 0))) {
return true;
}
return false;
}
/**
* @brief Gets the type property.
*
* @param array $base
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
public function get_primary_type($base = '', $namespace = '')
{
if (!$base) {
$base = $this->data;
}
$x = $this->get_property_obj('type', $base, $namespace);
if (is_array($x)) {
foreach ($x as $y) {
if (strpos($y, ':') === false) {
return $y;
}
}
}
return $x;
}
public function debug()
{
$x = var_export($this, true);
return $x;
}
public static function is_as_request()
{
$x = getBestSupportedMimeType([
'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
'application/activity+json',
'application/ld+json;profile="http://www.w3.org/ns/activitystreams"',
'application/ld+json', // required for Friendica ~2021-09, can possibly be removed after next release of that project
'application/x-zot-activity+json'
]);
return (($x) ? true : false);
}
}

View file

@ -2,31 +2,33 @@
namespace Zotlabs\Lib;
class Api_router
{
class Api_router {
private static $routes = [];
static private $routes = [];
public static function register($path, $fn, $auth_required)
{
self::$routes[$path] = ['func' => $fn, 'auth' => $auth_required];
}
static function register($path,$fn,$auth_required) {
self::$routes[$path] = [ 'func' => $fn, 'auth' => $auth_required ];
}
public static function find($path)
{
if (array_key_exists($path, self::$routes)) {
return self::$routes[$path];
}
static function find($path) {
if (array_key_exists($path,self::$routes)) {
return self::$routes[$path];
}
$with_params = dirname($path) . '/[id]';
$with_params = dirname($path) . '/[id]';
if (array_key_exists($with_params, self::$routes)) {
return self::$routes[$with_params];
}
if (array_key_exists($with_params,self::$routes)) {
return self::$routes[$with_params];
}
return null;
}
static function dbg() {
return self::$routes;
}
return null;
}
public static function dbg()
{
return self::$routes;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,51 +1,63 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Lib;
/**
* cache api
*/
/**
* cache api
*/
class Cache {
public static function get($key) {
class Cache
{
public static function get($key)
{
$hash = hash('whirlpool',$key);
$hash = hash('whirlpool', $key);
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
);
$r = q(
"SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
);
if ($r)
return $r[0]['v'];
return null;
}
if ($r) {
return $r[0]['v'];
}
return null;
}
public static function set($key,$value) {
public static function set($key, $value)
{
$hash = hash('whirlpool',$key);
$hash = hash('whirlpool', $key);
$r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
);
if($r) {
q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
dbesc($value),
dbesc(datetime_convert()),
dbesc($hash));
}
else {
q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
dbesc($hash),
dbesc($value),
dbesc(datetime_convert()));
}
}
$r = q(
"SELECT * FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
);
if ($r) {
q(
"UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
dbesc($value),
dbesc(datetime_convert()),
dbesc($hash)
);
} else {
q(
"INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
dbesc($hash),
dbesc($value),
dbesc(datetime_convert())
);
}
}
public static function clear() {
q("DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
}
public static function clear()
{
q(
"DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC', 'UTC', "now - 30 days"))
);
}
}

View file

@ -1,4 +1,5 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\Libsync;
@ -6,272 +7,307 @@ use Zotlabs\Lib\Libsync;
/**
* @brief A class with chatroom related static methods.
*/
class Chatroom {
/**
* @brief Creates a chatroom.
*
* @param array $channel
* @param array $arr
* @return array An associative array containing:
* * \e boolean \b success - A boolean success status
* * \e string \b message - (optional) A string
*/
static public function create($channel, $arr) {
class Chatroom
{
/**
* @brief Creates a chatroom.
*
* @param array $channel
* @param array $arr
* @return array An associative array containing:
* * \e boolean \b success - A boolean success status
* * \e string \b message - (optional) A string
*/
public static function create($channel, $arr)
{
$ret = array('success' => false);
$ret = array('success' => false);
$name = trim($arr['name']);
if(! $name) {
$ret['message'] = t('Missing room name');
return $ret;
}
$name = trim($arr['name']);
if (!$name) {
$ret['message'] = t('Missing room name');
return $ret;
}
$r = q("select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1",
intval($channel['channel_id']),
dbesc($name)
);
if($r) {
$ret['message'] = t('Duplicate room name');
return $ret;
}
$r = q(
"select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1",
intval($channel['channel_id']),
dbesc($name)
);
if ($r) {
$ret['message'] = t('Duplicate room name');
return $ret;
}
$r = q("select count(cr_id) as total from chatroom where cr_aid = %d",
intval($channel['channel_account_id'])
);
if($r)
$limit = service_class_fetch($channel['channel_id'], 'chatrooms');
$r = q(
"select count(cr_id) as total from chatroom where cr_aid = %d",
intval($channel['channel_account_id'])
);
if ($r) {
$limit = service_class_fetch($channel['channel_id'], 'chatrooms');
}
if(($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) {
$ret['message'] = upgrade_message();
return $ret;
}
if (($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) {
$ret['message'] = upgrade_message();
return $ret;
}
if(! array_key_exists('expire', $arr))
$arr['expire'] = 120; // minutes, e.g. 2 hours
if (!array_key_exists('expire', $arr)) {
$arr['expire'] = 120; // minutes, e.g. 2 hours
}
$created = datetime_convert();
$created = datetime_convert();
$x = q("insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid )
$x = q(
"insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid )
values ( %d, %d , '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s' ) ",
intval($channel['channel_account_id']),
intval($channel['channel_id']),
dbesc($name),
dbesc($created),
dbesc($created),
intval($arr['expire']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
dbesc($arr['deny_gid'])
);
intval($channel['channel_account_id']),
intval($channel['channel_id']),
dbesc($name),
dbesc($created),
dbesc($created),
intval($arr['expire']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
dbesc($arr['deny_gid'])
);
if($x)
$ret['success'] = true;
if ($x) {
$ret['success'] = true;
}
return $ret;
}
return $ret;
}
static public function destroy($channel,$arr) {
public static function destroy($channel, $arr)
{
$ret = array('success' => false);
$ret = array('success' => false);
if(intval($arr['cr_id']))
$sql_extra = " and cr_id = " . intval($arr['cr_id']) . " ";
elseif(trim($arr['cr_name']))
$sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' ";
else {
$ret['message'] = t('Invalid room specifier.');
return $ret;
}
if (intval($arr['cr_id'])) {
$sql_extra = " and cr_id = " . intval($arr['cr_id']) . " ";
} elseif (trim($arr['cr_name'])) {
$sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' ";
} else {
$ret['message'] = t('Invalid room specifier.');
return $ret;
}
$r = q("select * from chatroom where cr_uid = %d $sql_extra limit 1",
intval($channel['channel_id'])
);
if(! $r) {
$ret['message'] = t('Invalid room specifier.');
return $ret;
}
$r = q(
"select * from chatroom where cr_uid = %d $sql_extra limit 1",
intval($channel['channel_id'])
);
if (!$r) {
$ret['message'] = t('Invalid room specifier.');
return $ret;
}
Libsync::build_sync_packet($channel['channel_id'],array('chatroom' => $r));
Libsync::build_sync_packet($channel['channel_id'], array('chatroom' => $r));
q("delete from chatroom where cr_id = %d",
intval($r[0]['cr_id'])
);
if($r[0]['cr_id']) {
q("delete from chatpresence where cp_room = %d",
intval($r[0]['cr_id'])
);
q("delete from chat where chat_room = %d",
intval($r[0]['cr_id'])
);
}
q(
"delete from chatroom where cr_id = %d",
intval($r[0]['cr_id'])
);
if ($r[0]['cr_id']) {
q(
"delete from chatpresence where cp_room = %d",
intval($r[0]['cr_id'])
);
q(
"delete from chat where chat_room = %d",
intval($r[0]['cr_id'])
);
}
$ret['success'] = true;
return $ret;
}
$ret['success'] = true;
return $ret;
}
static public function enter($observer_xchan, $room_id, $status, $client) {
public static function enter($observer_xchan, $room_id, $status, $client)
{
if(! $room_id || ! $observer_xchan)
return;
if (!$room_id || !$observer_xchan) {
return;
}
$r = q("select * from chatroom where cr_id = %d limit 1",
intval($room_id)
);
if(! $r) {
notice( t('Room not found.') . EOL);
return false;
}
require_once('include/security.php');
$sql_extra = permissions_sql($r[0]['cr_uid']);
$r = q(
"select * from chatroom where cr_id = %d limit 1",
intval($room_id)
);
if (!$r) {
notice(t('Room not found.') . EOL);
return false;
}
require_once('include/security.php');
$sql_extra = permissions_sql($r[0]['cr_uid']);
$x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
intval($room_id),
intval($r[0]['cr_uid'])
);
if(! $x) {
notice( t('Permission denied.') . EOL);
return false;
}
$x = q(
"select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
intval($room_id),
intval($r[0]['cr_uid'])
);
if (!$x) {
notice(t('Permission denied.') . EOL);
return false;
}
$limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom');
if($limit !== false) {
$y = q("select count(*) as total from chatpresence where cp_room = %d",
intval($room_id)
);
if($y && $y[0]['total'] > $limit) {
notice( t('Room is full') . EOL);
return false;
}
}
$limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom');
if ($limit !== false) {
$y = q(
"select count(*) as total from chatpresence where cp_room = %d",
intval($room_id)
);
if ($y && $y[0]['total'] > $limit) {
notice(t('Room is full') . EOL);
return false;
}
}
if(intval($x[0]['cr_expire'])) {
$r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
db_utcnow(),
db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ),
intval($x[0]['cr_id'])
);
}
if (intval($x[0]['cr_expire'])) {
$r = q(
"delete from chat where created < %s - INTERVAL %s and chat_room = %d",
db_utcnow(),
db_quoteinterval(intval($x[0]['cr_expire']) . ' MINUTE'),
intval($x[0]['cr_id'])
);
}
$r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1",
dbesc($observer_xchan),
intval($room_id)
);
if($r) {
q("update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'",
dbesc(datetime_convert()),
intval($r[0]['cp_id']),
dbesc($client)
);
return true;
}
$r = q(
"select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1",
dbesc($observer_xchan),
intval($room_id)
);
if ($r) {
q(
"update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'",
dbesc(datetime_convert()),
intval($r[0]['cp_id']),
dbesc($client)
);
return true;
}
$r = q("insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client )
$r = q(
"insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client )
values ( %d, '%s', '%s', '%s', '%s' )",
intval($room_id),
dbesc($observer_xchan),
dbesc(datetime_convert()),
dbesc($status),
dbesc($client)
);
intval($room_id),
dbesc($observer_xchan),
dbesc(datetime_convert()),
dbesc($status),
dbesc($client)
);
return $r;
}
return $r;
}
function leave($observer_xchan, $room_id, $client) {
if(! $room_id || ! $observer_xchan)
return;
public function leave($observer_xchan, $room_id, $client)
{
if (!$room_id || !$observer_xchan) {
return;
}
$r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1",
dbesc($observer_xchan),
intval($room_id),
dbesc($client)
);
if($r) {
q("delete from chatpresence where cp_id = %d",
intval($r[0]['cp_id'])
);
}
$r = q(
"select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1",
dbesc($observer_xchan),
intval($room_id),
dbesc($client)
);
if ($r) {
q(
"delete from chatpresence where cp_id = %d",
intval($r[0]['cp_id'])
);
}
return true;
}
return true;
}
static public function roomlist($uid) {
require_once('include/security.php');
$sql_extra = permissions_sql($uid);
public static function roomlist($uid)
{
require_once('include/security.php');
$sql_extra = permissions_sql($uid);
$r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name",
intval($uid)
);
$r = q(
"select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name",
intval($uid)
);
return $r;
}
return $r;
}
static public function list_count($uid) {
require_once('include/security.php');
$sql_extra = permissions_sql($uid);
public static function list_count($uid)
{
require_once('include/security.php');
$sql_extra = permissions_sql($uid);
$r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra",
intval($uid)
);
$r = q(
"select count(*) as total from chatroom where cr_uid = %d $sql_extra",
intval($uid)
);
return $r[0]['total'];
}
return $r[0]['total'];
}
/**
* @brief Create a chat message via API.
*
* It is the caller's responsibility to enter the room.
*
* @param int $uid
* @param int $room_id
* @param string $xchan
* @param string $text
* @return array
*/
static public function message($uid, $room_id, $xchan, $text) {
/**
* @brief Create a chat message via API.
*
* It is the caller's responsibility to enter the room.
*
* @param int $uid
* @param int $room_id
* @param string $xchan
* @param string $text
* @return array
*/
public static function message($uid, $room_id, $xchan, $text)
{
$ret = array('success' => false);
$ret = array('success' => false);
if(! $text)
return;
if (!$text) {
return;
}
$sql_extra = permissions_sql($uid);
$sql_extra = permissions_sql($uid);
$r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
intval($uid),
intval($room_id)
);
if(! $r)
return $ret;
$r = q(
"select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
intval($uid),
intval($room_id)
);
if (!$r) {
return $ret;
}
$arr = [
'chat_room' => $room_id,
'chat_xchan' => $xchan,
'chat_text' => $text
];
/**
* @hooks chat_message
* Called to create a chat message.
* * \e int \b chat_room
* * \e string \b chat_xchan
* * \e string \b chat_text
*/
call_hooks('chat_message', $arr);
$arr = [
'chat_room' => $room_id,
'chat_xchan' => $xchan,
'chat_text' => $text
];
/**
* @hooks chat_message
* Called to create a chat message.
* * \e int \b chat_room
* * \e string \b chat_xchan
* * \e string \b chat_text
*/
call_hooks('chat_message', $arr);
$x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )
$x = q(
"insert into chat ( chat_room, chat_xchan, created, chat_text )
values( %d, '%s', '%s', '%s' )",
intval($room_id),
dbesc($xchan),
dbesc(datetime_convert()),
dbesc(str_rot47(base64url_encode($arr['chat_text'])))
);
intval($room_id),
dbesc($xchan),
dbesc(datetime_convert()),
dbesc(str_rot47(base64url_encode($arr['chat_text'])))
);
$ret['success'] = true;
return $ret;
}
$ret['success'] = true;
return $ret;
}
}

View file

@ -2,161 +2,174 @@
namespace Zotlabs\Lib;
use App;
class Config {
class Config
{
/**
* @brief Loads the hub's configuration from database to a cached storage.
*
* Retrieve a category ($family) of config variables from database to a cached
* storage in the global App::$config[$family].
*
* @param string $family
* The category of the configuration value
*/
static public function Load($family) {
if(! array_key_exists($family, \App::$config))
\App::$config[$family] = [];
/**
* @brief Loads the hub's configuration from database to a cached storage.
*
* Retrieve a category ($family) of config variables from database to a cached
* storage in the global App::$config[$family].
*
* @param string $family
* The category of the configuration value
*/
public static function Load($family)
{
if (! array_key_exists($family, App::$config)) {
App::$config[$family] = [];
}
if(! array_key_exists('config_loaded', \App::$config[$family])) {
$r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
if($r !== false) {
if($r) {
foreach($r as $rr) {
$k = $rr['k'];
\App::$config[$family][$k] = $rr['v'];
}
}
\App::$config[$family]['config_loaded'] = true;
}
}
}
if (! array_key_exists('config_loaded', App::$config[$family])) {
$r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
if ($r !== false) {
if ($r) {
foreach ($r as $rr) {
$k = $rr['k'];
App::$config[$family][$k] = $rr['v'];
}
}
App::$config[$family]['config_loaded'] = true;
}
}
}
/**
* @brief Sets a configuration value for the hub.
*
* Stores a config value ($value) in the category ($family) under the key ($key).
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param mixed $value
* The value to store in the configuration
* @return mixed
* Return the set value, or false if the database update failed
*/
static public function Set($family, $key, $value) {
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
/**
* @brief Sets a configuration value for the hub.
*
* Stores a config value ($value) in the category ($family) under the key ($key).
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param mixed $value
* The value to store in the configuration
* @return mixed
* Return the set value, or false if the database update failed
*/
public static function Set($family, $key, $value)
{
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
$ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
if($ret) {
\App::$config[$family][$key] = $value;
$ret = $value;
}
return $ret;
}
if (self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) {
$ret = q(
"INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
if ($ret) {
App::$config[$family][$key] = $value;
$ret = $value;
}
return $ret;
}
$ret = q("UPDATE config SET v = '%s' WHERE cat = '%s' AND k = '%s'",
dbesc($dbvalue),
dbesc($family),
dbesc($key)
);
$ret = q(
"UPDATE config SET v = '%s' WHERE cat = '%s' AND k = '%s'",
dbesc($dbvalue),
dbesc($family),
dbesc($key)
);
if($ret) {
\App::$config[$family][$key] = $value;
$ret = $value;
}
if ($ret) {
App::$config[$family][$key] = $value;
$ret = $value;
}
return $ret;
}
return $ret;
}
/**
* @brief Get a particular config variable given the category name ($family)
* and a key.
*
* Get a particular config variable from the given category ($family) and the
* $key from a cached storage in App::$config[$family]. If a key is found in the
* DB but does not exist in local config cache, pull it into the cache so we
* do not have to hit the DB again for this item.
*
* Returns false if not set.
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param string $default (optional) default false
* @return mixed Return value or false on error or if not set
*/
static public function Get($family, $key, $default = false) {
if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family])))
self::Load($family);
/**
* @brief Get a particular config variable given the category name ($family)
* and a key.
*
* Get a particular config variable from the given category ($family) and the
* $key from a cached storage in App::$config[$family]. If a key is found in the
* DB but does not exist in local config cache, pull it into the cache so we
* do not have to hit the DB again for this item.
*
* Returns false if not set.
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param string $default (optional) default false
* @return mixed Return value or false on error or if not set
*/
public static function Get($family, $key, $default = false)
{
if ((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family]))) {
self::Load($family);
}
if(array_key_exists('config_loaded', \App::$config[$family])) {
if(! array_key_exists($key, \App::$config[$family])) {
return $default;
}
return unserialise(\App::$config[$family][$key]);
}
if (array_key_exists('config_loaded', App::$config[$family])) {
if (! array_key_exists($key, App::$config[$family])) {
return $default;
}
return unserialise(App::$config[$family][$key]);
}
return $default;
}
return $default;
}
/**
* @brief Deletes the given key from the hub's configuration database.
*
* Removes the configured value from the stored cache in App::$config[$family]
* and removes it from the database.
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
static public function Delete($family, $key) {
/**
* @brief Deletes the given key from the hub's configuration database.
*
* Removes the configured value from the stored cache in App::$config[$family]
* and removes it from the database.
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
public static function Delete($family, $key)
{
$ret = false;
$ret = false;
if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family]))
unset(\App::$config[$family][$key]);
if (array_key_exists($family, App::$config) && array_key_exists($key, App::$config[$family])) {
unset(App::$config[$family][$key]);
}
$ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
dbesc($family),
dbesc($key)
);
$ret = q(
"DELETE FROM config WHERE cat = '%s' AND k = '%s'",
dbesc($family),
dbesc($key)
);
return $ret;
}
return $ret;
}
/**
* @brief Returns a record directly from the database configuration storage.
*
* This function queries directly the database and bypasses the cached storage
* from get_config($family, $key).
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @return mixed
*/
static private function get_from_storage($family,$key) {
$ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
dbesc($family),
dbesc($key)
);
return $ret;
}
/**
* @brief Returns a record directly from the database configuration storage.
*
* This function queries directly the database and bypasses the cached storage
* from get_config($family, $key).
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @return mixed
*/
private static function get_from_storage($family, $key)
{
$ret = q(
"SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
dbesc($family),
dbesc($key)
);
return $ret;
}
}

View file

@ -1,4 +1,6 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Lib;
@ -6,303 +8,304 @@ use App;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Run;
class Connect
{
/**
* Takes a $channel and a $url/handle and adds a new connection
*
* Returns array
* $return['success'] boolean true if successful
* $return['abook'] Address book entry joined with xchan if successful
* $return['message'] error text if success is false.
*
* This function does NOT send sync packets to clones. The caller is responsible for doing this
*/
public static function connect($channel, $url, $sub_channel = false)
{
$uid = $channel['channel_id'];
if (strpos($url, '@') === false && strpos($url, '/') === false) {
$url = $url . '@' . App::get_hostname();
}
$result = ['success' => false, 'message' => ''];
$my_perms = false;
$protocol = '';
$ap_allowed = get_config('system', 'activitypub', ACTIVITYPUB_ENABLED) && get_pconfig($uid, 'system', 'activitypub', ACTIVITYPUB_ENABLED);
if (substr($url, 0, 1) === '[') {
$x = strpos($url, ']');
if ($x) {
$protocol = substr($url, 1, $x - 1);
$url = substr($url, $x + 1);
}
}
if (!check_siteallowed($url)) {
$result['message'] = t('Channel is blocked on this site.');
return $result;
}
if (!$url) {
$result['message'] = t('Channel location missing.');
return $result;
}
// check service class limits
$r = q(
"select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
intval($uid)
);
if ($r) {
$total_channels = $r[0]['total'];
}
if (!service_class_allows($uid, 'total_channels', $total_channels)) {
$result['message'] = upgrade_message();
return $result;
}
$xchan_hash = '';
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
$r = q(
"select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ",
dbesc($url),
dbesc($url),
dbesc($url)
);
if ($r) {
// reset results to the best record or the first if we don't have the best
// note: this returns a single record and not an array of records
$r = Libzot::zot_record_preferred($r, 'xchan_network');
// ensure there's a valid hubloc for this xchan before proceeding - you cannot connect without it
if (in_array($r['xchan_network'], ['nomad', 'zot6', 'activitypub'])) {
$h = q(
"select * from hubloc where hubloc_hash = '%s'",
dbesc($r['xchan_hash'])
);
if (!$h) {
$r = null;
}
}
// we may have nulled out this record so check again
if ($r) {
// Check the site table to see if we should have a zot6 hubloc,
// If so, clear the xchan and start fresh
if ($r['xchan_network'] === 'activitypub') {
$m = parse_url($r['xchan_hash']);
unset($m['path']);
$h = unparse_url($m);
$s = q(
"select * from site where site_url = '%s'",
dbesc($h)
);
if (intval($s['site_type']) === SITE_TYPE_ZOT) {
logger('got zot - ignore activitypub entry');
$r = null;
}
}
}
}
class Connect {
$singleton = false;
/**
* Takes a $channel and a $url/handle and adds a new connection
*
* Returns array
* $return['success'] boolean true if successful
* $return['abook'] Address book entry joined with xchan if successful
* $return['message'] error text if success is false.
*
* This function does NOT send sync packets to clones. The caller is responsible for doing this
*/
if (!$r) {
// not in cache - try discovery
static function connect($channel, $url, $sub_channel = false) {
$wf = discover_by_webbie($url, $protocol, false);
$uid = $channel['channel_id'];
if (!$wf) {
$result['message'] = t('Remote channel or protocol unavailable.');
return $result;
}
}
if (strpos($url,'@') === false && strpos($url,'/') === false) {
$url = $url . '@' . App::get_hostname();
}
if ($wf) {
// something was discovered - find the record which was just created.
$result = [ 'success' => false, 'message' => '' ];
$r = q(
"select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
dbesc(($wf) ? $wf : $url),
dbesc($url),
dbesc($url)
);
$my_perms = false;
$protocol = '';
// convert to a single record (once again preferring a zot solution in the case of multiples)
$ap_allowed = get_config('system','activitypub', ACTIVITYPUB_ENABLED) && get_pconfig($uid,'system','activitypub', ACTIVITYPUB_ENABLED);
if ($r) {
$r = Libzot::zot_record_preferred($r, 'xchan_network');
}
}
if (substr($url,0,1) === '[') {
$x = strpos($url,']');
if ($x) {
$protocol = substr($url,1,$x-1);
$url = substr($url,$x+1);
}
}
// if discovery was a success or the channel was already cached we should have an xchan record in $r
if (! check_siteallowed($url)) {
$result['message'] = t('Channel is blocked on this site.');
return $result;
}
if ($r) {
$xchan = $r;
$xchan_hash = $r['xchan_hash'];
$their_perms = EMPTY_STR;
}
if (! $url) {
$result['message'] = t('Channel location missing.');
return $result;
}
// failure case
// check service class limits
if (!$xchan_hash) {
$result['message'] = t('Channel discovery failed.');
logger('follow: ' . $result['message']);
return $result;
}
$r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
intval($uid)
);
if ($r) {
$total_channels = $r[0]['total'];
}
if (! service_class_allows($uid,'total_channels',$total_channels)) {
$result['message'] = upgrade_message();
return $result;
}
$xchan_hash = '';
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ",
dbesc($url),
dbesc($url),
dbesc($url)
);
if ($r) {
// reset results to the best record or the first if we don't have the best
// note: this returns a single record and not an array of records
$r = Libzot::zot_record_preferred($r,'xchan_network');
// ensure there's a valid hubloc for this xchan before proceeding - you cannot connect without it
if (in_array($r['xchan_network'], [ 'nomad','zot6','activitypub' ])) {
$h = q("select * from hubloc where hubloc_hash = '%s'",
dbesc($r['xchan_hash'])
);
if (! $h) {
$r = null;
}
}
// we may have nulled out this record so check again
if ($r) {
// Check the site table to see if we should have a zot6 hubloc,
// If so, clear the xchan and start fresh
if ($r['xchan_network'] === 'activitypub') {
$m = parse_url($r['xchan_hash']);
unset($m['path']);
$h = unparse_url($m);
$s = q("select * from site where site_url = '%s'",
dbesc($h)
);
if (intval($s['site_type']) === SITE_TYPE_ZOT) {
logger('got zot - ignore activitypub entry');
$r = null;
}
}
}
}
if (!check_channelallowed($xchan_hash)) {
$result['message'] = t('Channel is blocked on this site.');
logger('follow: ' . $result['message']);
return $result;
}
$singleton = false;
if ($r['xchan_network'] === 'activitypub') {
if (!$ap_allowed) {
$result['message'] = t('Protocol not supported');
return $result;
}
$singleton = true;
}
if (! $r) {
// Now start processing the new connection
// not in cache - try discovery
$aid = $channel['channel_account_id'];
$hash = $channel['channel_hash'];
$default_group = $channel['channel_default_group'];
$wf = discover_by_webbie($url,$protocol,false);
if ($hash === $xchan_hash) {
$result['message'] = t('Cannot connect to yourself.');
return $result;
}
if (! $wf) {
$result['message'] = t('Remote channel or protocol unavailable.');
return $result;
}
}
$p = Permissions::connect_perms($uid);
if ($wf) {
// parent channels have unencumbered write permission
// something was discovered - find the record which was just created.
if ($sub_channel) {
$p['perms']['post_wall'] = 1;
$p['perms']['post_comments'] = 1;
$p['perms']['write_storage'] = 1;
$p['perms']['post_like'] = 1;
$p['perms']['delegate'] = 0;
$p['perms']['moderated'] = 0;
}
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
dbesc(($wf) ? $wf : $url),
dbesc($url),
dbesc($url)
);
$my_perms = Permissions::serialise($p['perms']);
// convert to a single record (once again preferring a zot solution in the case of multiples)
$profile_assign = get_pconfig($uid, 'system', 'profile_assign', '');
if ($r) {
$r = Libzot::zot_record_preferred($r,'xchan_network');
}
}
// See if we are already connected by virtue of having an abook record
// if discovery was a success or the channel was already cached we should have an xchan record in $r
if ($r) {
$xchan = $r;
$xchan_hash = $r['xchan_hash'];
$their_perms = EMPTY_STR;
}
// failure case
if (! $xchan_hash) {
$result['message'] = t('Channel discovery failed.');
logger('follow: ' . $result['message']);
return $result;
}
if (! check_channelallowed($xchan_hash)) {
$result['message'] = t('Channel is blocked on this site.');
logger('follow: ' . $result['message']);
return $result;
}
if ($r['xchan_network'] === 'activitypub') {
if (! $ap_allowed) {
$result['message'] = t('Protocol not supported');
return $result;
}
$singleton = true;
}
// Now start processing the new connection
$aid = $channel['channel_account_id'];
$hash = $channel['channel_hash'];
$default_group = $channel['channel_default_group'];
if ($hash === $xchan_hash) {
$result['message'] = t('Cannot connect to yourself.');
return $result;
}
$p = Permissions::connect_perms($uid);
// parent channels have unencumbered write permission
if ($sub_channel) {
$p['perms']['post_wall'] = 1;
$p['perms']['post_comments'] = 1;
$p['perms']['write_storage'] = 1;
$p['perms']['post_like'] = 1;
$p['perms']['delegate'] = 0;
$p['perms']['moderated'] = 0;
}
$my_perms = Permissions::serialise($p['perms']);
$profile_assign = get_pconfig($uid,'system','profile_assign','');
// See if we are already connected by virtue of having an abook record
$r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
$r = q(
"select abook_id, abook_xchan, abook_pending, abook_instance from abook
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)
);
dbesc($xchan_hash),
intval($uid)
);
if ($r) {
if ($r) {
$abook_instance = $r[0]['abook_instance'];
$abook_instance = $r[0]['abook_instance'];
// If they are on a non-nomadic network, add them to this location
// If they are on a non-nomadic network, add them to this location
if (($singleton) && strpos($abook_instance, z_root()) === false) {
if ($abook_instance) {
$abook_instance .= ',';
}
$abook_instance .= z_root();
if (($singleton) && strpos($abook_instance,z_root()) === false) {
if ($abook_instance) {
$abook_instance .= ',';
}
$abook_instance .= z_root();
$x = q(
"update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d",
dbesc($abook_instance),
intval($r[0]['abook_id'])
);
}
$x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d",
dbesc($abook_instance),
intval($r[0]['abook_id'])
);
}
// if they have a pending connection, we just followed them so approve the connection request
// if they have a pending connection, we just followed them so approve the connection request
if (intval($r[0]['abook_pending'])) {
$x = q(
"update abook set abook_pending = 0 where abook_id = %d",
intval($r[0]['abook_id'])
);
}
} else {
// create a new abook record
if (intval($r[0]['abook_pending'])) {
$x = q("update abook set abook_pending = 0 where abook_id = %d",
intval($r[0]['abook_id'])
);
}
}
else {
$closeness = get_pconfig($uid, 'system', 'new_abook_closeness', 80);
// create a new abook record
$r = abook_store_lowlevel(
[
'abook_account' => intval($aid),
'abook_channel' => intval($uid),
'abook_closeness' => intval($closeness),
'abook_xchan' => $xchan_hash,
'abook_profile' => $profile_assign,
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_instance' => (($singleton) ? z_root() : '')
]
);
}
$closeness = get_pconfig($uid,'system','new_abook_closeness',80);
if (!$r) {
logger('abook creation failed');
$result['message'] = t('error saving data');
return $result;
}
$r = abook_store_lowlevel(
[
'abook_account' => intval($aid),
'abook_channel' => intval($uid),
'abook_closeness' => intval($closeness),
'abook_xchan' => $xchan_hash,
'abook_profile' => $profile_assign,
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_instance' => (($singleton) ? z_root() : '')
]
);
}
// Set suitable permissions to the connection
if (! $r) {
logger('abook creation failed');
$result['message'] = t('error saving data');
return $result;
}
if ($my_perms) {
set_abconfig($uid, $xchan_hash, 'system', 'my_perms', $my_perms);
}
// Set suitable permissions to the connection
// fetch the entire record
if ($my_perms) {
set_abconfig($uid,$xchan_hash,'system','my_perms',$my_perms);
}
// fetch the entire record
$r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
$r = q(
"select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)
);
dbesc($xchan_hash),
intval($uid)
);
if ($r) {
$result['abook'] = array_shift($r);
Run::Summon([ 'Notifier', 'permissions_create', $result['abook']['abook_id'] ]);
}
if ($r) {
$result['abook'] = array_shift($r);
Run::Summon(['Notifier', 'permissions_create', $result['abook']['abook_id']]);
}
$arr = [ 'channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook'] ];
$arr = ['channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']];
call_hooks('follow', $arr);
call_hooks('follow', $arr);
/** If there is a default group for this channel, add this connection to it */
/** If there is a default group for this channel, add this connection to it */
if ($default_group) {
$g = AccessList::rec_byhash($uid,$default_group);
if ($g) {
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
}
}
if ($default_group) {
$g = AccessList::rec_byhash($uid, $default_group);
if ($g) {
AccessList::member_add($uid, '', $xchan_hash, $g['id']);
}
}
$result['success'] = true;
return $result;
}
$result['success'] = true;
return $result;
}
}

View file

@ -1,210 +1,213 @@
<?php
namespace Zotlabs\Lib;
use Exception;
class Crypto {
class Crypto
{
static public $openssl_algorithms = [
public static $openssl_algorithms = [
// zot6 nickname, opensslname, keylength, ivlength
// zot6 nickname, opensslname, keylength, ivlength
[ 'aes256ctr', 'aes-256-ctr', 32, 16 ],
[ 'camellia256cfb', 'camellia-256-cfb', 32, 16 ],
[ 'cast5cfb', 'cast5-cfb', 16, 8 ]
[ 'aes256ctr', 'aes-256-ctr', 32, 16 ],
[ 'camellia256cfb', 'camellia-256-cfb', 32, 16 ],
[ 'cast5cfb', 'cast5-cfb', 16, 8 ]
];
];
static public function methods() {
$ret = [];
public static function methods()
{
$ret = [];
foreach(self::$openssl_algorithms as $ossl) {
$ret[] = $ossl[0] . '.oaep';
}
foreach (self::$openssl_algorithms as $ossl) {
$ret[] = $ossl[0] . '.oaep';
}
call_hooks('crypto_methods',$ret);
return $ret;
}
call_hooks('crypto_methods', $ret);
return $ret;
}
static public function signing_methods() {
public static function signing_methods()
{
$ret = [ 'sha256' ];
call_hooks('signing_methods',$ret);
return $ret;
}
$ret = [ 'sha256' ];
call_hooks('signing_methods', $ret);
return $ret;
}
static public function new_keypair($bits) {
public static function new_keypair($bits)
{
$openssl_options = [
'digest_alg' => 'sha1',
'private_key_bits' => $bits,
'encrypt_key' => false
];
$openssl_options = [
'digest_alg' => 'sha1',
'private_key_bits' => $bits,
'encrypt_key' => false
];
$conf = get_config('system','openssl_conf_file');
$conf = get_config('system', 'openssl_conf_file');
if ($conf) {
$openssl_options['config'] = $conf;
}
if ($conf) {
$openssl_options['config'] = $conf;
}
$result = openssl_pkey_new($openssl_options);
$result = openssl_pkey_new($openssl_options);
if (empty($result)) {
return false;
}
if (empty($result)) {
return false;
}
// Get private key
// Get private key
$response = [ 'prvkey' => '', 'pubkey' => '' ];
$response = [ 'prvkey' => '', 'pubkey' => '' ];
openssl_pkey_export($result, $response['prvkey']);
openssl_pkey_export($result, $response['prvkey']);
// Get public key
$pkey = openssl_pkey_get_details($result);
$response['pubkey'] = $pkey["key"];
// Get public key
$pkey = openssl_pkey_get_details($result);
$response['pubkey'] = $pkey["key"];
return $response;
}
return $response;
}
static public function sign($data,$key,$alg = 'sha256') {
public static function sign($data, $key, $alg = 'sha256')
{
if (! $key) {
return false;
}
if (! $key) {
return false;
}
$sig = '';
openssl_sign($data,$sig,$key,$alg);
return $sig;
}
$sig = '';
openssl_sign($data, $sig, $key, $alg);
return $sig;
}
static public function verify($data,$sig,$key,$alg = 'sha256') {
public static function verify($data, $sig, $key, $alg = 'sha256')
{
if (! $key) {
return false;
}
if (! $key) {
return false;
}
try {
$verify = openssl_verify($data,$sig,$key,$alg);
}
catch (Exception $e) {
$verify = (-1);
}
try {
$verify = openssl_verify($data, $sig, $key, $alg);
} catch (Exception $e) {
$verify = (-1);
}
if ($verify === (-1)) {
while ($msg = openssl_error_string()) {
logger('openssl_verify: ' . $msg,LOGGER_NORMAL,LOG_ERR);
}
btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR);
}
if ($verify === (-1)) {
while ($msg = openssl_error_string()) {
logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR);
}
btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR);
}
return (($verify > 0) ? true : false);
}
return (($verify > 0) ? true : false);
}
static public function encapsulate($data,$pubkey,$alg) {
public static function encapsulate($data, $pubkey, $alg)
{
if (! ($alg && $pubkey)) {
return $data;
}
if (! ($alg && $pubkey)) {
return $data;
}
$alg_base = $alg;
$padding = OPENSSL_PKCS1_PADDING;
$alg_base = $alg;
$padding = OPENSSL_PKCS1_PADDING;
$exts = explode('.',$alg);
if (count($exts) > 1) {
switch ($exts[1]) {
case 'oaep':
$padding = OPENSSL_PKCS1_OAEP_PADDING;
break;
default:
break;
}
$alg_base = $exts[0];
}
$exts = explode('.', $alg);
if (count($exts) > 1) {
switch ($exts[1]) {
case 'oaep':
$padding = OPENSSL_PKCS1_OAEP_PADDING;
break;
default:
break;
}
$alg_base = $exts[0];
}
$method = null;
$method = null;
foreach (self::$openssl_algorithms as $ossl) {
if ($ossl[0] === $alg_base) {
$method = $ossl;
break;
}
}
foreach (self::$openssl_algorithms as $ossl) {
if ($ossl[0] === $alg_base) {
$method = $ossl;
break;
}
}
if ($method) {
$result = [ 'encrypted' => true ];
if ($method) {
$result = [ 'encrypted' => true ];
$key = openssl_random_pseudo_bytes(256);
$iv = openssl_random_pseudo_bytes(256);
$key = openssl_random_pseudo_bytes(256);
$iv = openssl_random_pseudo_bytes(256);
$key1 = substr($key, 0, $method[2]);
$iv1 = substr($iv, 0, $method[3]);
$key1 = substr($key, 0, $method[2]);
$iv1 = substr($iv, 0, $method[3]);
$result['data'] = base64url_encode(openssl_encrypt($data,$method[1],$key1,OPENSSL_RAW_DATA,$iv1),true);
$result['data'] = base64url_encode(openssl_encrypt($data, $method[1], $key1, OPENSSL_RAW_DATA, $iv1), true);
openssl_public_encrypt($key, $k, $pubkey, $padding);
openssl_public_encrypt($iv, $i, $pubkey, $padding);
openssl_public_encrypt($key, $k, $pubkey, $padding);
openssl_public_encrypt($iv, $i, $pubkey, $padding);
$result['alg'] = $alg;
$result['key'] = base64url_encode($k,true);
$result['iv'] = base64url_encode($i,true);
return $result;
$result['alg'] = $alg;
$result['key'] = base64url_encode($k, true);
$result['iv'] = base64url_encode($i, true);
return $result;
} else {
$x = [ 'data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data ];
call_hooks('crypto_encapsulate', $x);
return $x['result'];
}
}
}
else {
$x = [ 'data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data ];
call_hooks('crypto_encapsulate', $x);
return $x['result'];
}
}
public static function unencapsulate($data, $prvkey)
{
static public function unencapsulate($data,$prvkey) {
if (! (is_array($data) && array_key_exists('encrypted', $data) && array_key_exists('alg', $data) && $data['alg'])) {
logger('not encrypted');
if (! (is_array($data) && array_key_exists('encrypted',$data) && array_key_exists('alg',$data) && $data['alg'])) {
logger('not encrypted');
return $data;
}
return $data;
}
$alg_base = $data['alg'];
$padding = OPENSSL_PKCS1_PADDING;
$alg_base = $data['alg'];
$padding = OPENSSL_PKCS1_PADDING;
$exts = explode('.', $data['alg']);
if (count($exts) > 1) {
switch ($exts[1]) {
case 'oaep':
$padding = OPENSSL_PKCS1_OAEP_PADDING;
break;
default:
break;
}
$alg_base = $exts[0];
}
$exts = explode('.',$data['alg']);
if (count($exts) > 1) {
switch ($exts[1]) {
case 'oaep':
$padding = OPENSSL_PKCS1_OAEP_PADDING;
break;
default:
break;
}
$alg_base = $exts[0];
}
$method = null;
$method = null;
foreach (self::$openssl_algorithms as $ossl) {
if ($ossl[0] === $alg_base) {
$method = $ossl;
break;
}
}
foreach (self::$openssl_algorithms as $ossl) {
if ($ossl[0] === $alg_base) {
$method = $ossl;
break;
}
}
if ($method) {
openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey,$padding);
openssl_private_decrypt(base64url_decode($data['iv']), $i,$prvkey,$padding);
return openssl_decrypt(base64url_decode($data['data']),$method[1],substr($k,0,$method[2]),OPENSSL_RAW_DATA,substr($i,0,$method[3]));
}
else {
$x = [ 'data' => $data, 'prvkey' => $prvkey, 'alg' => $data['alg'], 'result' => $data ];
call_hooks('crypto_unencapsulate',$x);
return $x['result'];
}
}
if ($method) {
openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey, $padding);
openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey, $padding);
return openssl_decrypt(base64url_decode($data['data']), $method[1], substr($k, 0, $method[2]), OPENSSL_RAW_DATA, substr($i, 0, $method[3]));
} else {
$x = [ 'data' => $data, 'prvkey' => $prvkey, 'alg' => $data['alg'], 'result' => $data ];
call_hooks('crypto_unencapsulate', $x);
return $x['result'];
}
}
}

View file

@ -2,113 +2,116 @@
namespace Zotlabs\Lib;
use App;
class DB_Upgrade {
class DB_Upgrade
{
public $config_name = '';
public $func_prefix = '';
public $config_name = '';
public $func_prefix = '';
function __construct($db_revision) {
public function __construct($db_revision)
{
$this->config_name = 'db_version';
$this->func_prefix = '_';
$this->config_name = 'db_version';
$this->func_prefix = '_';
$build = get_config('system', 'db_version', 0);
if(! intval($build))
$build = set_config('system', 'db_version', $db_revision);
$build = get_config('system', 'db_version', 0);
if (!intval($build)) {
$build = set_config('system', 'db_version', $db_revision);
}
if($build == $db_revision) {
// Nothing to be done.
return;
}
else {
$stored = intval($build);
if(! $stored) {
logger('Critical: check_config unable to determine database schema version');
return;
}
if ($build == $db_revision) {
// Nothing to be done.
return;
} else {
$stored = intval($build);
if (!$stored) {
logger('Critical: check_config unable to determine database schema version');
return;
}
$current = intval($db_revision);
$current = intval($db_revision);
if($stored < $current) {
if ($stored < $current) {
// The last update we performed was $stored.
// Start at $stored + 1 and continue until we have completed $current
// The last update we performed was $stored.
// Start at $stored + 1 and continue until we have completed $current
for ($x = $stored + 1; $x <= $current; $x++) {
$s = '_' . $x;
$cls = '\\Zotlabs\Update\\' . $s;
if (!class_exists($cls)) {
return;
}
for($x = $stored + 1; $x <= $current; $x ++) {
$s = '_' . $x;
$cls = '\\Zotlabs\Update\\' . $s ;
if(! class_exists($cls)) {
return;
}
// There could be a lot of processes running or about to run.
// We want exactly one process to run the update command.
// So store the fact that we're taking responsibility
// after first checking to see if somebody else already has.
// There could be a lot of processes running or about to run.
// We want exactly one process to run the update command.
// So store the fact that we're taking responsibility
// after first checking to see if somebody else already has.
// If the update fails or times-out completely you may need to
// delete the config entry to try again.
// If the update fails or times-out completely you may need to
// delete the config entry to try again.
Config::Load('database');
Config::Load('database');
if(get_config('database', $s))
break;
set_config('database',$s, '1');
if (get_config('database', $s)) {
break;
}
set_config('database', $s, '1');
$c = new $cls();
$c = new $cls();
$retval = $c->run();
$retval = $c->run();
if($retval != UPDATE_SUCCESS) {
if ($retval != UPDATE_SUCCESS) {
$source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php');
$source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php');
// Prevent sending hundreds of thousands of emails by creating
// a lockfile.
$lockfile = 'cache/mailsent';
// Prevent sending hundreds of thousands of emails by creating
// a lockfile.
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400))) {
return;
}
@unlink($lockfile);
//send the administrator an e-mail
file_put_contents($lockfile, $x);
$lockfile = 'cache/mailsent';
$r = q(
"select account_language from account where account_email = '%s' limit 1",
dbesc(App::$config['system']['admin_email'])
);
push_lang(($r) ? $r[0]['account_language'] : 'en');
z_mail(
[
'toEmail' => App::$config['system']['admin_email'],
'messageSubject' => sprintf(t('Update Error at %s'), z_root()),
'textVersion' => replace_macros(
get_intltext_template('update_fail_eml.tpl'),
[
'$sitename' => App::$config['system']['sitename'],
'$siteurl' => z_root(),
'$update' => $x,
'$error' => sprintf(t('Update %s failed. See error logs.'), $x),
'$baseurl' => z_root(),
'$source' => $source
]
)
]
);
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400)))
return;
@unlink($lockfile);
//send the administrator an e-mail
file_put_contents($lockfile, $x);
$r = q("select account_language from account where account_email = '%s' limit 1",
dbesc(\App::$config['system']['admin_email'])
);
push_lang(($r) ? $r[0]['account_language'] : 'en');
z_mail(
[
'toEmail' => \App::$config['system']['admin_email'],
'messageSubject' => sprintf( t('Update Error at %s'), z_root()),
'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'),
[
'$sitename' => \App::$config['system']['sitename'],
'$siteurl' => z_root(),
'$update' => $x,
'$error' => sprintf( t('Update %s failed. See error logs.'), $x),
'$baseurl' => z_root(),
'$source' => $source
]
)
]
);
//try the logger
logger('CRITICAL: Update Failed: ' . $x);
pop_lang();
}
else {
set_config('database',$s, 'success');
}
}
}
set_config('system', 'db_version', $db_revision);
}
}
//try the logger
logger('CRITICAL: Update Failed: ' . $x);
pop_lang();
} else {
set_config('database', $s, 'success');
}
}
}
set_config('system', 'db_version', $db_revision);
}
}
}

View file

@ -1,135 +1,154 @@
<?php
namespace Zotlabs\Lib;
class DReport {
class DReport
{
private $location;
private $sender;
private $recipient;
private $message_id;
private $status;
private $date;
private $location;
private $sender;
private $recipient;
private $message_id;
private $status;
private $date;
function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') {
$this->location = $location;
$this->sender = $sender;
$this->recipient = $recipient;
$this->name = EMPTY_STR;
$this->message_id = $message_id;
$this->status = $status;
$this->date = datetime_convert();
}
public function __construct($location, $sender, $recipient, $message_id, $status = 'deliver')
{
$this->location = $location;
$this->sender = $sender;
$this->recipient = $recipient;
$this->name = EMPTY_STR;
$this->message_id = $message_id;
$this->status = $status;
$this->date = datetime_convert();
}
function update($status) {
$this->status = $status;
$this->date = datetime_convert();
}
public function update($status)
{
$this->status = $status;
$this->date = datetime_convert();
}
function set_name($name) {
$this->name = $name;
}
public function set_name($name)
{
$this->name = $name;
}
function addto_update($status) {
$this->status = $this->status . ' ' . $status;
}
public function addto_update($status)
{
$this->status = $this->status . ' ' . $status;
}
function set($arr) {
$this->location = $arr['location'];
$this->sender = $arr['sender'];
$this->recipient = $arr['recipient'];
$this->name = $arr['name'];
$this->message_id = $arr['message_id'];
$this->status = $arr['status'];
$this->date = $arr['date'];
}
public function set($arr)
{
$this->location = $arr['location'];
$this->sender = $arr['sender'];
$this->recipient = $arr['recipient'];
$this->name = $arr['name'];
$this->message_id = $arr['message_id'];
$this->status = $arr['status'];
$this->date = $arr['date'];
}
function get() {
return array(
'location' => $this->location,
'sender' => $this->sender,
'recipient' => $this->recipient,
'name' => $this->name,
'message_id' => $this->message_id,
'status' => $this->status,
'date' => $this->date
);
}
public function get()
{
return array(
'location' => $this->location,
'sender' => $this->sender,
'recipient' => $this->recipient,
'name' => $this->name,
'message_id' => $this->message_id,
'status' => $this->status,
'date' => $this->date
);
}
/**
* @brief decide whether to store a returned delivery report
*
* @param array $dr
* @return boolean
*/
/**
* @brief decide whether to store a returned delivery report
*
* @param array $dr
* @return bool
*/
static function is_storable($dr) {
public static function is_storable($dr)
{
if(get_config('system', 'disable_dreport'))
return false;
if (get_config('system', 'disable_dreport')) {
return false;
}
/**
* @hooks dreport_is_storable
* Called before storing a dreport record to determine whether to store it.
* * \e array
*/
/**
* @hooks dreport_is_storable
* Called before storing a dreport record to determine whether to store it.
* * \e array
*/
call_hooks('dreport_is_storable', $dr);
call_hooks('dreport_is_storable', $dr);
// let plugins accept or reject - if neither, continue on
if(array_key_exists('accept',$dr) && intval($dr['accept']))
return true;
if(array_key_exists('reject',$dr) && intval($dr['reject']))
return false;
// let plugins accept or reject - if neither, continue on
if (array_key_exists('accept', $dr) && intval($dr['accept'])) {
return true;
}
if (array_key_exists('reject', $dr) && intval($dr['reject'])) {
return false;
}
if(! ($dr['sender']))
return false;
if (!($dr['sender'])) {
return false;
}
// Is the sender one of our channels?
// Is the sender one of our channels?
$c = q("select channel_id from channel where channel_hash = '%s' limit 1",
dbesc($dr['sender'])
);
if(! $c)
return false;
$c = q(
"select channel_id from channel where channel_hash = '%s' limit 1",
dbesc($dr['sender'])
);
if (!$c) {
return false;
}
// is the recipient one of our connections, or do we want to store every report?
// is the recipient one of our connections, or do we want to store every report?
$rxchan = $dr['recipient'];
$pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all');
if($pcf)
return true;
$rxchan = $dr['recipient'];
$pcf = get_pconfig($c[0]['channel_id'], 'system', 'dreport_store_all');
if ($pcf) {
return true;
}
// We always add ourself as a recipient to private and relayed posts
// So if a remote site says they can't find us, that's no big surprise
// and just creates a lot of extra report noise
// We always add ourself as a recipient to private and relayed posts
// So if a remote site says they can't find us, that's no big surprise
// and just creates a lot of extra report noise
if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found'))
return false;
if (($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found')) {
return false;
}
// If you have a private post with a recipient list, every single site is going to report
// back a failed delivery for anybody on that list that isn't local to them. We're only
// concerned about this if we have a local hubloc record which says we expected them to
// have a channel on that site.
// If you have a private post with a recipient list, every single site is going to report
// back a failed delivery for anybody on that list that isn't local to them. We're only
// concerned about this if we have a local hubloc record which says we expected them to
// have a channel on that site.
$r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
dbesc($rxchan),
dbesc($dr['location'])
);
if((! $r) && ($dr['status'] === 'recipient not found'))
return false;
$r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($rxchan),
intval($c[0]['channel_id'])
);
if($r)
return true;
return false;
}
$r = q(
"select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
dbesc($rxchan),
dbesc($dr['location'])
);
if ((!$r) && ($dr['status'] === 'recipient not found')) {
return false;
}
$r = q(
"select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($rxchan),
intval($c[0]['channel_id'])
);
if ($r) {
return true;
}
return false;
}
}

File diff suppressed because it is too large Load diff

View file

@ -8,50 +8,56 @@
namespace Zotlabs\Lib;
use ZipArchive;
/**
* Description of ExtendedZip
*
* @author andrew
*/
class ExtendedZip extends \ZipArchive {
class ExtendedZip extends ZipArchive
{
// Member function to add a whole file system subtree to the archive
public function addTree($dirname, $localname = '') {
if ($localname)
$this->addEmptyDir($localname);
$this->_addTree($dirname, $localname);
}
// Member function to add a whole file system subtree to the archive
public function addTree($dirname, $localname = '')
{
if ($localname) {
$this->addEmptyDir($localname);
}
$this->_addTree($dirname, $localname);
}
// Internal function, to recurse
protected function _addTree($dirname, $localname) {
$dir = opendir($dirname);
while ($filename = readdir($dir)) {
// Discard . and ..
if ($filename == '.' || $filename == '..')
continue;
// Internal function, to recurse
protected function _addTree($dirname, $localname)
{
$dir = opendir($dirname);
while ($filename = readdir($dir)) {
// Discard . and ..
if ($filename == '.' || $filename == '..') {
continue;
}
// Proceed according to type
$path = $dirname . '/' . $filename;
$localpath = $localname ? ($localname . '/' . $filename) : $filename;
if (is_dir($path)) {
// Directory: add & recurse
$this->addEmptyDir($localpath);
$this->_addTree($path, $localpath);
}
else if (is_file($path)) {
// File: just add
$this->addFile($path, $localpath);
}
}
closedir($dir);
}
// Helper function
public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '') {
$zip = new self();
$zip->open($zipFilename, $flags);
$zip->addTree($dirname, $localname);
$zip->close();
}
// Proceed according to type
$path = $dirname . '/' . $filename;
$localpath = $localname ? ($localname . '/' . $filename) : $filename;
if (is_dir($path)) {
// Directory: add & recurse
$this->addEmptyDir($localpath);
$this->_addTree($path, $localpath);
} elseif (is_file($path)) {
// File: just add
$this->addFile($path, $localpath);
}
}
closedir($dir);
}
// Helper function
public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '')
{
$zip = new self();
$zip->open($zipFilename, $flags);
$zip->addTree($dirname, $localname);
$zip->close();
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace Zotlabs\Lib;
namespace Zotlabs\Lib;
/*
* Zotlabs\Lib\Hashpath
@ -28,29 +28,30 @@ namespace Zotlabs\Lib;
*
*/
class Hashpath {
class Hashpath
{
static function path($url, $prefix = '.', $depth = 1, $mkdir = true) {
$hash = hash('sha256', $url);
$start = 0;
$slice = 2;
if ($depth < 1) {
$depth = 1;
}
$sluglen = $depth * $slice;
public static function path($url, $prefix = '.', $depth = 1, $mkdir = true)
{
$hash = hash('sha256', $url);
$start = 0;
$slice = 2;
if ($depth < 1) {
$depth = 1;
}
$sluglen = $depth * $slice;
do {
$slug = substr($hash,$start,$slice);
$prefix .= '/' . $slug;
$start += $slice;
$sluglen -= $slice;
}
while ($sluglen);
do {
$slug = substr($hash, $start, $slice);
$prefix .= '/' . $slug;
$start += $slice;
$sluglen -= $slice;
} while ($sluglen);
if ($mkdir) {
os_mkdir($prefix, STORAGE_DEFAULT_PERMISSIONS, true);
}
if ($mkdir) {
os_mkdir($prefix, STORAGE_DEFAULT_PERMISSIONS, true);
}
return $prefix . '/' . $hash;
}
return $prefix . '/' . $hash;
}
}

View file

@ -2,173 +2,181 @@
namespace Zotlabs\Lib;
class IConfig
{
public static function Load(&$item)
{
return;
}
public static function Get(&$item, $family, $key, $default = false)
{
$is_item = false;
if (is_array($item)) {
$is_item = true;
if ((! array_key_exists('iconfig', $item)) || (! is_array($item['iconfig']))) {
$item['iconfig'] = [];
}
if (array_key_exists('item_id', $item)) {
$iid = $item['item_id'];
} else {
$iid = ((isset($item['id'])) ? $item['id'] : 0);
}
if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $c) {
if ($c['cat'] == $family && $c['k'] == $key) {
return $c['v'];
}
}
}
} elseif (intval($item)) {
$iid = $item;
}
if (! $iid) {
return $default;
}
$r = q(
"select * from iconfig where iid = %d and cat = '%s' and k = '%s' limit 1",
intval($iid),
dbesc($family),
dbesc($key)
);
if ($r) {
$r[0]['v'] = unserialise($r[0]['v']);
if ($is_item) {
$item['iconfig'][] = $r[0];
}
return $r[0]['v'];
}
return $default;
}
/**
* IConfig::Set(&$item, $family, $key, $value, $sharing = false);
*
* $item - item array or item id. If passed an array the iconfig meta information is
* added to the item structure (which will need to be saved with item_store eventually).
* If passed an id, the DB is updated, but may not be federated and/or cloned.
* $family - namespace of meta variable
* $key - key of meta variable
* $value - value of meta variable
* $sharing - boolean (default false); if true the meta information is propagated with the item
* to other sites/channels, mostly useful when $item is an array and has not yet been stored/delivered.
* If the meta information is added after delivery and you wish it to be shared, it may be necessary to
* alter the item edited timestamp and invoke the delivery process on the updated item. The edited
* timestamp needs to be altered in order to trigger an item_store_update() at the receiving end.
*/
class IConfig {
public static function Set(&$item, $family, $key, $value, $sharing = false)
{
static public function Load(&$item) {
return;
}
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
static public function Get(&$item, $family, $key, $default = false) {
$is_item = false;
$idx = null;
$is_item = false;
if (is_array($item)) {
$is_item = true;
if ((! array_key_exists('iconfig', $item)) || (! is_array($item['iconfig']))) {
$item['iconfig'] = [];
} elseif ($item['iconfig']) {
for ($x = 0; $x < count($item['iconfig']); $x++) {
if ($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
$idx = $x;
}
}
}
$entry = array('cat' => $family, 'k' => $key, 'v' => $value, 'sharing' => $sharing);
if (is_array($item)) {
$is_item = true;
if (is_null($idx)) {
$item['iconfig'][] = $entry;
} else {
$item['iconfig'][$idx] = $entry;
}
return $value;
}
if ((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig']))) {
$item['iconfig'] = [];
}
if (intval($item)) {
$iid = intval($item);
}
if (array_key_exists('item_id',$item)) {
$iid = $item['item_id'];
}
else {
$iid = ((isset($item['id'])) ? $item['id'] : 0);
}
if (! $iid) {
return false;
}
if (array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $c) {
if ($c['cat'] == $family && $c['k'] == $key) {
return $c['v'];
}
}
}
}
elseif (intval($item)) {
$iid = $item;
}
if (self::Get($item, $family, $key) === false) {
$r = q(
"insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
intval($iid),
dbesc($family),
dbesc($key),
dbesc($dbvalue),
intval($sharing)
);
} else {
$r = q(
"update iconfig set v = '%s', sharing = %d where iid = %d and cat = '%s' and k = '%s' ",
dbesc($dbvalue),
intval($sharing),
intval($iid),
dbesc($family),
dbesc($key)
);
}
if (! $iid) {
return $default;
}
if (! $r) {
return false;
}
$r = q("select * from iconfig where iid = %d and cat = '%s' and k = '%s' limit 1",
intval($iid),
dbesc($family),
dbesc($key)
);
if ($r) {
$r[0]['v'] = unserialise($r[0]['v']);
if ($is_item) {
$item['iconfig'][] = $r[0];
}
return $r[0]['v'];
}
return $default;
}
/**
* IConfig::Set(&$item, $family, $key, $value, $sharing = false);
*
* $item - item array or item id. If passed an array the iconfig meta information is
* added to the item structure (which will need to be saved with item_store eventually).
* If passed an id, the DB is updated, but may not be federated and/or cloned.
* $family - namespace of meta variable
* $key - key of meta variable
* $value - value of meta variable
* $sharing - boolean (default false); if true the meta information is propagated with the item
* to other sites/channels, mostly useful when $item is an array and has not yet been stored/delivered.
* If the meta information is added after delivery and you wish it to be shared, it may be necessary to
* alter the item edited timestamp and invoke the delivery process on the updated item. The edited
* timestamp needs to be altered in order to trigger an item_store_update() at the receiving end.
*/
static public function Set(&$item, $family, $key, $value, $sharing = false) {
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
$is_item = false;
$idx = null;
if(is_array($item)) {
$is_item = true;
if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
$item['iconfig'] = [];
elseif($item['iconfig']) {
for($x = 0; $x < count($item['iconfig']); $x ++) {
if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
$idx = $x;
}
}
}
$entry = array('cat' => $family, 'k' => $key, 'v' => $value, 'sharing' => $sharing);
if(is_null($idx))
$item['iconfig'][] = $entry;
else
$item['iconfig'][$idx] = $entry;
return $value;
}
if(intval($item))
$iid = intval($item);
if(! $iid)
return false;
if(self::Get($item, $family, $key) === false) {
$r = q("insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
intval($iid),
dbesc($family),
dbesc($key),
dbesc($dbvalue),
intval($sharing)
);
}
else {
$r = q("update iconfig set v = '%s', sharing = %d where iid = %d and cat = '%s' and k = '%s' ",
dbesc($dbvalue),
intval($sharing),
intval($iid),
dbesc($family),
dbesc($key)
);
}
if(! $r)
return false;
return $value;
}
return $value;
}
static public function Delete(&$item, $family, $key) {
public static function Delete(&$item, $family, $key)
{
$is_item = false;
$idx = null;
$is_item = false;
$idx = null;
if(is_array($item)) {
$is_item = true;
if(is_array($item['iconfig'])) {
for($x = 0; $x < count($item['iconfig']); $x ++) {
if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
unset($item['iconfig'][$x]);
}
}
// re-order the array index
$item['iconfig'] = array_values($item['iconfig']);
}
return true;
}
if (is_array($item)) {
$is_item = true;
if (is_array($item['iconfig'])) {
for ($x = 0; $x < count($item['iconfig']); $x++) {
if ($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
unset($item['iconfig'][$x]);
}
}
// re-order the array index
$item['iconfig'] = array_values($item['iconfig']);
}
return true;
}
if(intval($item))
$iid = intval($item);
if (intval($item)) {
$iid = intval($item);
}
if(! $iid)
return false;
return q("delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
intval($iid),
dbesc($family),
dbesc($key)
);
}
if (! $iid) {
return false;
}
return q(
"delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
intval($iid),
dbesc($family),
dbesc($key)
);
}
}

View file

@ -1,87 +1,83 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\Hashpath;
use Zotlabs\Daemon\Run;
class Img_cache {
class Img_cache
{
static $cache_life = 18600 * 7;
public static $cache_life = 18600 * 7;
static function get_filename($url, $prefix = '.') {
return Hashpath::path($url,$prefix);
}
public static function get_filename($url, $prefix = '.')
{
return Hashpath::path($url, $prefix);
}
// Check to see if we have this url in our cache
// If we have it return true.
// If we do not, or the cache file is empty or expired, return false
// but attempt to fetch the entry in the background
// Check to see if we have this url in our cache
// If we have it return true.
// If we do not, or the cache file is empty or expired, return false
// but attempt to fetch the entry in the background
static function check($url, $prefix = '.') {
public static function check($url, $prefix = '.')
{
if (strpos($url,z_root()) !== false) {
return false;
}
if (strpos($url, z_root()) !== false) {
return false;
}
$path = self::get_filename($url,$prefix);
if (file_exists($path)) {
$t = filemtime($path);
if ($t && time() - $t >= self::$cache_life) {
Run::Summon( [ 'Cache_image', $url, $path ] );
return false;
}
else {
return ((filesize($path)) ? true : false);
}
}
$path = self::get_filename($url, $prefix);
if (file_exists($path)) {
$t = filemtime($path);
if ($t && time() - $t >= self::$cache_life) {
Run::Summon(['Cache_image', $url, $path]);
return false;
} else {
return ((filesize($path)) ? true : false);
}
}
// Cache_image invokes url_to_cache() as a background task
// Cache_image invokes url_to_cache() as a background task
Run::Summon( [ 'Cache_image', $url, $path ] );
return false;
}
Run::Summon(['Cache_image', $url, $path]);
return false;
}
static function url_to_cache($url,$file) {
public static function url_to_cache($url, $file)
{
$fp = fopen($file,'wb');
$fp = fopen($file, 'wb');
if (! $fp) {
logger('failed to open storage file: ' . $file,LOGGER_NORMAL,LOG_ERR);
return false;
}
if (!$fp) {
logger('failed to open storage file: ' . $file, LOGGER_NORMAL, LOG_ERR);
return false;
}
// don't check certs, and since we're running in the background,
// allow a two-minute timeout rather than the default one minute.
// This is a compromise. We want to cache all the slow sites we can,
// but don't want to rack up too many processes doing so.
// don't check certs, and since we're running in the background,
// allow a two-minute timeout rather than the default one minute.
// This is a compromise. We want to cache all the slow sites we can,
// but don't want to rack up too many processes doing so.
$redirects = 0;
$x = z_fetch_url($url,true,$redirects,[ 'filep' => $fp, 'novalidate' => true, 'timeout' => 120 ]);
$redirects = 0;
$x = z_fetch_url($url, true, $redirects, ['filep' => $fp, 'novalidate' => true, 'timeout' => 120]);
fclose($fp);
fclose($fp);
if ($x['success'] && file_exists($file)) {
$i = @getimagesize($file);
if ($i && $i[2]) { // looking for non-zero imagetype
Run::Summon( [ 'CacheThumb' , basename($file) ] );
return true;
}
}
if ($x['success'] && file_exists($file)) {
$i = @getimagesize($file);
if ($i && $i[2]) { // looking for non-zero imagetype
Run::Summon(['CacheThumb', basename($file)]);
return true;
}
}
// We could not cache the image for some reason. Leave an empty file here
// to provide a record of the attempt. We'll use this as a flag to avoid
// doing it again repeatedly.
file_put_contents($file, EMPTY_STR);
logger('cache failed from ' . $url);
return false;
}
// We could not cache the image for some reason. Leave an empty file here
// to provide a record of the attempt. We'll use this as a flag to avoid
// doing it again repeatedly.
file_put_contents($file, EMPTY_STR);
logger('cache failed from ' . $url);
return false;
}
}

View file

@ -2,51 +2,56 @@
namespace Zotlabs\Lib;
class Img_filesize {
class Img_filesize
{
private $url;
private $url;
function __construct($url) {
$this->url = $url;
}
public function __construct($url)
{
$this->url = $url;
}
function getSize() {
$size = null;
public function getSize()
{
$size = null;
if(stripos($this->url,z_root() . '/photo') !== false) {
$size = self::getLocalFileSize($this->url);
}
if(! $size) {
$size = getRemoteFileSize($this->url);
}
if (stripos($this->url, z_root() . '/photo') !== false) {
$size = self::getLocalFileSize($this->url);
}
if (!$size) {
$size = getRemoteFileSize($this->url);
}
return $size;
}
return $size;
}
static function getLocalFileSize($url) {
public static function getLocalFileSize($url)
{
$fname = basename($url);
$resolution = 0;
$fname = basename($url);
$resolution = 0;
if(strpos($fname,'.') !== false)
$fname = substr($fname,0,strpos($fname,'.'));
if (strpos($fname, '.') !== false) {
$fname = substr($fname, 0, strpos($fname, '.'));
}
if(substr($fname,-2,1) == '-') {
$resolution = intval(substr($fname,-1,1));
$fname = substr($fname,0,-2);
}
$r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($fname),
intval($resolution)
);
if($r) {
return $r[0]['filesize'];
}
return null;
}
if (substr($fname, -2, 1) == '-') {
$resolution = intval(substr($fname, -1, 1));
$fname = substr($fname, 0, -2);
}
$r = q(
"SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($fname),
intval($resolution)
);
if ($r) {
return $r[0]['filesize'];
}
return null;
}
}
/**
@ -78,7 +83,7 @@ function getRemoteFileSize($url)
curl_setopt($ch, CURLOPT_VERBOSE, 0); // set to 1 to debug
curl_setopt($ch, CURLOPT_STDERR, fopen('php://output', 'r'));
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $line) use (&$in_headers, &$size) {
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $line) use (&$in_headers, &$size) {
$length = strlen($line);
if (trim($line) == '') {
@ -93,7 +98,7 @@ function getRemoteFileSize($url)
list($rng, $s) = explode('/', $content, 2);
$size = (int)$s;
return 0; // aborts transfer
} else if ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
} elseif ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
// found content-length header and this is not a 206 Partial Content response (range response)
$size = (int)$content;
return 0;
@ -103,7 +108,7 @@ function getRemoteFileSize($url)
}
});
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use ($in_headers) {
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($curl, $data) use ($in_headers) {
if (!$in_headers) {
// shouldn't be here unless we couldn't determine file size
// abort transfer
@ -116,7 +121,7 @@ function getRemoteFileSize($url)
curl_exec($ch);
curl_getinfo($ch);
curl_close($ch);
curl_close($ch);
return $size;
}

View file

@ -4,69 +4,70 @@ namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig;
class JSalmon {
class JSalmon
{
static function sign($data,$key_id,$key,$data_type = 'application/x-nomad+json') {
public static function sign($data, $key_id, $key, $data_type = 'application/x-nomad+json')
{
$data = base64url_encode(json_encode($data,true),true); // strip padding
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$data = base64url_encode(json_encode($data, true), true); // strip padding
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$data = preg_replace('/\s+/','',$data);
$data = preg_replace('/\s+/', '', $data);
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
$precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
$precomputed = '.' . base64url_encode($data_type, true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
$signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true);
$signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true);
return ([
'signed' => true,
'data' => $data,
'data_type' => $data_type,
'encoding' => $encoding,
'alg' => $algorithm,
'sigs' => [
'value' => $signature,
'key_id' => base64url_encode($key_id, true)
]
]);
return ([
'signed' => true,
'data' => $data,
'data_type' => $data_type,
'encoding' => $encoding,
'alg' => $algorithm,
'sigs' => [
'value' => $signature,
'key_id' => base64url_encode($key_id, true)
]
]);
}
}
public static function verify($x)
{
static function verify($x) {
logger('verify');
$ret = ['results' => []];
logger('verify');
$ret = [ 'results' => [] ];
if (!is_array($x)) {
return false;
}
if (!(array_key_exists('signed', $x) && $x['signed'])) {
return false;
}
if(! is_array($x)) {
return false;
}
if(! ( array_key_exists('signed',$x) && $x['signed'])) {
return false;
}
$signed_data = preg_replace('/\s+/', '', $x['data']) . '.'
. base64url_encode($x['data_type'], true) . '.'
. base64url_encode($x['encoding'], true) . '.'
. base64url_encode($x['alg'], true);
$signed_data = preg_replace('/\s+/','',$x['data']) . '.'
. base64url_encode($x['data_type'],true) . '.'
. base64url_encode($x['encoding'],true) . '.'
. base64url_encode($x['alg'],true);
$key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id']));
logger('key: ' . print_r($key,true));
if($key['portable_id'] && $key['public_key']) {
if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
logger('verified');
$ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ];
}
}
return $ret;
}
static function unpack($data) {
return json_decode(base64url_decode($data),true);
}
$key = HTTPSig::get_key(EMPTY_STR, 'zot6', base64url_decode($x['sigs']['key_id']));
logger('key: ' . print_r($key, true));
if ($key['portable_id'] && $key['public_key']) {
if (Crypto::verify($signed_data, base64url_decode($x['sigs']['value']), $key['public_key'])) {
logger('verified');
$ret = ['success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc']];
}
}
return $ret;
}
public static function unpack($data)
{
return json_decode(base64url_decode($data), true);
}
}

View file

@ -9,91 +9,94 @@ use phpseclib\Math\BigInteger;
* Keyutils
* Convert RSA keys between various formats
*/
class Keyutils {
class Keyutils
{
/**
* @param string $m modulo
* @param string $e exponent
* @return string
*/
public static function meToPem($m, $e) {
/**
* @param string $m modulo
* @param string $e exponent
* @return string
*/
public static function meToPem($m, $e)
{
$rsa = new RSA();
$rsa->loadKey([
'e' => new BigInteger($e, 256),
'n' => new BigInteger($m, 256)
]);
return $rsa->getPublicKey();
$rsa = new RSA();
$rsa->loadKey([
'e' => new BigInteger($e, 256),
'n' => new BigInteger($m, 256)
]);
return $rsa->getPublicKey();
}
}
/**
* @param string key
* @return string
*/
public static function rsaToPem($key)
{
/**
* @param string key
* @return string
*/
public static function rsaToPem($key) {
$rsa = new RSA();
$rsa->setPublicKey($key);
$rsa = new RSA();
$rsa->setPublicKey($key);
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
}
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
/**
* @param string key
* @return string
*/
public static function pemToRsa($key)
{
}
$rsa = new RSA();
$rsa->setPublicKey($key);
/**
* @param string key
* @return string
*/
public static function pemToRsa($key) {
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
}
$rsa = new RSA();
$rsa->setPublicKey($key);
/**
* @param string $key key
* @param string $m reference modulo
* @param string $e reference exponent
*/
public static function pemToMe($key, &$m, &$e)
{
return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
$rsa = new RSA();
$rsa->loadKey($key);
$rsa->setPublicKey();
}
$m = $rsa->modulus->toBytes();
$e = $rsa->exponent->toBytes();
}
/**
* @param string $key key
* @param string $m reference modulo
* @param string $e reference exponent
*/
public static function pemToMe($key, &$m, &$e) {
/**
* @param string $pubkey
* @return string
*/
public static function salmonKey($pubkey)
{
self::pemToMe($pubkey, $m, $e);
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
}
$rsa = new RSA();
$rsa->loadKey($key);
$rsa->setPublicKey();
/**
* @param string $key
* @return string
*/
public static function convertSalmonKey($key)
{
if (strstr($key, ',')) {
$rawkey = substr($key, strpos($key, ',') + 1);
} else {
$rawkey = substr($key, 5);
}
$m = $rsa->modulus->toBytes();
$e = $rsa->exponent->toBytes();
$key_info = explode('.', $rawkey);
}
/**
* @param string $pubkey
* @return string
*/
public static function salmonKey($pubkey) {
self::pemToMe($pubkey, $m, $e);
return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
}
/**
* @param string $key
* @return string
*/
public static function convertSalmonKey($key) {
if (strstr($key, ','))
$rawkey = substr($key, strpos($key, ',') + 1);
else
$rawkey = substr($key, 5);
$key_info = explode('.', $rawkey);
$m = base64url_decode($key_info[1]);
$e = base64url_decode($key_info[2]);
return self::meToPem($m, $e);
}
$m = base64url_decode($key_info[1]);
$e = base64url_decode($key_info[2]);
return self::meToPem($m, $e);
}
}

View file

@ -2,131 +2,137 @@
namespace Zotlabs\Lib;
use Exception;
use Zotlabs\Lib\Activity;
require_once('library/jsonld/jsonld.php');
class LDSignatures {
class LDSignatures
{
static function verify($data,$pubkey) {
public static function verify($data, $pubkey)
{
$ohash = self::hash(self::signable_options($data['signature']));
$dhash = self::hash(self::signable_data($data));
$ohash = self::hash(self::signable_options($data['signature']));
$dhash = self::hash(self::signable_data($data));
$x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
logger('LD-verify: ' . intval($x));
$x = Crypto::verify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey);
logger('LD-verify: ' . intval($x));
return $x;
}
return $x;
}
static function dopplesign(&$data,$channel) {
// remove for the time being - performance issues
// $data['magicEnv'] = self::salmon_sign($data,$channel);
return self::sign($data,$channel);
}
public static function dopplesign(&$data, $channel)
{
// remove for the time being - performance issues
// $data['magicEnv'] = self::salmon_sign($data,$channel);
return self::sign($data, $channel);
}
static function sign($data,$channel) {
public static function sign($data, $channel)
{
$options = [
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => channel_url($channel),
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
];
$options = [
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => channel_url($channel),
'created' => datetime_convert('UTC', 'UTC', 'now', 'Y-m-d\TH:i:s\Z')
];
$ohash = self::hash(self::signable_options($options));
$dhash = self::hash(self::signable_data($data));
$options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash,$channel['channel_prvkey']));
$ohash = self::hash(self::signable_options($options));
$dhash = self::hash(self::signable_data($data));
$options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash, $channel['channel_prvkey']));
return $options;
}
return $options;
}
static function signable_data($data) {
public static function signable_data($data)
{
$newdata = [];
if($data) {
foreach($data as $k => $v) {
if(! in_array($k,[ 'signature' ])) {
$newdata[$k] = $v;
}
}
}
return json_encode($newdata,JSON_UNESCAPED_SLASHES);
}
$newdata = [];
if ($data) {
foreach ($data as $k => $v) {
if (!in_array($k, ['signature'])) {
$newdata[$k] = $v;
}
}
}
return json_encode($newdata, JSON_UNESCAPED_SLASHES);
}
static function signable_options($options) {
public static function signable_options($options)
{
$newopts = [ '@context' => 'https://w3id.org/identity/v1' ];
if($options) {
foreach($options as $k => $v) {
if(! in_array($k,[ 'type','id','signatureValue' ])) {
$newopts[$k] = $v;
}
}
}
return json_encode($newopts,JSON_UNESCAPED_SLASHES);
}
$newopts = ['@context' => 'https://w3id.org/identity/v1'];
if ($options) {
foreach ($options as $k => $v) {
if (!in_array($k, ['type', 'id', 'signatureValue'])) {
$newopts[$k] = $v;
}
}
}
return json_encode($newopts, JSON_UNESCAPED_SLASHES);
}
static function hash($obj) {
public static function hash($obj)
{
return hash('sha256',self::normalise($obj));
}
return hash('sha256', self::normalise($obj));
}
static function normalise($data) {
if(is_string($data)) {
$data = json_decode($data);
}
public static function normalise($data)
{
if (is_string($data)) {
$data = json_decode($data);
}
if(! is_object($data))
return '';
if (!is_object($data)) {
return '';
}
jsonld_set_document_loader('jsonld_document_loader');
jsonld_set_document_loader('jsonld_document_loader');
try {
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
}
catch (\Exception $e) {
// Don't log the exception - this can exhaust memory
// logger('normalise error:' . print_r($e,true));
logger('normalise error: ' . print_r($data,true));
}
try {
$d = jsonld_normalize($data, ['algorithm' => 'URDNA2015', 'format' => 'application/nquads']);
} catch (Exception $e) {
// Don't log the exception - this can exhaust memory
// logger('normalise error:' . print_r($e,true));
logger('normalise error: ' . print_r($data, true));
}
return $d;
}
return $d;
}
static function salmon_sign($data,$channel) {
public static function salmon_sign($data, $channel)
{
$arr = $data;
$data = json_encode($data,JSON_UNESCAPED_SLASHES);
$data = base64url_encode($data, false); // do not strip padding
$data_type = 'application/activity+json';
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$keyhash = base64url_encode(channel_url($channel));
$arr = $data;
$data = json_encode($data, JSON_UNESCAPED_SLASHES);
$data = base64url_encode($data, false); // do not strip padding
$data_type = 'application/activity+json';
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$keyhash = base64url_encode(channel_url($channel));
$data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data);
$data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $data);
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
$precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
$signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey']));
return ([
'id' => $arr['id'],
'meData' => $data,
'meDataType' => $data_type,
'meEncoding' => $encoding,
'meAlgorithm' => $algorithm,
'meCreator' => channel_url($channel),
'meSignatureValue' => $signature
]);
}
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
$precomputed = '.' . base64url_encode($data_type, false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
$signature = base64url_encode(Crypto::sign($data . $precomputed, $channel['channel_prvkey']));
return ([
'id' => $arr['id'],
'meData' => $data,
'meDataType' => $data_type,
'meEncoding' => $encoding,
'meAlgorithm' => $algorithm,
'meCreator' => channel_url($channel),
'meSignatureValue' => $signature
]);
}
}

View file

@ -2,109 +2,117 @@
namespace Zotlabs\Lib;
class LibBlock
{
class LibBlock {
public static $cache = [];
public static $empty = [];
static $cache = [];
static $empty = [];
// This limits the number of DB queries for fetch_by_entity to once per page load.
// This limits the number of DB queries for fetch_by_entity to once per page load.
static function fetch_from_cache($channel_id,$entity) {
if (! isset(self::$cache[$channel_id])) {
if (! isset(self::$empty[$channel_id])) {
self::$cache[$channel_id] = self::fetch($channel_id);
if (! self::$cache[$channel_id]) {
self::$empty[$channel_id] = true;
}
}
}
if (isset(self::$cache[$channel_id]) && self::$cache[$channel_id] && is_array(self::$cache[$channel_id])) {
foreach (self::$cache[$channel_id] as $entry) {
if (is_array($entry) && strcasecmp($entry['block_entity'],$entity) === 0) {
return $entry;
}
}
}
return false;
}
public static function fetch_from_cache($channel_id, $entity)
{
if (!isset(self::$cache[$channel_id])) {
if (!isset(self::$empty[$channel_id])) {
self::$cache[$channel_id] = self::fetch($channel_id);
if (!self::$cache[$channel_id]) {
self::$empty[$channel_id] = true;
}
}
}
if (isset(self::$cache[$channel_id]) && self::$cache[$channel_id] && is_array(self::$cache[$channel_id])) {
foreach (self::$cache[$channel_id] as $entry) {
if (is_array($entry) && strcasecmp($entry['block_entity'], $entity) === 0) {
return $entry;
}
}
}
return false;
}
static function store($arr) {
public static function store($arr)
{
$arr['block_entity'] = trim($arr['block_entity']);
$arr['block_entity'] = trim($arr['block_entity']);
if (! $arr['block_entity']) {
return false;
}
if (!$arr['block_entity']) {
return false;
}
$arr['block_channel_id'] = ((array_key_exists('block_channel_id',$arr)) ? intval($arr['block_channel_id']) : 0);
$arr['block_type'] = ((array_key_exists('block_type',$arr)) ? intval($arr['block_type']) : BLOCKTYPE_CHANNEL );
$arr['block_comment'] = ((array_key_exists('block_comment',$arr)) ? escape_tags(trim($arr['block_comment'])) : EMPTY_STR);
$arr['block_channel_id'] = ((array_key_exists('block_channel_id', $arr)) ? intval($arr['block_channel_id']) : 0);
$arr['block_type'] = ((array_key_exists('block_type', $arr)) ? intval($arr['block_type']) : BLOCKTYPE_CHANNEL);
$arr['block_comment'] = ((array_key_exists('block_comment', $arr)) ? escape_tags(trim($arr['block_comment'])) : EMPTY_STR);
if (! intval($arr['block_id'])) {
$r = q("select * from block where block_channel_id = %d and block_entity = '%s' and block_type = %d limit 1",
intval($arr['block_channel_id']),
dbesc($arr['block_entity']),
intval($arr['block_type'])
);
if ($r) {
$arr['block_id'] = $r[0]['block_id'];
}
}
if (!intval($arr['block_id'])) {
$r = q(
"select * from block where block_channel_id = %d and block_entity = '%s' and block_type = %d limit 1",
intval($arr['block_channel_id']),
dbesc($arr['block_entity']),
intval($arr['block_type'])
);
if ($r) {
$arr['block_id'] = $r[0]['block_id'];
}
}
if (intval($arr['block_id'])) {
return q("UPDATE block set block_channel_id = %d, block_entity = '%s', block_type = %d, block_comment = '%s' where block_id = %d",
intval($arr['block_channel_id']),
dbesc($arr['block_entity']),
intval($arr['block_type']),
dbesc($arr['block_comment']),
intval($arr['block_id'])
);
}
else {
return create_table_from_array('block',$arr);
}
}
if (intval($arr['block_id'])) {
return q(
"UPDATE block set block_channel_id = %d, block_entity = '%s', block_type = %d, block_comment = '%s' where block_id = %d",
intval($arr['block_channel_id']),
dbesc($arr['block_entity']),
intval($arr['block_type']),
dbesc($arr['block_comment']),
intval($arr['block_id'])
);
} else {
return create_table_from_array('block', $arr);
}
}
static function remove($channel_id,$entity) {
return q("delete from block where block_channel_id = %d and block_entity = '%s'",
intval($channel_id),
dbesc($entity)
);
}
public static function remove($channel_id, $entity)
{
return q(
"delete from block where block_channel_id = %d and block_entity = '%s'",
intval($channel_id),
dbesc($entity)
);
}
static function fetch_by_id($channel_id,$id) {
if (! intval($channel_id)) {
return false;
}
$r = q("select * from block where block_channel_id = %d and block_id = %d ",
intval($channel_id)
);
return (($r) ? array_shift($r) : $r);
}
public static function fetch_by_id($channel_id, $id)
{
if (!intval($channel_id)) {
return false;
}
$r = q(
"select * from block where block_channel_id = %d and block_id = %d ",
intval($channel_id)
);
return (($r) ? array_shift($r) : $r);
}
static function fetch_by_entity($channel_id,$entity) {
if (! intval($channel_id)) {
return false;
}
public static function fetch_by_entity($channel_id, $entity)
{
if (!intval($channel_id)) {
return false;
}
return self::fetch_from_cache($channel_id,$entity);
return self::fetch_from_cache($channel_id, $entity);
}
}
public static function fetch($channel_id, $type = false)
{
if (!intval($channel_id)) {
return [];
}
static function fetch($channel_id,$type = false) {
if (! intval($channel_id)) {
return [];
}
$sql_extra = (($type === false) ? EMPTY_STR : " and block_type = " . intval($type));
$r = q("select * from block where block_channel_id = %d $sql_extra",
intval($channel_id)
);
return $r;
}
$sql_extra = (($type === false) ? EMPTY_STR : " and block_type = " . intval($type));
$r = q(
"select * from block where block_channel_id = %d $sql_extra",
intval($channel_id)
);
return $r;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Webfinger;
use Zotlabs\Lib\Zotfinger;
@ -9,332 +10,359 @@ use Zotlabs\Lib\Zotfinger;
require_once('include/permissions.php');
class Libzotdir {
class Libzotdir
{
/**
* Directories may come and go over time. We will need to check that our
* directory server is still valid occasionally, and reset to something that
* is if our directory has gone offline for any reason
*/
/**
* Directories may come and go over time. We will need to check that our
* directory server is still valid occasionally, and reset to something that
* is if our directory has gone offline for any reason
*/
static function check_upstream_directory() {
public static function check_upstream_directory()
{
$directory = get_config('system', 'directory_server');
$directory = get_config('system', 'directory_server');
// it's possible there is no directory server configured and the local hub is being used.
// If so, default to preserving the absence of a specific server setting.
// it's possible there is no directory server configured and the local hub is being used.
// If so, default to preserving the absence of a specific server setting.
$isadir = true;
$isadir = true;
if ($directory) {
$j = Zotfinger::exec($directory);
if (array_path_exists('data/directory_mode',$j)) {
if ($j['data']['directory_mode'] === 'normal') {
$isadir = false;
}
}
if ($directory) {
$j = Zotfinger::exec($directory);
if (array_path_exists('data/directory_mode', $j)) {
if ($j['data']['directory_mode'] === 'normal') {
$isadir = false;
}
}
}
if (!$isadir) {
set_config('system', 'directory_server', '');
}
}
public static function get_directory_setting($observer, $setting)
{
if ($observer) {
$ret = get_xconfig($observer, 'directory', $setting);
} else {
$ret = ((array_key_exists($setting, $_SESSION)) ? intval($_SESSION[$setting]) : false);
}
if ($ret === false) {
$ret = get_config('directory', $setting);
if ($ret === false) {
$ret = (in_array($setting, ['globaldir', 'safemode', 'activedir']) ? 1 : 0);
}
}
if ($setting === 'globaldir' && intval(get_config('system', 'localdir_hide'))) {
$ret = 1;
}
return $ret;
}
/**
* @brief Called by the directory_sort widget.
*/
public static function dir_sort_links()
{
$safe_mode = 1;
$observer = get_observer_hash();
$safe_mode = self::get_directory_setting($observer, 'safemode');
$globaldir = self::get_directory_setting($observer, 'globaldir');
$pubforums = self::get_directory_setting($observer, 'chantype');
$activedir = self::get_directory_setting($observer, 'activedir');
$hide_local = intval(get_config('system', 'localdir_hide'));
if ($hide_local) {
$globaldir = 1;
}
// Build urls without order and pubforums so it's easy to tack on the changed value
// Probably there's an easier way to do this
$directory_sort_order = get_config('system', 'directory_sort_order');
if (!$directory_sort_order) {
$directory_sort_order = 'date';
}
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
$url = 'directory?f=';
$tmp = array_merge($_GET, $_POST);
unset($tmp['suggest']);
unset($tmp['pubforums']);
unset($tmp['type']);
unset($tmp['global']);
unset($tmp['safe']);
unset($tmp['active']);
unset($tmp['req']);
unset($tmp['f']);
$q = http_build_query($tmp);
$forumsurl = $url . (($q) ? '&' . $q : '') . $suggest;
$o = replace_macros(get_markup_template('dir_sort_links.tpl'), [
'$header' => t('Directory Options'),
'$forumsurl' => $forumsurl,
'$safemode' => array('safemode', t('Safe Mode'), $safe_mode, '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''),
'$pubforums' => array('pubforums', t('Groups Only'), (($pubforums == 1) ? true : false), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''),
// '$collections' => array('collections', t('Collections Only'),(($pubforums == 2) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 2 : 0)\''),
'$hide_local' => $hide_local,
'$globaldir' => array('globaldir', t('This Website Only'), 1 - intval($globaldir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''),
'$activedir' => array('activedir', t('Recently Updated'), intval($activedir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''),
]);
return $o;
}
/**
* @brief
*
* Given an update record, probe the channel, grab a zot-info packet and refresh/sync the data.
*
* Ignore updating records marked as deleted.
*
* If successful, sets ud_last in the DB to the current datetime for this
* reddress/webbie.
*
* @param array $ud Entry from update table
*/
public static function update_directory_entry($ud)
{
logger('update_directory_entry: ' . print_r($ud, true), LOGGER_DATA);
if ($ud['ud_addr'] && (!($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
$success = false;
$href = Webfinger::zot_url(punify($ud['ud_addr']));
if ($href) {
$zf = Zotfinger::exec($href);
}
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
} else {
q(
"update updates set ud_last = '%s' where ud_addr = '%s'",
dbesc(datetime_convert()),
dbesc($ud['ud_addr'])
);
}
}
}
/**
* @brief Push local channel updates to a local directory server.
*
* This is called from Zotlabs/Daemon/Directory.php if a profile is to be pushed to the
* directory and the local hub in this case is any kind of directory server.
*
* @param int $uid
* @param bool $force
*/
public static function local_dir_update($uid, $force)
{
logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG);
$p = q(
"select channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
intval($uid)
);
$profile = [];
$profile['encoding'] = 'zot';
if ($p) {
$hash = $p[0]['channel_hash'];
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if ($age = age($p[0]['dob'], $p[0]['channel_timezone'], '')) {
$profile['age'] = $age;
}
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if ($p[0]['keywords']) {
$tags = [];
$k = explode(' ', $p[0]['keywords']);
if ($k) {
foreach ($k as $kk) {
if (trim($kk)) {
$tags[] = trim($kk);
}
}
}
if ($tags) {
$profile['keywords'] = $tags;
}
}
$hidden = (1 - intval($p[0]['publish']));
// logger('hidden: ' . $hidden);
$r = q(
"select xchan_hidden from xchan where xchan_hash = '%s' limit 1",
dbesc($p[0]['channel_hash'])
);
if (intval($r[0]['xchan_hidden']) != $hidden) {
$r = q(
"update xchan set xchan_hidden = %d where xchan_hash = '%s'",
intval($hidden),
dbesc($p[0]['channel_hash'])
);
}
$arr = ['channel_id' => $uid, 'hash' => $hash, 'profile' => $profile];
call_hooks('local_dir_update', $arr);
$address = channel_reddress($p[0]);
if (perm_is_allowed($uid, '', 'view_profile')) {
self::import_directory_profile($hash, $arr['profile'], $address, 0);
} else {
// they may have made it private
$r = q(
"delete from xprof where xprof_hash = '%s'",
dbesc($hash)
);
$r = q(
"delete from xtag where xtag_hash = '%s'",
dbesc($hash)
);
}
}
$ud_hash = random_string() . '@' . App::get_hostname();
self::update_modtime($hash, $ud_hash, channel_reddress($p[0]), (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
}
/**
* @brief Imports a directory profile.
*
* @param string $hash
* @param array $profile
* @param string $addr
* @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED
* @param number $suppress_update (optional) default 0
* @return bool $updated if something changed
*/
public static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0)
{
logger('import_directory_profile', LOGGER_DEBUG);
if (!$hash) {
return false;
}
$maxlen = get_max_import_size();
if ($maxlen && mb_strlen($profile['about']) > $maxlen) {
$profile['about'] = mb_substr($profile['about'], 0, $maxlen, 'UTF-8');
}
$arr = [];
$arr['xprof_hash'] = $hash;
if (isset($profile['birthday'])) {
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00')
? $profile['birthday']
: datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
}
$arr['xprof_age'] = (isset($profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_pronouns'] = ((isset($profile['pronouns']) && $profile['pronouns']) ? htmlspecialchars($profile['pronouns'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT, 'UTF-8', false) : '');
if (! $isadir)
set_config('system', 'directory_server', '');
}
$clean = [];
if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) {
self::import_directory_keywords($hash, $profile['keywords']);
foreach ($profile['keywords'] as $kw) {
$kw = trim(htmlspecialchars($kw, ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
}
}
$arr['xprof_keywords'] = implode(' ', $clean);
// Self censored, make it so
// These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult".
static function get_directory_setting($observer, $setting) {
if (in_arrayi('nsfw', $clean) || in_arrayi('adult', $clean)) {
q(
"update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'",
dbesc($hash)
);
}
$r = q(
"select * from xprof where xprof_hash = '%s' limit 1",
dbesc($hash)
);
if ($observer)
$ret = get_xconfig($observer, 'directory', $setting);
else
$ret = ((array_key_exists($setting,$_SESSION)) ? intval($_SESSION[$setting]) : false);
if ($arr['xprof_age'] > 150) {
$arr['xprof_age'] = 150;
}
if ($arr['xprof_age'] < 0) {
$arr['xprof_age'] = 0;
}
if($ret === false) {
$ret = get_config('directory', $setting);
if($ret === false) {
$ret = (in_array($setting,[ 'globaldir','safemode', 'activedir' ]) ? 1 : 0);
}
}
if($setting === 'globaldir' && intval(get_config('system','localdir_hide')))
$ret = 1;
return $ret;
}
/**
* @brief Called by the directory_sort widget.
*/
static function dir_sort_links() {
$safe_mode = 1;
$observer = get_observer_hash();
$safe_mode = self::get_directory_setting($observer, 'safemode');
$globaldir = self::get_directory_setting($observer, 'globaldir');
$pubforums = self::get_directory_setting($observer, 'chantype');
$activedir = self::get_directory_setting($observer, 'activedir');
$hide_local = intval(get_config('system','localdir_hide'));
if ($hide_local) {
$globaldir = 1;
}
// Build urls without order and pubforums so it's easy to tack on the changed value
// Probably there's an easier way to do this
$directory_sort_order = get_config('system','directory_sort_order');
if (! $directory_sort_order) {
$directory_sort_order = 'date';
}
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
$url = 'directory?f=';
$tmp = array_merge($_GET,$_POST);
unset($tmp['suggest']);
unset($tmp['pubforums']);
unset($tmp['type']);
unset($tmp['global']);
unset($tmp['safe']);
unset($tmp['active']);
unset($tmp['req']);
unset($tmp['f']);
$q = http_build_query($tmp);
$forumsurl = $url . (($q) ? '&' . $q : '') . $suggest;
$o = replace_macros(get_markup_template('dir_sort_links.tpl'), [
'$header' => t('Directory Options'),
'$forumsurl' => $forumsurl,
'$safemode' => array('safemode', t('Safe Mode'),$safe_mode,'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''),
'$pubforums' => array('pubforums', t('Groups Only'),(($pubforums == 1) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''),
// '$collections' => array('collections', t('Collections Only'),(($pubforums == 2) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 2 : 0)\''),
'$hide_local' => $hide_local,
'$globaldir' => array('globaldir', t('This Website Only'), 1-intval($globaldir),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''),
'$activedir' => array('activedir', t('Recently Updated'), intval($activedir),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''),
]);
return $o;
}
/**
* @brief
*
* Given an update record, probe the channel, grab a zot-info packet and refresh/sync the data.
*
* Ignore updating records marked as deleted.
*
* If successful, sets ud_last in the DB to the current datetime for this
* reddress/webbie.
*
* @param array $ud Entry from update table
*/
static function update_directory_entry($ud) {
logger('update_directory_entry: ' . print_r($ud,true), LOGGER_DATA);
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
$success = false;
$href = Webfinger::zot_url(punify($ud['ud_addr']));
if($href) {
$zf = Zotfinger::exec($href);
}
if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
}
else {
q("update updates set ud_last = '%s' where ud_addr = '%s'",
dbesc(datetime_convert()),
dbesc($ud['ud_addr'])
);
}
}
}
/**
* @brief Push local channel updates to a local directory server.
*
* This is called from Zotlabs/Daemon/Directory.php if a profile is to be pushed to the
* directory and the local hub in this case is any kind of directory server.
*
* @param int $uid
* @param boolean $force
*/
static function local_dir_update($uid, $force) {
logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG);
$p = q("select channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
intval($uid)
);
$profile = [];
$profile['encoding'] = 'zot';
if ($p) {
$hash = $p[0]['channel_hash'];
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
$profile['age'] = $age;
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if ($p[0]['keywords']) {
$tags = [];
$k = explode(' ', $p[0]['keywords']);
if ($k)
foreach ($k as $kk)
if (trim($kk))
$tags[] = trim($kk);
if ($tags)
$profile['keywords'] = $tags;
}
$hidden = (1 - intval($p[0]['publish']));
// logger('hidden: ' . $hidden);
$r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1",
dbesc($p[0]['channel_hash'])
);
if(intval($r[0]['xchan_hidden']) != $hidden) {
$r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
intval($hidden),
dbesc($p[0]['channel_hash'])
);
}
$arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ];
call_hooks('local_dir_update', $arr);
$address = channel_reddress($p[0]);
if (perm_is_allowed($uid, '', 'view_profile')) {
self::import_directory_profile($hash, $arr['profile'], $address, 0);
}
else {
// they may have made it private
$r = q("delete from xprof where xprof_hash = '%s'",
dbesc($hash)
);
$r = q("delete from xtag where xtag_hash = '%s'",
dbesc($hash)
);
}
}
$ud_hash = random_string() . '@' . \App::get_hostname();
self::update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
}
/**
* @brief Imports a directory profile.
*
* @param string $hash
* @param array $profile
* @param string $addr
* @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED
* @param number $suppress_update (optional) default 0
* @return boolean $updated if something changed
*/
static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) {
logger('import_directory_profile', LOGGER_DEBUG);
if (! $hash)
return false;
$maxlen = get_max_import_size();
if($maxlen && mb_strlen($profile['about']) > $maxlen) {
$profile['about'] = mb_substr($profile['about'],0,$maxlen,'UTF-8');
}
$arr = [];
$arr['xprof_hash'] = $hash;
$arr['xprof_dob'] = ((isset($profile['birthday']) && $profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year
$arr['xprof_age'] = (isset($profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_pronouns'] = ((isset($profile['pronouns']) && $profile['pronouns']) ? htmlspecialchars($profile['pronouns'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
$clean = [];
if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) {
self::import_directory_keywords($hash,$profile['keywords']);
foreach ($profile['keywords'] as $kw) {
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
}
}
$arr['xprof_keywords'] = implode(' ',$clean);
// Self censored, make it so
// These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult".
if(in_arrayi('nsfw',$clean) || in_arrayi('adult',$clean)) {
q("update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'",
dbesc($hash)
);
}
$r = q("select * from xprof where xprof_hash = '%s' limit 1",
dbesc($hash)
);
if ($arr['xprof_age'] > 150)
$arr['xprof_age'] = 150;
if ($arr['xprof_age'] < 0)
$arr['xprof_age'] = 0;
if ($r) {
$update = false;
foreach ($r[0] as $k => $v) {
if ((array_key_exists($k,$arr)) && ($arr[$k] != $v)) {
logger('import_directory_profile: update ' . $k . ' => ' . $arr[$k]);
$update = true;
break;
}
}
if ($update) {
q("update xprof set
if ($r) {
$update = false;
foreach ($r[0] as $k => $v) {
if ((array_key_exists($k, $arr)) && ($arr[$k] != $v)) {
logger('import_directory_profile: update ' . $k . ' => ' . $arr[$k]);
$update = true;
break;
}
}
if ($update) {
q(
"update xprof set
xprof_desc = '%s',
xprof_dob = '%s',
xprof_age = %d,
@ -351,156 +379,161 @@ class Libzotdir {
xprof_keywords = '%s',
xprof_pronouns = '%s'
where xprof_hash = '%s'",
dbesc($arr['xprof_desc']),
dbesc($arr['xprof_dob']),
intval($arr['xprof_age']),
dbesc($arr['xprof_gender']),
dbesc($arr['xprof_marital']),
dbesc($arr['xprof_sexual']),
dbesc($arr['xprof_locale']),
dbesc($arr['xprof_region']),
dbesc($arr['xprof_postcode']),
dbesc($arr['xprof_country']),
dbesc($arr['xprof_about']),
dbesc($arr['xprof_homepage']),
dbesc($arr['xprof_hometown']),
dbesc($arr['xprof_keywords']),
dbesc($arr['xprof_pronouns']),
dbesc($arr['xprof_hash'])
);
}
} else {
$update = true;
logger('New profile');
q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords, xprof_pronouns) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
dbesc($arr['xprof_hash']),
dbesc($arr['xprof_desc']),
dbesc($arr['xprof_dob']),
intval($arr['xprof_age']),
dbesc($arr['xprof_gender']),
dbesc($arr['xprof_marital']),
dbesc($arr['xprof_sexual']),
dbesc($arr['xprof_locale']),
dbesc($arr['xprof_region']),
dbesc($arr['xprof_postcode']),
dbesc($arr['xprof_country']),
dbesc($arr['xprof_about']),
dbesc($arr['xprof_homepage']),
dbesc($arr['xprof_hometown']),
dbesc($arr['xprof_keywords']),
dbesc($arr['xprof_pronouns'])
);
}
dbesc($arr['xprof_desc']),
dbesc($arr['xprof_dob']),
intval($arr['xprof_age']),
dbesc($arr['xprof_gender']),
dbesc($arr['xprof_marital']),
dbesc($arr['xprof_sexual']),
dbesc($arr['xprof_locale']),
dbesc($arr['xprof_region']),
dbesc($arr['xprof_postcode']),
dbesc($arr['xprof_country']),
dbesc($arr['xprof_about']),
dbesc($arr['xprof_homepage']),
dbesc($arr['xprof_hometown']),
dbesc($arr['xprof_keywords']),
dbesc($arr['xprof_pronouns']),
dbesc($arr['xprof_hash'])
);
}
} else {
$update = true;
logger('New profile');
q(
"insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords, xprof_pronouns) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
dbesc($arr['xprof_hash']),
dbesc($arr['xprof_desc']),
dbesc($arr['xprof_dob']),
intval($arr['xprof_age']),
dbesc($arr['xprof_gender']),
dbesc($arr['xprof_marital']),
dbesc($arr['xprof_sexual']),
dbesc($arr['xprof_locale']),
dbesc($arr['xprof_region']),
dbesc($arr['xprof_postcode']),
dbesc($arr['xprof_country']),
dbesc($arr['xprof_about']),
dbesc($arr['xprof_homepage']),
dbesc($arr['xprof_hometown']),
dbesc($arr['xprof_keywords']),
dbesc($arr['xprof_pronouns'])
);
}
$d = [
'xprof' => $arr,
'profile' => $profile,
'update' => $update
];
$d = [
'xprof' => $arr,
'profile' => $profile,
'update' => $update
];
/**
* @hooks import_directory_profile
* Called when processing delivery of a profile structure from an external source (usually for directory storage).
* * \e array \b xprof
* * \e array \b profile
* * \e boolean \b update
*/
/**
* @hooks import_directory_profile
* Called when processing delivery of a profile structure from an external source (usually for directory storage).
* * \e array \b xprof
* * \e array \b profile
* * \e boolean \b update
*/
call_hooks('import_directory_profile', $d);
call_hooks('import_directory_profile', $d);
if (($d['update']) && (! $suppress_update)) {
self::update_modtime($arr['xprof_hash'], new_uuid(), $addr, $ud_flags);
}
if (($d['update']) && (!$suppress_update)) {
self::update_modtime($arr['xprof_hash'], new_uuid(), $addr, $ud_flags);
}
q("update xchan set xchan_updated = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($arr['xprof_hash'])
);
q(
"update xchan set xchan_updated = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($arr['xprof_hash'])
);
return $d['update'];
}
return $d['update'];
}
/**
* @brief
*
* @param string $hash An xtag_hash
* @param array $keywords
*/
/**
* @brief
*
* @param string $hash An xtag_hash
* @param array $keywords
*/
static function import_directory_keywords($hash, $keywords) {
public static function import_directory_keywords($hash, $keywords)
{
$existing = [];
$r = q("select * from xtag where xtag_hash = '%s' and xtag_flags = 0",
dbesc($hash)
);
$existing = [];
$r = q(
"select * from xtag where xtag_hash = '%s' and xtag_flags = 0",
dbesc($hash)
);
if($r) {
foreach($r as $rr)
$existing[] = $rr['xtag_term'];
}
if ($r) {
foreach ($r as $rr) {
$existing[] = $rr['xtag_term'];
}
}
$clean = [];
foreach($keywords as $kw) {
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
}
$clean = [];
foreach ($keywords as $kw) {
$kw = trim(htmlspecialchars($kw, ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
}
foreach($existing as $x) {
if(! in_array($x, $clean))
$r = q("delete from xtag where xtag_hash = '%s' and xtag_term = '%s' and xtag_flags = 0",
dbesc($hash),
dbesc($x)
);
}
foreach($clean as $x) {
if(! in_array($x, $existing)) {
$r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )",
dbesc($hash),
dbesc($x)
);
}
}
}
/**
* @brief
*
* @param string $hash
* @param string $guid
* @param string $addr
* @param int $flags (optional) default 0
*/
static function update_modtime($hash, $guid, $addr, $flags = 0) {
$dirmode = intval(get_config('system', 'directory_mode'));
if($dirmode == DIRECTORY_MODE_NORMAL)
return;
if($flags) {
q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
dbesc($hash),
dbesc($guid),
dbesc(datetime_convert()),
intval($flags),
dbesc($addr)
);
}
else {
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and (ud_flags & %d) = 0 ",
intval(UPDATE_FLAGS_UPDATED),
dbesc($addr),
intval(UPDATE_FLAGS_UPDATED)
);
}
}
foreach ($existing as $x) {
if (!in_array($x, $clean)) {
$r = q(
"delete from xtag where xtag_hash = '%s' and xtag_term = '%s' and xtag_flags = 0",
dbesc($hash),
dbesc($x)
);
}
}
foreach ($clean as $x) {
if (!in_array($x, $existing)) {
$r = q(
"insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )",
dbesc($hash),
dbesc($x)
);
}
}
}
/**
* @brief
*
* @param string $hash
* @param string $guid
* @param string $addr
* @param int $flags (optional) default 0
*/
public static function update_modtime($hash, $guid, $addr, $flags = 0)
{
$dirmode = intval(get_config('system', 'directory_mode'));
if ($dirmode == DIRECTORY_MODE_NORMAL) {
return;
}
if ($flags) {
q(
"insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
dbesc($hash),
dbesc($guid),
dbesc(datetime_convert()),
intval($flags),
dbesc($addr)
);
} else {
q(
"update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and (ud_flags & %d) = 0 ",
intval(UPDATE_FLAGS_UPDATED),
dbesc($addr),
intval(UPDATE_FLAGS_UPDATED)
);
}
}
}

View file

@ -1,4 +1,5 @@
<?php
namespace Zotlabs\Lib;
/**
@ -6,7 +7,6 @@ namespace Zotlabs\Lib;
*/
use Michelf\MarkdownExtra;
use League\HTMLToMarkdown\HtmlConverter;
use League\HTMLToMarkdown\Environment;
use League\HTMLToMarkdown\Converter\ConverterInterface;
@ -18,308 +18,329 @@ require_once("include/html2bbcode.php");
require_once("include/bbcode.php");
class Markdown {
/**
* @brief Convert Markdown to bbcode.
*
* We don't want to support a bbcode specific markdown interpreter
* and the markdown library we have is pretty good, but provides HTML output.
* So we'll use that to convert to HTML, then convert the HTML back to bbcode,
* and then clean up a few Diaspora specific constructs.
*
* @param string $s The message as Markdown
* @param boolean $use_zrl default false
* @param array $options default empty
* @return string The message converted to bbcode
*/
static public function to_bbcode($s, $use_zrl = false, $options = []) {
if(is_array($s)) {
btlogger('markdown_to_bb called with array. ' . print_r($s, true), LOGGER_NORMAL, LOG_WARNING);
return '';
}
$s = str_replace("&#xD;","\r",$s);
$s = str_replace("&#xD;\n&gt;","",$s);
$s = html_entity_decode($s,ENT_COMPAT,'UTF-8');
// if empty link text replace with the url
$s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s);
$x = [
'text' => $s,
'zrl' => $use_zrl,
'options' => $options
];
/**
* @hooks markdown_to_bb_init
* * \e string \b text - The message as Markdown and what will get returned
* * \e boolean \b zrl
* * \e array \b options
*/
call_hooks('markdown_to_bb_init', $x);
$s = $x['text'];
// Escaping the hash tags
$s = preg_replace('/\#([^\s\#])/','&#35;$1',$s);
$s = MarkdownExtra::defaultTransform($s);
if($options && $options['preserve_lf']) {
$s = str_replace(["\r","\n"],["",'<br>'],$s);
}
else {
$s = str_replace("\r","",$s);
}
$s = str_replace('&#35;','#',$s);
$s = html2bbcode($s);
// Convert everything that looks like a link to a link
if($use_zrl) {
if (strpos($s,'[/img]') !== false) {
$s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img'], $s);
$s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img_x' ], $s);
}
$s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_link'] ,$s);
}
else {
$s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s);
}
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s);
/**
* @hooks markdown_to_bb
* * \e string - The already converted message as bbcode
*/
call_hooks('markdown_to_bb', $s);
return $s;
}
static function use_zrl_cb_link($match) {
$res = '';
$is_zid = is_matrix_url(trim($match[0]));
if($is_zid)
$res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]';
else
$res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]';
return $res;
}
static function use_zrl_cb_img($match) {
$res = '';
$is_zid = is_matrix_url(trim($match[1]));
if($is_zid)
$res = '[zmg]' . $match[1] . '[/zmg]';
else
$res = $match[0];
return $res;
}
class Markdown
{
/**
* @brief Convert Markdown to bbcode.
*
* We don't want to support a bbcode specific markdown interpreter
* and the markdown library we have is pretty good, but provides HTML output.
* So we'll use that to convert to HTML, then convert the HTML back to bbcode,
* and then clean up a few Diaspora specific constructs.
*
* @param string $s The message as Markdown
* @param bool $use_zrl default false
* @param array $options default empty
* @return string The message converted to bbcode
*/
public static function to_bbcode($s, $use_zrl = false, $options = [])
{
if (is_array($s)) {
btlogger('markdown_to_bb called with array. ' . print_r($s, true), LOGGER_NORMAL, LOG_WARNING);
return '';
}
$s = str_replace("&#xD;", "\r", $s);
$s = str_replace("&#xD;\n&gt;", "", $s);
$s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
// if empty link text replace with the url
$s = preg_replace("/\[\]\((.*?)\)/ism", '[$1]($1)', $s);
$x = [
'text' => $s,
'zrl' => $use_zrl,
'options' => $options
];
/**
* @hooks markdown_to_bb_init
* * \e string \b text - The message as Markdown and what will get returned
* * \e boolean \b zrl
* * \e array \b options
*/
call_hooks('markdown_to_bb_init', $x);
$s = $x['text'];
// Escaping the hash tags
$s = preg_replace('/\#([^\s\#])/', '&#35;$1', $s);
$s = MarkdownExtra::defaultTransform($s);
if ($options && $options['preserve_lf']) {
$s = str_replace(["\r", "\n"], ["", '<br>'], $s);
} else {
$s = str_replace("\r", "", $s);
}
$s = str_replace('&#35;', '#', $s);
$s = html2bbcode($s);
// Convert everything that looks like a link to a link
if ($use_zrl) {
if (strpos($s, '[/img]') !== false) {
$s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img'], $s);
$s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img_x'], $s);
}
$s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_link'], $s);
} else {
$s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]', $s);
}
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism", "[code]$2[/code]", $s);
/**
* @hooks markdown_to_bb
* * \e string - The already converted message as bbcode
*/
call_hooks('markdown_to_bb', $s);
return $s;
}
public static function use_zrl_cb_link($match)
{
$res = '';
$is_zid = is_matrix_url(trim($match[0]));
if ($is_zid) {
$res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]';
} else {
$res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]';
}
return $res;
}
public static function use_zrl_cb_img($match)
{
$res = '';
$is_zid = is_matrix_url(trim($match[1]));
if ($is_zid) {
$res = '[zmg]' . $match[1] . '[/zmg]';
} else {
$res = $match[0];
}
return $res;
}
public static function use_zrl_cb_img_x($match)
{
$res = '';
$is_zid = is_matrix_url(trim($match[3]));
if ($is_zid) {
$res = '[zmg=' . $match[1] . 'x' . $match[2] . ']' . $match[3] . '[/zmg]';
} else {
$res = $match[0];
}
return $res;
}
/**
* @brief
*
* @param array $match
* @return string
*/
public static function from_bbcode_share($match)
{
$matches = [];
$attributes = $match[1];
$author = "";
preg_match("/author='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$author = urldecode($matches[1]);
}
$link = "";
preg_match("/link='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$link = $matches[1];
}
$avatar = "";
preg_match("/avatar='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$avatar = $matches[1];
}
$profile = "";
preg_match("/profile='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$profile = $matches[1];
}
$posted = "";
preg_match("/posted='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$posted = $matches[1];
}
static function use_zrl_cb_img_x($match) {
$res = '';
$is_zid = is_matrix_url(trim($match[3]));
// message_id is never used, do we still need it?
$message_id = "";
preg_match("/message_id='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$message_id = $matches[1];
}
if($is_zid)
$res = '[zmg=' . $match[1] . 'x' . $match[2] . ']' . $match[3] . '[/zmg]';
else
$res = $match[0];
if (!$message_id) {
preg_match("/guid='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$message_id = $matches[1];
}
}
return $res;
}
/**
* @brief
*
* @param array $match
* @return string
*/
$reldate = datetime_convert('UTC', date_default_timezone_get(), $posted, 'r');
static public function from_bbcode_share($match) {
$headline = '';
$matches = [];
$attributes = $match[1];
if ($avatar != "") {
$headline .= '[url=' . zid($profile) . '][img]' . $avatar . '[/img][/url]';
}
$author = "";
preg_match("/author='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$author = urldecode($matches[1]);
// Bob Smith wrote the following post 2 hours ago
$link = "";
preg_match("/link='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$link = $matches[1];
$fmt = sprintf(
t('%1$s wrote the following %2$s %3$s'),
'[url=' . zid($profile) . ']' . $author . '[/url]',
'[url=' . zid($link) . ']' . t('post') . '[/url]',
$reldate
);
$headline .= $fmt . "\n\n";
$text = $headline . trim($match[2]);
return $text;
}
/**
* @brief Convert bbcode to Markdown.
*
* @param string $Text The message as bbcode
* @param array $options default empty
* @return string The message converted to Markdown
*/
public static function from_bbcode($Text, $options = [])
{
/*
* Transform #tags, strip off the [url] and replace spaces with underscore
*/
$Text = preg_replace_callback(
'/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i',
create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'),
$Text
);
$Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text);
// Converting images with size parameters to simple images. Markdown doesn't know it.
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text);
$Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'from_bbcode_share'], $Text);
$x = ['bbcode' => $Text, 'options' => $options];
/**
* @hooks bb_to_markdown_bb
* * \e string \b bbcode - The message as bbcode and what will get returned
* * \e array \b options
*/
call_hooks('bb_to_markdown_bb', $x);
$Text = $x['bbcode'];
// Convert it to HTML - don't try oembed
$Text = bbcode($Text, ['tryoembed' => false]);
$avatar = "";
preg_match("/avatar='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$avatar = $matches[1];
// Now convert HTML to Markdown
$Text = self::from_html($Text);
$profile = "";
preg_match("/profile='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$profile = $matches[1];
//html2markdown adds backslashes infront of hashes after a new line. remove them
$Text = str_replace("\n\#", "\n#", $Text);
$posted = "";
preg_match("/posted='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$posted = $matches[1];
// message_id is never used, do we still need it?
$message_id = "";
preg_match("/message_id='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$message_id = $matches[1];
// If the text going into bbcode() has a plain URL in it, i.e.
// with no [url] tags around it, it will come out of parseString()
// looking like: <http://url.com>, which gets removed by strip_tags().
// So take off the angle brackets of any such URL
$Text = preg_replace("/<http(.*?)>/is", "http$1", $Text);
if(! $message_id) {
preg_match("/guid='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$message_id = $matches[1];
}
// Remove empty zrl links
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
$Text = trim($Text);
$reldate = datetime_convert('UTC', date_default_timezone_get(), $posted, 'r');
/**
* @hooks bb_to_markdown
* * \e string - The already converted message as bbcode and what will get returned
*/
call_hooks('bb_to_markdown', $Text);
$headline = '';
return $Text;
}
if ($avatar != "")
$headline .= '[url=' . zid($profile) . '][img]' . $avatar . '[/img][/url]';
// Bob Smith wrote the following post 2 hours ago
/**
* @brief Convert a HTML text into Markdown.
*
* This function uses the library league/html-to-markdown for this task.
*
* If the HTML text can not get parsed it will return an empty string.
*
* @param string $html The HTML code to convert
* @return string Markdown representation of the given HTML text, empty on error
*/
$fmt = sprintf( t('%1$s wrote the following %2$s %3$s'),
'[url=' . zid($profile) . ']' . $author . '[/url]',
'[url=' . zid($link) . ']' . t('post') . '[/url]',
$reldate
);
public static function from_html($html, $options = [])
{
$markdown = '';
$headline .= $fmt . "\n\n";
if (!$options) {
$options = [
'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2
'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style
'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style
'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script'
'hard_break' => false, // Set to true to turn <br> into `\n` instead of ` \n`
'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+'
];
}
$text = $headline . trim($match[2]);
$environment = Environment::createDefaultEnvironment($options);
$environment->addConverter(new TableConverter());
$converter = new HtmlConverter($environment);
try {
$markdown = $converter->convert($html);
} catch (InvalidArgumentException $e) {
logger("Invalid HTML. HTMLToMarkdown library threw an exception.");
}
return $text;
}
/**
* @brief Convert bbcode to Markdown.
*
* @param string $Text The message as bbcode
* @param array $options default empty
* @return string The message converted to Markdown
*/
static public function from_bbcode($Text, $options = []) {
/*
* Transform #tags, strip off the [url] and replace spaces with underscore
*/
$Text = preg_replace_callback('/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i',
create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text);
$Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text);
// Converting images with size parameters to simple images. Markdown doesn't know it.
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text);
$Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'from_bbcode_share'], $Text);
$x = [ 'bbcode' => $Text, 'options' => $options ];
/**
* @hooks bb_to_markdown_bb
* * \e string \b bbcode - The message as bbcode and what will get returned
* * \e array \b options
*/
call_hooks('bb_to_markdown_bb', $x);
$Text = $x['bbcode'];
// Convert it to HTML - don't try oembed
$Text = bbcode($Text, [ 'tryoembed' => false ]);
// Now convert HTML to Markdown
$Text = self::from_html($Text);
//html2markdown adds backslashes infront of hashes after a new line. remove them
$Text = str_replace("\n\#", "\n#", $Text);
// If the text going into bbcode() has a plain URL in it, i.e.
// with no [url] tags around it, it will come out of parseString()
// looking like: <http://url.com>, which gets removed by strip_tags().
// So take off the angle brackets of any such URL
$Text = preg_replace("/<http(.*?)>/is", "http$1", $Text);
// Remove empty zrl links
$Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text);
$Text = trim($Text);
/**
* @hooks bb_to_markdown
* * \e string - The already converted message as bbcode and what will get returned
*/
call_hooks('bb_to_markdown', $Text);
return $Text;
}
/**
* @brief Convert a HTML text into Markdown.
*
* This function uses the library league/html-to-markdown for this task.
*
* If the HTML text can not get parsed it will return an empty string.
*
* @param string $html The HTML code to convert
* @return string Markdown representation of the given HTML text, empty on error
*/
static public function from_html($html,$options = []) {
$markdown = '';
if(! $options) {
$options = [
'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2
'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style
'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style
'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script'
'hard_break' => false, // Set to true to turn <br> into `\n` instead of ` \n`
'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+'
];
}
$environment = Environment::createDefaultEnvironment($options);
$environment->addConverter(new TableConverter());
$converter = new HtmlConverter($environment);
try {
$markdown = $converter->convert($html);
} catch (InvalidArgumentException $e) {
logger("Invalid HTML. HTMLToMarkdown library threw an exception.");
}
return $markdown;
}
return $markdown;
}
}
// Tables are not an official part of the markdown specification.
@ -330,64 +351,64 @@ class Markdown {
class TableConverter implements ConverterInterface
{
/**
* @param ElementInterface $element
*
* @return string
*/
public function convert(ElementInterface $element)
{
switch ($element->getTagName()) {
case 'tr':
$line = [];
$i = 1;
foreach ($element->getChildren() as $td) {
$i++;
$v = $td->getValue();
$v = trim($v);
if ($i % 2 === 0 || $v !== '') {
$line[] = $v;
}
}
return '| ' . implode(' | ', $line) . " |\n";
case 'td':
case 'th':
return trim($element->getValue());
case 'tbody':
return trim($element->getValue());
case 'thead':
$headerLine = reset($element->getChildren())->getValue();
$headers = explode(' | ', trim(trim($headerLine, "\n"), '|'));
$hr = [];
foreach ($headers as $td) {
$length = strlen(trim($td)) + 2;
$hr[] = str_repeat('-', $length > 3 ? $length : 3);
}
$hr = '|' . implode('|', $hr) . '|';
return $headerLine . $hr . "\n";
case 'table':
$inner = $element->getValue();
if (strpos($inner, '-----') === false) {
$inner = explode("\n", $inner);
$single = explode(' | ', trim($inner[0], '|'));
$hr = [];
foreach ($single as $td) {
$length = strlen(trim($td)) + 2;
$hr[] = str_repeat('-', $length > 3 ? $length : 3);
}
$hr = '|' . implode('|', $hr) . '|';
array_splice($inner, 1, 0, $hr);
$inner = implode("\n", $inner);
}
return trim($inner) . "\n\n";
}
return $element->getValue();
}
/**
* @return string[]
*/
public function getSupportedTags()
{
return array('table', 'tr', 'thead', 'td', 'tbody');
}
/**
* @param ElementInterface $element
*
* @return string
*/
public function convert(ElementInterface $element)
{
switch ($element->getTagName()) {
case 'tr':
$line = [];
$i = 1;
foreach ($element->getChildren() as $td) {
$i++;
$v = $td->getValue();
$v = trim($v);
if ($i % 2 === 0 || $v !== '') {
$line[] = $v;
}
}
return '| ' . implode(' | ', $line) . " |\n";
case 'td':
case 'th':
return trim($element->getValue());
case 'tbody':
return trim($element->getValue());
case 'thead':
$headerLine = reset($element->getChildren())->getValue();
$headers = explode(' | ', trim(trim($headerLine, "\n"), '|'));
$hr = [];
foreach ($headers as $td) {
$length = strlen(trim($td)) + 2;
$hr[] = str_repeat('-', $length > 3 ? $length : 3);
}
$hr = '|' . implode('|', $hr) . '|';
return $headerLine . $hr . "\n";
case 'table':
$inner = $element->getValue();
if (strpos($inner, '-----') === false) {
$inner = explode("\n", $inner);
$single = explode(' | ', trim($inner[0], '|'));
$hr = [];
foreach ($single as $td) {
$length = strlen(trim($td)) + 2;
$hr[] = str_repeat('-', $length > 3 ? $length : 3);
}
$hr = '|' . implode('|', $hr) . '|';
array_splice($inner, 1, 0, $hr);
$inner = implode("\n", $inner);
}
return trim($inner) . "\n\n";
}
return $element->getValue();
}
/**
* @return string[]
*/
public function getSupportedTags()
{
return array('table', 'tr', 'thead', 'td', 'tbody');
}
}

View file

@ -22,111 +22,126 @@ namespace Zotlabs\Lib;
* $html = \Michelf\MarkdownExtra::DefaultTransform($markdown);
* @endcode
*/
class MarkdownSoap {
class MarkdownSoap
{
/**
* @var string
*/
private $str;
/**
* @var string
*/
private $token;
/**
* @var string
*/
private $str;
/**
* @var string
*/
private $token;
function __construct($s) {
$this->str = $s;
$this->token = random_string(20);
}
public function __construct($s)
{
$this->str = $s;
$this->token = random_string(20);
}
function clean() {
public function clean()
{
$x = $this->extract_code($this->str);
$x = $this->extract_code($this->str);
$x = $this->purify($x);
$x = $this->purify($x);
$x = $this->putback_code($x);
$x = $this->putback_code($x);
$x = $this->escape($x);
$x = $this->escape($x);
return $x;
}
return $x;
}
/**
* @brief Extracts code blocks and privately escapes them from processing.
*
* @see encode_code()
* @see putback_code()
*
* @param string $s
* @return string
*/
function extract_code($s) {
/**
* @brief Extracts code blocks and privately escapes them from processing.
*
* @param string $s
* @return string
* @see encode_code()
* @see putback_code()
*
*/
public function extract_code($s)
{
$text = preg_replace_callback('{
$text = preg_replace_callback(
'{
(?:\n\n|\A\n?)
( # $1 = the code block -- one or more lines, starting with a space/tab
(?>
[ ]{'.'4'.'} # Lines must start with a tab or a tab-width of spaces
[ ]{' . '4' . '} # Lines must start with a tab or a tab-width of spaces
.*\n+
)+
)
((?=^[ ]{0,'.'4'.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
((?=^[ ]{0,' . '4' . '}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
}xm',
[ $this , 'encode_code' ], $s);
[$this, 'encode_code'],
$s
);
return $text;
}
return $text;
}
function encode_code($matches) {
return $this->token . ';' . base64_encode($matches[0]) . ';' ;
}
public function encode_code($matches)
{
return $this->token . ';' . base64_encode($matches[0]) . ';';
}
function decode_code($matches) {
return base64_decode($matches[1]);
}
public function decode_code($matches)
{
return base64_decode($matches[1]);
}
/**
* @brief Put back the code blocks.
*
* @see extract_code()
* @see decode_code()
*
* @param string $s
* @return string
*/
function putback_code($s) {
$text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm', [ $this, 'decode_code' ], $s);
return $text;
}
/**
* @brief Put back the code blocks.
*
* @param string $s
* @return string
* @see extract_code()
* @see decode_code()
*
*/
public function putback_code($s)
{
$text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm', [$this, 'decode_code'], $s);
return $text;
}
function purify($s) {
$s = $this->protect_autolinks($s);
$s = purify_html($s);
$s = $this->unprotect_autolinks($s);
return $s;
}
public function purify($s)
{
$s = $this->protect_autolinks($s);
$s = purify_html($s);
$s = $this->unprotect_autolinks($s);
return $s;
}
function protect_autolinks($s) {
$s = preg_replace('/\<(https?\:\/\/)(.*?)\>/', '[$1$2]($1$2)', $s);
return $s;
}
public function protect_autolinks($s)
{
$s = preg_replace('/\<(https?\:\/\/)(.*?)\>/', '[$1$2]($1$2)', $s);
return $s;
}
function unprotect_autolinks($s) {
return $s;
}
public function unprotect_autolinks($s)
{
return $s;
}
function escape($s) {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false);
}
public function escape($s)
{
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false);
}
/**
* @brief Converts special HTML entities back to characters.
*
* @param string $s
* @return string
*/
static public function unescape($s) {
return htmlspecialchars_decode($s, ENT_QUOTES);
}
/**
* @brief Converts special HTML entities back to characters.
*
* @param string $s
* @return string
*/
public static function unescape($s)
{
return htmlspecialchars_decode($s, ENT_QUOTES);
}
}

View file

@ -5,99 +5,104 @@ namespace Zotlabs\Lib;
use App;
use Zotlabs\Lib\PConfig;
class MastAPI
{
class MastAPI {
public static function format_channel($channel)
{
$p = q(
"select * from profile where uid = %d and is_default = 1",
intval($channel['channel_id'])
);
static function format_channel($channel) {
$p = q("select * from profile where uid = %d and is_default = 1",
intval($channel['channel_id'])
);
$a = q(
"select * from account where account_id = %d",
intval($channel['channel_account_id'])
);
$a = q("select * from account where account_id = %d",
intval($channel['channel_account_id'])
);
$followers = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ",
$followers = q(
"select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
$following = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
$following = q(
"select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
$cover_photo = get_cover_photo($channel['channel_id'],'array');
$cover_photo = get_cover_photo($channel['channel_id'], 'array');
$item_normal = item_normal();
// count posts/comments
$statuses = q("SELECT COUNT(id) as total FROM item
$statuses = q(
"SELECT COUNT(id) as total FROM item
WHERE uid = %d
AND author_xchan = '%s' $item_normal ",
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
dbesc($channel['channel_hash'])
);
$ret = [];
$ret['id'] = (string) $channel['channel_id'];
$ret['username'] = $channel['channel_address'];
$ret['acct'] = $channel['channel_address'];
$ret['display_name'] = $channel['channel_name'];
$ret['locked'] = ((intval(PConfig::Get($channel['channel_id'],'system','autoperms'))) ? false : true );
$ret['discoverable'] = ((1 - intval($channel['xchan_hidden'])) ? true : false);
$ret['created_at'] = datetime_convert('UTC','UTC', $a[0]['account_created'], ATOM_TIME);
$ret['note'] = bbcode($p[0]['about'], [ 'export' => true ]);
$ret['url'] = channel_url($channel);
$ret['avatar'] = $channel['xchan_photo_l'];
$ret['avatar_static'] = $channel['xchan_photo_l'];
if ($cover_photo) {
$ret['header'] = $cover_photo['url'];
$ret['header_static'] = $cover_photo['url'];
}
$ret['followers_count'] = intval($followers[0]['total']);
$ret['following_count'] = intval($following[0]['total']);
$ret['statuses_count'] = intval($statuses[0]['total']);
$ret['last_status_at'] = datetime_convert('UTC','UTC', $channel['lastpost'], ATOM_TIME);
$ret = [];
$ret['id'] = (string)$channel['channel_id'];
$ret['username'] = $channel['channel_address'];
$ret['acct'] = $channel['channel_address'];
$ret['display_name'] = $channel['channel_name'];
$ret['locked'] = ((intval(PConfig::Get($channel['channel_id'], 'system', 'autoperms'))) ? false : true);
$ret['discoverable'] = ((1 - intval($channel['xchan_hidden'])) ? true : false);
$ret['created_at'] = datetime_convert('UTC', 'UTC', $a[0]['account_created'], ATOM_TIME);
$ret['note'] = bbcode($p[0]['about'], ['export' => true]);
$ret['url'] = channel_url($channel);
$ret['avatar'] = $channel['xchan_photo_l'];
$ret['avatar_static'] = $channel['xchan_photo_l'];
if ($cover_photo) {
$ret['header'] = $cover_photo['url'];
$ret['header_static'] = $cover_photo['url'];
}
$ret['followers_count'] = intval($followers[0]['total']);
$ret['following_count'] = intval($following[0]['total']);
$ret['statuses_count'] = intval($statuses[0]['total']);
$ret['last_status_at'] = datetime_convert('UTC', 'UTC', $channel['lastpost'], ATOM_TIME);
return $ret;
}
return $ret;
}
static function format_site() {
public static function format_site()
{
$register = intval(get_config('system','register_policy'));
$register = intval(get_config('system', 'register_policy'));
$u = q("select count(channel_id) as total from channel where channel_removed = 0");
$i = q("select count(id) as total from item where item_origin = 1");
$s = q("select count(site_url) as total from site");
$u = q("select count(channel_id) as total from channel where channel_removed = 0");
$i = q("select count(id) as total from item where item_origin = 1");
$s = q("select count(site_url) as total from site");
$admins = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 ) > 0 and account_default_channel = channel_id");
$adminsx = channelx_by_n($admins[0]['channel_id']);
$admins = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 ) > 0 and account_default_channel = channel_id");
$adminsx = channelx_by_n($admins[0]['channel_id']);
$ret = [];
$ret['uri'] = z_root();
$ret['title'] = System::get_site_name();
$ret['description'] = bbcode(get_config('system','siteinfo',''), [ 'export' => true ] );
$ret['email'] = get_config('system','admin_email');
$ret['version'] = System::get_project_version();
$ret['registrations'] = (($register) ? true : false);
$ret['approval_required'] = (($register === REGISTER_APPROVE) ? true : false);
$ret['invites_enabled'] = false;
$ret['urls'] = [];
$ret['stats'] = [
'user_count' => intval($u[0]['total']),
'status_count' => intval($i[0]['total']),
'domain_count' => intval($s[0]['total']),
];
$ret = [];
$ret['uri'] = z_root();
$ret['title'] = System::get_site_name();
$ret['description'] = bbcode(get_config('system', 'siteinfo', ''), ['export' => true]);
$ret['email'] = get_config('system', 'admin_email');
$ret['version'] = System::get_project_version();
$ret['registrations'] = (($register) ? true : false);
$ret['approval_required'] = (($register === REGISTER_APPROVE) ? true : false);
$ret['invites_enabled'] = false;
$ret['urls'] = [];
$ret['stats'] = [
'user_count' => intval($u[0]['total']),
'status_count' => intval($i[0]['total']),
'domain_count' => intval($s[0]['total']),
];
$ret['contact_account'] = self::format_channel($adminsx);
return $ret;
}
$ret['contact_account'] = self::format_channel($adminsx);
return $ret;
}
}

View file

@ -3,88 +3,94 @@
namespace Zotlabs\Lib;
class MessageFilter {
class MessageFilter
{
static public function evaluate($item,$incl,$excl) {
public static function evaluate($item, $incl, $excl)
{
require_once('include/html2plain.php');
require_once('include/html2plain.php');
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/x-multicode'));
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
$lang = null;
$lang = null;
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) {
$lang = detect_language($text);
}
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
$lang = detect_language($text);
}
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
// exclude always has priority
// exclude always has priority
$exclude = (($excl) ? explode("\n",$excl) : null);
$exclude = (($excl) ? explode("\n", $excl) : null);
if($exclude) {
foreach($exclude as $word) {
$word = trim($word);
if(! $word)
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return false;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return false;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return false;
elseif(stristr($text,$word) !== false)
return false;
}
}
if ($exclude) {
foreach ($exclude as $word) {
$word = trim($word);
if (! $word) {
continue;
}
if (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return false;
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
return false;
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
return false;
} elseif (stristr($text, $word) !== false) {
return false;
}
}
}
$include = (($incl) ? explode("\n",$incl) : null);
if($include) {
foreach($include as $word) {
$word = trim($word);
if(! $word)
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return true;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return true;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return true;
elseif(stristr($text,$word) !== false)
return true;
}
}
else {
return true;
}
return false;
}
$include = (($incl) ? explode("\n", $incl) : null);
if ($include) {
foreach ($include as $word) {
$word = trim($word);
if (! $word) {
continue;
}
if (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return true;
} elseif ((strpos($word, 'lang=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 5))) == 0)) {
return true;
} elseif ((strpos($word, 'lang!=') === 0) && ($lang) && (strcasecmp($lang, trim(substr($word, 6))) != 0)) {
return true;
} elseif (stristr($text, $word) !== false) {
return true;
}
}
} else {
return true;
}
return false;
}
}

View file

@ -2,43 +2,40 @@
namespace Zotlabs\Lib;
class Nodeinfo
{
class Nodeinfo {
static public function fetch($url) {
$href = EMPTY_STR;
$m = parse_url($url);
if ($m['scheme'] && $m['host']) {
$s = $m['scheme'] . '://' . $m['host'] . '/.well-known/nodeinfo';
$n = z_fetch_url($s);
if ($n['success']) {
$j = json_decode($n['body'], true);
if ($j && $j['links']) {
// lemmy just sends one result
if (isset($j['links']['rel'])) {
if ($j['links']['rel'] === 'http://nodeinfo.diaspora.software/ns/schema/2.0' && isset($j['links']['href'])) {
$href = $j['links']['href'];
}
}
else {
foreach ($j['links'] as $l) {
if (isset($l['rel']) && $l['rel'] === 'http://nodeinfo.diaspora.software/ns/schema/2.0' && isset($l['href'])) {
$href = $l['href'];
}
}
}
}
}
}
if ($href) {
$n = z_fetch_url($href);
if ($n['success']) {
return json_decode($n['body'],true);
}
}
return [];
}
public static function fetch($url)
{
$href = EMPTY_STR;
$m = parse_url($url);
if ($m['scheme'] && $m['host']) {
$s = $m['scheme'] . '://' . $m['host'] . '/.well-known/nodeinfo';
$n = z_fetch_url($s);
if ($n['success']) {
$j = json_decode($n['body'], true);
if ($j && $j['links']) {
// lemmy just sends one result
if (isset($j['links']['rel'])) {
if ($j['links']['rel'] === 'http://nodeinfo.diaspora.software/ns/schema/2.0' && isset($j['links']['href'])) {
$href = $j['links']['href'];
}
} else {
foreach ($j['links'] as $l) {
if (isset($l['rel']) && $l['rel'] === 'http://nodeinfo.diaspora.software/ns/schema/2.0' && isset($l['href'])) {
$href = $l['href'];
}
}
}
}
}
}
if ($href) {
$n = z_fetch_url($href);
if ($n['success']) {
return json_decode($n['body'], true);
}
}
return [];
}
}

View file

@ -2,6 +2,8 @@
namespace Zotlabs\Lib;
use App;
/**
* @brief Class for handling channel specific configurations.
*
@ -16,193 +18,212 @@ namespace Zotlabs\Lib;
* The old (deprecated?) way to access a PConfig value is:
* @code{.php}$var = get_pconfig(local_channel(), 'category', 'key');@endcode
*/
class PConfig {
class PConfig
{
/**
* @brief Loads all configuration values of a channel into a cached storage.
*
* All configuration values of the given channel are stored in global cache
* which is available under the global variable App::$config[$uid].
*
* @param string $uid
* The channel_id
* @return void|false Nothing or false if $uid is null or false
*/
static public function Load($uid) {
if(is_null($uid) || $uid === false)
return false;
/**
* @brief Loads all configuration values of a channel into a cached storage.
*
* All configuration values of the given channel are stored in global cache
* which is available under the global variable App::$config[$uid].
*
* @param string $uid
* The channel_id
* @return void|false Nothing or false if $uid is null or false
*/
public static function Load($uid)
{
if (is_null($uid) || $uid === false) {
return false;
}
if(! is_array(\App::$config)) {
btlogger('App::$config not an array');
}
if (! is_array(App::$config)) {
btlogger('App::$config not an array');
}
if(! array_key_exists($uid, \App::$config)) {
\App::$config[$uid] = [];
}
if (! array_key_exists($uid, App::$config)) {
App::$config[$uid] = [];
}
if(! is_array(\App::$config[$uid])) {
btlogger('App::$config[$uid] not an array: ' . $uid);
}
if (! is_array(App::$config[$uid])) {
btlogger('App::$config[$uid] not an array: ' . $uid);
}
$r = q("SELECT * FROM pconfig WHERE uid = %d",
intval($uid)
);
$r = q(
"SELECT * FROM pconfig WHERE uid = %d",
intval($uid)
);
if($r) {
foreach($r as $rr) {
$k = $rr['k'];
$c = $rr['cat'];
if(! array_key_exists($c, \App::$config[$uid])) {
\App::$config[$uid][$c] = [];
\App::$config[$uid][$c]['config_loaded'] = true;
}
\App::$config[$uid][$c][$k] = $rr['v'];
}
}
}
if ($r) {
foreach ($r as $rr) {
$k = $rr['k'];
$c = $rr['cat'];
if (! array_key_exists($c, App::$config[$uid])) {
App::$config[$uid][$c] = [];
App::$config[$uid][$c]['config_loaded'] = true;
}
App::$config[$uid][$c][$k] = $rr['v'];
}
}
}
/**
* @brief Get a particular channel's config variable given the category name
* ($family) and a key.
*
* Get a particular channel's config value from the given category ($family)
* and the $key from a cached storage in App::$config[$uid].
*
* Returns false if not set.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param mixed $default (optional, default false)
* Default value to return if key does not exist
* @return mixed Stored value or false if it does not exist
*/
static public function Get($uid, $family, $key, $default = false) {
/**
* @brief Get a particular channel's config variable given the category name
* ($family) and a key.
*
* Get a particular channel's config value from the given category ($family)
* and the $key from a cached storage in App::$config[$uid].
*
* Returns false if not set.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param mixed $default (optional, default false)
* Default value to return if key does not exist
* @return mixed Stored value or false if it does not exist
*/
public static function Get($uid, $family, $key, $default = false)
{
if(is_null($uid) || $uid === false)
return $default;
if (is_null($uid) || $uid === false) {
return $default;
}
if(! array_key_exists($uid, \App::$config))
self::Load($uid);
if (! array_key_exists($uid, App::$config)) {
self::Load($uid);
}
if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family])))
return $default;
if ((! array_key_exists($family, App::$config[$uid])) || (! array_key_exists($key, App::$config[$uid][$family]))) {
return $default;
}
return unserialise(\App::$config[$uid][$family][$key]);
}
return unserialise(App::$config[$uid][$family][$key]);
}
/**
* @brief Sets a configuration value for a channel.
*
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the channel_id $uid.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param string $value
* The value to store
* @return mixed Stored $value or false
*/
static public function Set($uid, $family, $key, $value) {
/**
* @brief Sets a configuration value for a channel.
*
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the channel_id $uid.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param string $value
* The value to store
* @return mixed Stored $value or false
*/
public static function Set($uid, $family, $key, $value)
{
// this catches subtle errors where this function has been called
// with local_channel() when not logged in (which returns false)
// and throws an error in array_key_exists below.
// we provide a function backtrace in the logs so that we can find
// and fix the calling function.
// this catches subtle errors where this function has been called
// with local_channel() when not logged in (which returns false)
// and throws an error in array_key_exists below.
// we provide a function backtrace in the logs so that we can find
// and fix the calling function.
if(is_null($uid) || $uid === false) {
btlogger('UID is FALSE!', LOGGER_NORMAL, LOG_ERR);
return;
}
if (is_null($uid) || $uid === false) {
btlogger('UID is FALSE!', LOGGER_NORMAL, LOG_ERR);
return;
}
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($uid, $family, $key) === false) {
if(! array_key_exists($uid, \App::$config))
\App::$config[$uid] = [];
if(! array_key_exists($family, \App::$config[$uid]))
\App::$config[$uid][$family] = [];
if (self::Get($uid, $family, $key) === false) {
if (! array_key_exists($uid, App::$config)) {
App::$config[$uid] = [];
}
if (! array_key_exists($family, App::$config[$uid])) {
App::$config[$uid][$family] = [];
}
$ret = q("INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ",
intval($uid),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
}
else {
$ret = q(
"INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ",
intval($uid),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
} else {
$ret = q(
"UPDATE pconfig SET v = '%s' WHERE uid = %d and cat = '%s' AND k = '%s'",
dbesc($dbvalue),
intval($uid),
dbesc($family),
dbesc($key)
);
}
$ret = q("UPDATE pconfig SET v = '%s' WHERE uid = %d and cat = '%s' AND k = '%s'",
dbesc($dbvalue),
intval($uid),
dbesc($family),
dbesc($key)
);
}
// keep a separate copy for all variables which were
// set in the life of this page. We need this to
// synchronise channel clones.
// keep a separate copy for all variables which were
// set in the life of this page. We need this to
// synchronise channel clones.
if (! array_key_exists('transient', App::$config[$uid])) {
App::$config[$uid]['transient'] = [];
}
if (! array_key_exists($family, App::$config[$uid]['transient'])) {
App::$config[$uid]['transient'][$family] = [];
}
if(! array_key_exists('transient', \App::$config[$uid]))
\App::$config[$uid]['transient'] = [];
if(! array_key_exists($family, \App::$config[$uid]['transient']))
\App::$config[$uid]['transient'][$family] = [];
App::$config[$uid][$family][$key] = $value;
App::$config[$uid]['transient'][$family][$key] = $value;
\App::$config[$uid][$family][$key] = $value;
\App::$config[$uid]['transient'][$family][$key] = $value;
if ($ret) {
return $value;
}
if($ret)
return $value;
return $ret;
}
return $ret;
}
/**
* @brief Deletes the given key from the channel's configuration.
*
* Removes the configured value from the stored cache in App::$config[$uid]
* and removes it from the database.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
static public function Delete($uid, $family, $key) {
/**
* @brief Deletes the given key from the channel's configuration.
*
* Removes the configured value from the stored cache in App::$config[$uid]
* and removes it from the database.
*
* @param string $uid
* The channel_id
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
public static function Delete($uid, $family, $key)
{
if(is_null($uid) || $uid === false)
return false;
if (is_null($uid) || $uid === false) {
return false;
}
$ret = false;
$ret = false;
if(array_key_exists($uid,\App::$config)
&& is_array(\App::$config['uid'])
&& array_key_exists($family,\App::$config['uid'])
&& array_key_exists($key, \App::$config[$uid][$family]))
unset(\App::$config[$uid][$family][$key]);
if (
array_key_exists($uid, App::$config)
&& is_array(App::$config['uid'])
&& array_key_exists($family, App::$config['uid'])
&& array_key_exists($key, App::$config[$uid][$family])
) {
unset(App::$config[$uid][$family][$key]);
}
$ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
intval($uid),
dbesc($family),
dbesc($key)
);
return $ret;
}
$ret = q(
"DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
intval($uid),
dbesc($family),
dbesc($key)
);
return $ret;
}
}

View file

@ -21,157 +21,168 @@ use Zotlabs\Access\Permissions;
* These answer the question "Can Joe view *this* album/photo?".
*/
class Permcat {
class Permcat
{
/**
* @var array
*/
private $permcats = [];
/**
* @var array
*/
private $permcats = [];
/**
* @brief Permcat constructor.
*
* @param int $channel_id
*/
public function __construct($channel_id) {
/**
* @brief Permcat constructor.
*
* @param int $channel_id
*/
public function __construct($channel_id)
{
$perms = [];
$perms = [];
// first check role perms for a perms_connect setting
// first check role perms for a perms_connect setting
$role = get_pconfig($channel_id,'system','permissions_role');
if($role) {
$x = PermissionRoles::role_perms($role);
if($x['perms_connect']) {
$perms = Permissions::FilledPerms($x['perms_connect']);
}
}
$role = get_pconfig($channel_id, 'system', 'permissions_role');
if ($role) {
$x = PermissionRoles::role_perms($role);
if ($x['perms_connect']) {
$perms = Permissions::FilledPerms($x['perms_connect']);
}
}
// if no role perms it may be a custom role, see if there any autoperms
// if no role perms it may be a custom role, see if there any autoperms
if(! $perms) {
$perms = Permissions::FilledAutoPerms($channel_id);
}
if (! $perms) {
$perms = Permissions::FilledAutoPerms($channel_id);
}
// if no autoperms it may be a custom role with manual perms
// if no autoperms it may be a custom role with manual perms
if(! $perms) {
$c = channelx_by_n($channel_id);
if($c) {
$perms = Permissions::FilledPerms(get_abconfig($channel_id,$c['channel_hash'],'system','my_perms',EMPTY_STR));
}
}
if (! $perms) {
$c = channelx_by_n($channel_id);
if ($c) {
$perms = Permissions::FilledPerms(get_abconfig($channel_id, $c['channel_hash'], 'system', 'my_perms', EMPTY_STR));
}
}
// nothing was found - create a filled permission array where all permissions are 0
// nothing was found - create a filled permission array where all permissions are 0
if(! $perms) {
$perms = Permissions::FilledPerms([]);
}
if (! $perms) {
$perms = Permissions::FilledPerms([]);
}
$this->permcats[] = [
'name' => 'default',
'localname' => t('default','permcat'),
'perms' => Permissions::Operms($perms),
'system' => 1
];
$this->permcats[] = [
'name' => 'default',
'localname' => t('default', 'permcat'),
'perms' => Permissions::Operms($perms),
'system' => 1
];
$p = $this->load_permcats($channel_id);
if($p) {
for($x = 0; $x < count($p); $x++) {
$this->permcats[] = [
'name' => $p[$x][0],
'localname' => $p[$x][1],
'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])),
'system' => intval($p[$x][3])
];
}
}
}
$p = $this->load_permcats($channel_id);
if ($p) {
for ($x = 0; $x < count($p); $x++) {
$this->permcats[] = [
'name' => $p[$x][0],
'localname' => $p[$x][1],
'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])),
'system' => intval($p[$x][3])
];
}
}
}
/**
* @brief Return array with permcats.
*
* @return array
*/
public function listing() {
return $this->permcats;
}
/**
* @brief Return array with permcats.
*
* @return array
*/
public function listing()
{
return $this->permcats;
}
/**
* @brief
*
* @param string $name
* @return array
* * \e array with permcats
* * \e bool \b error if $name not found in permcats true
*/
public function fetch($name) {
if($name && $this->permcats) {
foreach($this->permcats as $permcat) {
if(strcasecmp($permcat['name'], $name) === 0) {
return $permcat;
}
}
}
/**
* @brief
*
* @param string $name
* @return array
* * \e array with permcats
* * \e bool \b error if $name not found in permcats true
*/
public function fetch($name)
{
if ($name && $this->permcats) {
foreach ($this->permcats as $permcat) {
if (strcasecmp($permcat['name'], $name) === 0) {
return $permcat;
}
}
}
return ['error' => true];
}
return ['error' => true];
}
public function load_permcats($uid) {
public function load_permcats($uid)
{
$permcats = [
[ 'follower', t('follower','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_like' ], 1
],
[ 'contributor', t('contributor','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_wall','post_comments','write_wiki','post_like','tag_deliver','chat' ], 1
],
[ 'publisher', t('publisher','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages',
'write_storage','post_wall','write_pages','write_wiki','post_comments','post_like','tag_deliver',
'chat', 'republish' ], 1
]
];
$permcats = [
[ 'follower', t('follower', 'permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_like' ], 1
],
[ 'contributor', t('contributor', 'permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_wall','post_comments','write_wiki','post_like','tag_deliver','chat' ], 1
],
[ 'publisher', t('publisher', 'permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages',
'write_storage','post_wall','write_pages','write_wiki','post_comments','post_like','tag_deliver',
'chat', 'republish' ], 1
]
];
if($uid) {
$x = q("select * from pconfig where uid = %d and cat = 'permcat'",
intval($uid)
);
if($x) {
foreach($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [ $xv['k'], $xv['k'], $value, 0 ];
}
}
}
if ($uid) {
$x = q(
"select * from pconfig where uid = %d and cat = 'permcat'",
intval($uid)
);
if ($x) {
foreach ($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [ $xv['k'], $xv['k'], $value, 0 ];
}
}
}
/**
* @hooks permcats
* * \e array
*/
call_hooks('permcats', $permcats);
/**
* @hooks permcats
* * \e array
*/
call_hooks('permcats', $permcats);
return $permcats;
}
return $permcats;
}
static public function find_permcat($arr, $name) {
if((! $arr) || (! $name))
return false;
public static function find_permcat($arr, $name)
{
if ((! $arr) || (! $name)) {
return false;
}
foreach($arr as $p)
if($p['name'] == $name)
return $p['value'];
}
foreach ($arr as $p) {
if ($p['name'] == $name) {
return $p['value'];
}
}
}
static public function update($channel_id, $name, $permarr) {
PConfig::Set($channel_id, 'permcat', $name, $permarr);
}
static public function delete($channel_id, $name) {
PConfig::Delete($channel_id, 'permcat', $name);
}
public static function update($channel_id, $name, $permarr)
{
PConfig::Set($channel_id, 'permcat', $name, $permarr);
}
public static function delete($channel_id, $name)
{
PConfig::Delete($channel_id, 'permcat', $name);
}
}

View file

@ -2,6 +2,10 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
require_once("include/permissions.php");
require_once("include/language.php");
require_once("include/text.php");
@ -12,148 +16,178 @@ require_once("include/text.php");
* permission settings for an item with an empty ACL.
* i.e the caption, icon, and tooltip for the no-ACL option in the ACL dialog.
*/
class PermissionDescription {
class PermissionDescription
{
private $global_perm;
private $channel_perm;
private $fallback_description;
private $global_perm;
private $channel_perm;
private $fallback_description;
/**
* Constructor is private.
* Use static methods fromGlobalPermission(), fromStandalonePermission(),
* or fromDescription() to create instances.
*
* @internal
* @param int $global_perm
* @param int $channel_perm
* @param string $description (optional) default empty
*/
private function __construct($global_perm, $channel_perm, $description = '') {
$this->global_perm = $global_perm;
$this->channel_perm = $channel_perm;
$this->fallback_description = ($description == '') ? t('Visible to your default audience') : $description;
}
/**
* Constructor is private.
* Use static methods fromGlobalPermission(), fromStandalonePermission(),
* or fromDescription() to create instances.
*
* @internal
* @param int $global_perm
* @param int $channel_perm
* @param string $description (optional) default empty
*/
private function __construct($global_perm, $channel_perm, $description = '')
{
$this->global_perm = $global_perm;
$this->channel_perm = $channel_perm;
$this->fallback_description = ($description == '') ? t('Visible to your default audience') : $description;
}
/**
* If the interpretation of an empty ACL can't be summarised with a global default permission
* or a specific permission setting then use this method and describe what it means instead.
* Remember to localize the description first.
*
* @param string $description - the localized caption for the no-ACL option in the ACL dialog.
* @return a new instance of PermissionDescription
*/
public static function fromDescription($description) {
return new PermissionDescription('', 0x80000, $description);
}
/**
* If the interpretation of an empty ACL can't be summarised with a global default permission
* or a specific permission setting then use this method and describe what it means instead.
* Remember to localize the description first.
*
* @param string $description - the localized caption for the no-ACL option in the ACL dialog.
* @return a new instance of PermissionDescription
*/
public static function fromDescription($description)
{
return new PermissionDescription('', 0x80000, $description);
}
/**
* Use this method only if the interpretation of an empty ACL doesn't fall back to a global
* default permission. You should pass one of the constants from boot.php - PERMS_PUBLIC,
* PERMS_NETWORK etc.
*
* @param integer $perm - a single enumerated constant permission - PERMS_PUBLIC, PERMS_NETWORK etc.
* @return a new instance of PermissionDescription
*/
public static function fromStandalonePermission($perm) {
/**
* Use this method only if the interpretation of an empty ACL doesn't fall back to a global
* default permission. You should pass one of the constants from boot.php - PERMS_PUBLIC,
* PERMS_NETWORK etc.
*
* @param int $perm - a single enumerated constant permission - PERMS_PUBLIC, PERMS_NETWORK etc.
* @return a new instance of PermissionDescription
*/
public static function fromStandalonePermission($perm)
{
$result = new PermissionDescription('', $perm);
$result = new PermissionDescription('', $perm);
$checkPerm = $result->get_permission_description();
if($checkPerm == $result->fallback_description) {
$result = null;
logger('null PermissionDescription from unknown standalone permission: ' . $perm, LOGGER_DEBUG, LOG_ERR);
}
$checkPerm = $result->get_permission_description();
if ($checkPerm == $result->fallback_description) {
$result = null;
logger('null PermissionDescription from unknown standalone permission: ' . $perm, LOGGER_DEBUG, LOG_ERR);
}
return $result;
}
return $result;
}
/**
* This is the preferred way to create a PermissionDescription, as it provides the most details.
* Use this method if you know an empty ACL will result in one of the global default permissions
* being used, such as channel_r_stream (for which you would pass 'view_stream').
*
* @param string $permname - a key for the global perms array from get_perms() in permissions.php,
* e.g. 'view_stream', 'view_profile', etc.
* @return a new instance of PermissionDescription
*/
public static function fromGlobalPermission($permname) {
/**
* This is the preferred way to create a PermissionDescription, as it provides the most details.
* Use this method if you know an empty ACL will result in one of the global default permissions
* being used, such as channel_r_stream (for which you would pass 'view_stream').
*
* @param string $permname - a key for the global perms array from get_perms() in permissions.php,
* e.g. 'view_stream', 'view_profile', etc.
* @return a new instance of PermissionDescription
*/
public static function fromGlobalPermission($permname)
{
$result = null;
$result = null;
$global_perms = \Zotlabs\Access\Permissions::Perms();
$global_perms = Permissions::Perms();
if(array_key_exists($permname, $global_perms)) {
if (array_key_exists($permname, $global_perms)) {
$channelPerm = PermissionLimits::Get(App::$channel['channel_id'], $permname);
$channelPerm = \Zotlabs\Access\PermissionLimits::Get(\App::$channel['channel_id'], $permname);
$result = new PermissionDescription('', $channelPerm);
} else {
// The acl dialog can handle null arguments, but it shouldn't happen
logger('null PermissionDescription from unknown global permission: ' . $permname, LOGGER_DEBUG, LOG_ERR);
}
$result = new PermissionDescription('', $channelPerm);
} else {
// The acl dialog can handle null arguments, but it shouldn't happen
logger('null PermissionDescription from unknown global permission: ' . $permname, LOGGER_DEBUG, LOG_ERR);
}
return $result;
}
return $result;
}
/**
* Gets a localized description of the permission, or a generic message if the permission
* is unknown.
*
* @return string description
*/
public function get_permission_description()
{
/**
* Gets a localized description of the permission, or a generic message if the permission
* is unknown.
*
* @return string description
*/
public function get_permission_description() {
switch ($this->channel_perm) {
case 0:
return t('Only me');
case PERMS_PUBLIC:
return t('Public');
case PERMS_NETWORK:
return t('Anybody in the $Projectname network');
case PERMS_SITE:
return sprintf(t('Any account on %s'), App::get_hostname());
case PERMS_CONTACTS:
return t('Any of my connections');
case PERMS_SPECIFIC:
return t('Only connections I specifically allow');
case PERMS_AUTHED:
return t('Anybody authenticated (could include visitors from other networks)');
case PERMS_PENDING:
return t('Any connections including those who haven\'t yet been approved');
default:
return $this->fallback_description;
}
}
switch($this->channel_perm) {
case 0: return t('Only me');
case PERMS_PUBLIC: return t('Public');
case PERMS_NETWORK: return t('Anybody in the $Projectname network');
case PERMS_SITE: return sprintf(t('Any account on %s'), \App::get_hostname());
case PERMS_CONTACTS: return t('Any of my connections');
case PERMS_SPECIFIC: return t('Only connections I specifically allow');
case PERMS_AUTHED: return t('Anybody authenticated (could include visitors from other networks)');
case PERMS_PENDING: return t('Any connections including those who haven\'t yet been approved');
default: return $this->fallback_description;
}
}
/**
* Returns an icon css class name if an appropriate one is available, e.g. "fa-globe" for Public,
* otherwise returns empty string.
*
* @return string icon css class name (often FontAwesome)
*/
public function get_permission_icon()
{
/**
* Returns an icon css class name if an appropriate one is available, e.g. "fa-globe" for Public,
* otherwise returns empty string.
*
* @return string icon css class name (often FontAwesome)
*/
public function get_permission_icon() {
switch ($this->channel_perm) {
case 0:
return 'fa-eye-slash';
case PERMS_PUBLIC:
return 'fa-globe';
case PERMS_NETWORK:
return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
case PERMS_SITE:
return 'fa-sitemap';
case PERMS_CONTACTS:
return 'fa-group';
case PERMS_SPECIFIC:
return 'fa-list';
case PERMS_AUTHED:
return '';
case PERMS_PENDING:
return '';
default:
return '';
}
}
switch($this->channel_perm) {
case 0:/* only me */ return 'fa-eye-slash';
case PERMS_PUBLIC: return 'fa-globe';
case PERMS_NETWORK: return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
case PERMS_SITE: return 'fa-sitemap';
case PERMS_CONTACTS: return 'fa-group';
case PERMS_SPECIFIC: return 'fa-list';
case PERMS_AUTHED: return '';
case PERMS_PENDING: return '';
default: return '';
}
}
/**
* Returns a localized description of where the permission came from, if this is known.
* If it's not know, or if the permission is standalone and didn't come from a default
* permission setting, then empty string is returned.
*
* @return string description or empty string
*/
public function get_permission_origin_description() {
switch($this->global_perm) {
case PERMS_R_STREAM: return t('This is your default setting for the audience of your normal stream, and posts.');
case PERMS_R_PROFILE: return t('This is your default setting for who can view your default channel profile');
case PERMS_R_ABOOK: return t('This is your default setting for who can view your connections');
case PERMS_R_STORAGE: return t('This is your default setting for who can view your file storage and photos');
case PERMS_R_PAGES: return t('This is your default setting for the audience of your webpages');
default: return '';
}
}
/**
* Returns a localized description of where the permission came from, if this is known.
* If it's not know, or if the permission is standalone and didn't come from a default
* permission setting, then empty string is returned.
*
* @return string description or empty string
*/
public function get_permission_origin_description()
{
switch ($this->global_perm) {
case PERMS_R_STREAM:
return t('This is your default setting for the audience of your normal stream, and posts.');
case PERMS_R_PROFILE:
return t('This is your default setting for who can view your default channel profile');
case PERMS_R_ABOOK:
return t('This is your default setting for who can view your connections');
case PERMS_R_STORAGE:
return t('This is your default setting for who can view your file storage and photos');
case PERMS_R_PAGES:
return t('This is your default setting for the audience of your webpages');
default:
return '';
}
}
}

View file

@ -1,4 +1,6 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Lib;
@ -6,463 +8,481 @@ use Zotlabs\Lib\Libzot;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Zot6\Receiver;
use Zotlabs\Zot6\Zot6Handler;
class Queue {
class Queue
{
static function update($id, $add_priority = 0) {
public static function update($id, $add_priority = 0)
{
logger('queue: requeue item ' . $id,LOGGER_DEBUG);
logger('queue: requeue item ' . $id, LOGGER_DEBUG);
// This queue item failed. Perhaps it was rejected. Perhaps the site is dead.
// Since we don't really know, check and see if we've got something else destined
// for that server and give it priority. At a minimum it will keep the queue from
// getting stuck on a particular message when another one with different content
// might actually succeed.
// This queue item failed. Perhaps it was rejected. Perhaps the site is dead.
// Since we don't really know, check and see if we've got something else destined
// for that server and give it priority. At a minimum it will keep the queue from
// getting stuck on a particular message when another one with different content
// might actually succeed.
$x = q("select outq_created, outq_hash, outq_posturl from outq where outq_hash = '%s' limit 1",
dbesc($id)
);
if (! $x) {
return;
}
$x = q(
"select outq_created, outq_hash, outq_posturl from outq where outq_hash = '%s' limit 1",
dbesc($id)
);
if (!$x) {
return;
}
$g = q("select outq_created, outq_hash, outq_posturl from outq where outq_posturl = '%s' and outq_hash != '%s' limit 1",
dbesc($x[0]['outq_posturl']),
dbesc($id)
);
$g = q(
"select outq_created, outq_hash, outq_posturl from outq where outq_posturl = '%s' and outq_hash != '%s' limit 1",
dbesc($x[0]['outq_posturl']),
dbesc($id)
);
// swap them
// swap them
if ($g) {
$x = $g;
}
if ($g) {
$x = $g;
}
$y = q(
"select min(outq_created) as earliest from outq where outq_posturl = '%s'",
dbesc($x[0]['outq_posturl'])
);
$y = q("select min(outq_created) as earliest from outq where outq_posturl = '%s'",
dbesc($x[0]['outq_posturl'])
);
// look for the oldest queue entry with this destination URL. If it's older than a couple of days,
// the destination is considered to be down and only scheduled once an hour, regardless of the
// age of the current queue item.
// look for the oldest queue entry with this destination URL. If it's older than a couple of days,
// the destination is considered to be down and only scheduled once an hour, regardless of the
// age of the current queue item.
$might_be_down = false;
$might_be_down = false;
if($y)
$might_be_down = ((datetime_convert('UTC','UTC',$y[0]['earliest']) < datetime_convert('UTC','UTC','now - 2 days')) ? true : false);
if ($y) {
$might_be_down = ((datetime_convert('UTC', 'UTC', $y[0]['earliest']) < datetime_convert('UTC', 'UTC', 'now - 2 days')) ? true : false);
}
// Set all other records for this destination way into the future.
// The queue delivers by destination. We'll keep one queue item for
// this destination (this one) with a shorter delivery. If we succeed
// once, we'll try to deliver everything for that destination.
// The delivery will be set to at most once per hour, and if the
// queue item is less than 12 hours old, we'll schedule for fifteen
// minutes.
// Set all other records for this destination way into the future.
// The queue delivers by destination. We'll keep one queue item for
// this destination (this one) with a shorter delivery. If we succeed
// once, we'll try to deliver everything for that destination.
// The delivery will be set to at most once per hour, and if the
// queue item is less than 12 hours old, we'll schedule for fifteen
// minutes.
$r = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'",
dbesc(datetime_convert('UTC','UTC','now + 5 days')),
dbesc($x[0]['outq_posturl'])
);
$r = q(
"UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'",
dbesc(datetime_convert('UTC', 'UTC', 'now + 5 days')),
dbesc($x[0]['outq_posturl'])
);
$since = datetime_convert('UTC','UTC',$y[0]['earliest']);
$since = datetime_convert('UTC', 'UTC', $y[0]['earliest']);
if(($might_be_down) || ($since < datetime_convert('UTC','UTC','now - 12 hour'))) {
$next = datetime_convert('UTC','UTC','now + 1 hour');
}
else {
$next = datetime_convert('UTC','UTC','now + ' . intval($add_priority) . ' minutes');
}
if (($might_be_down) || ($since < datetime_convert('UTC', 'UTC', 'now - 12 hour'))) {
$next = datetime_convert('UTC', 'UTC', 'now + 1 hour');
} else {
$next = datetime_convert('UTC', 'UTC', 'now + ' . intval($add_priority) . ' minutes');
}
q("UPDATE outq SET outq_updated = '%s',
q(
"UPDATE outq SET outq_updated = '%s',
outq_priority = outq_priority + %d,
outq_scheduled = '%s'
WHERE outq_hash = '%s'",
dbesc(datetime_convert()),
intval($add_priority),
dbesc($next),
dbesc($x[0]['outq_hash'])
);
}
dbesc(datetime_convert()),
intval($add_priority),
dbesc($next),
dbesc($x[0]['outq_hash'])
);
}
static function remove($id,$channel_id = 0) {
logger('queue: remove queue item ' . $id,LOGGER_DEBUG);
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
public static function remove($id, $channel_id = 0)
{
logger('queue: remove queue item ' . $id, LOGGER_DEBUG);
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
dbesc($id)
);
}
q(
"DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
dbesc($id)
);
}
static function remove_by_posturl($posturl) {
logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG);
public static function remove_by_posturl($posturl)
{
logger('queue: remove queue posturl ' . $posturl, LOGGER_DEBUG);
q("DELETE FROM outq WHERE outq_posturl = '%s' ",
dbesc($posturl)
);
}
q(
"DELETE FROM outq WHERE outq_posturl = '%s' ",
dbesc($posturl)
);
}
public static function set_delivered($id, $channel = 0)
{
logger('queue: set delivered ' . $id, LOGGER_DEBUG);
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
static function set_delivered($id,$channel = 0) {
logger('queue: set delivered ' . $id,LOGGER_DEBUG);
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
// Set the next scheduled run date so far in the future that it will be expired
// long before it ever makes it back into the delivery chain.
// Set the next scheduled run date so far in the future that it will be expired
// long before it ever makes it back into the delivery chain.
q("update outq set outq_delivered = 1, outq_updated = '%s', outq_scheduled = '%s' where outq_hash = '%s' $sql_extra ",
dbesc(datetime_convert()),
dbesc(datetime_convert('UTC','UTC','now + 5 days')),
dbesc($id)
);
}
q(
"update outq set outq_delivered = 1, outq_updated = '%s', outq_scheduled = '%s' where outq_hash = '%s' $sql_extra ",
dbesc(datetime_convert()),
dbesc(datetime_convert('UTC', 'UTC', 'now + 5 days')),
dbesc($id)
);
}
public static function insert($arr)
{
static function insert($arr) {
logger('insert: ' . print_r($arr, true), LOGGER_DATA);
logger('insert: ' . print_r($arr,true), LOGGER_DATA);
// do not queue anything with no destination
// do not queue anything with no destination
if (! (array_key_exists('posturl',$arr) && trim($arr['posturl']))) {
logger('no destination');
return false;
}
if (!(array_key_exists('posturl', $arr) && trim($arr['posturl']))) {
logger('no destination');
return false;
}
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
$x = q(
"insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )",
dbesc($arr['hash']),
intval($arr['account_id']),
intval($arr['channel_id']),
dbesc($arr['hash']),
intval($arr['account_id']),
intval($arr['channel_id']),
dbesc((isset($arr['driver']) && $arr['driver']) ? $arr['driver'] : 'nomad'),
dbesc($arr['posturl']),
intval(1),
intval((isset($arr['priority'])) ? $arr['priority'] : 0),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc((isset($arr['scheduled'])) ? $arr['scheduled'] : datetime_convert()),
dbesc($arr['notify']),
dbesc(($arr['msg']) ? $arr['msg'] : '')
);
return $x;
}
dbesc($arr['posturl']),
intval(1),
intval((isset($arr['priority'])) ? $arr['priority'] : 0),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc((isset($arr['scheduled'])) ? $arr['scheduled'] : datetime_convert()),
dbesc($arr['notify']),
dbesc(($arr['msg']) ? $arr['msg'] : '')
);
return $x;
}
public static function deliver($outq, $immediate = false)
{
static function deliver($outq, $immediate = false) {
$base = null;
$h = parse_url($outq['outq_posturl']);
if ($h !== false) {
$base = $h['scheme'] . '://' . $h['host'] . ((isset($h['port']) && intval($h['port'])) ? ':' . $h['port'] : '');
}
$base = null;
$h = parse_url($outq['outq_posturl']);
if ($h !== false) {
$base = $h['scheme'] . '://' . $h['host'] . ((isset($h['port']) && intval($h['port'])) ? ':' . $h['port'] : '');
}
if (($base) && ($base !== z_root()) && ($immediate)) {
$y = q(
"select site_update, site_dead from site where site_url = '%s' ",
dbesc($base)
);
if ($y) {
if (intval($y[0]['site_dead'])) {
q(
"update dreport set dreport_result = '%s' where dreport_queue = '%s'",
dbesc('site dead'),
dbesc($outq['outq_hash'])
);
if (($base) && ($base !== z_root()) && ($immediate)) {
$y = q("select site_update, site_dead from site where site_url = '%s' ",
dbesc($base)
);
if ($y) {
if (intval($y[0]['site_dead'])) {
q("update dreport set dreport_result = '%s' where dreport_queue = '%s'",
dbesc('site dead'),
dbesc($outq['outq_hash'])
);
self::remove_by_posturl($outq['outq_posturl']);
logger('dead site ignored ' . $base);
return;
}
if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
q(
"update dreport set dreport_log = '%s' where dreport_queue = '%s'",
dbesc('site deferred'),
dbesc($outq['outq_hash'])
);
self::update($outq['outq_hash'], 10);
logger('immediate delivery deferred for site ' . $base);
return;
}
} else {
// zot sites should all have a site record, unless they've been dead for as long as
// your site has existed. Since we don't know for sure what these sites are,
// call them unknown
self::remove_by_posturl($outq['outq_posturl']);
logger('dead site ignored ' . $base);
return;
}
if ($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) {
q("update dreport set dreport_log = '%s' where dreport_queue = '%s'",
dbesc('site deferred'),
dbesc($outq['outq_hash'])
);
self::update($outq['outq_hash'],10);
logger('immediate delivery deferred for site ' . $base);
return;
}
}
else {
site_store_lowlevel(
[
'site_url' => $base,
'site_update' => datetime_convert(),
'site_dead' => 0,
'site_type' => ((in_array($outq['outq_driver'], ['post', 'activitypub'])) ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN),
'site_crypto' => ''
]
);
}
}
// zot sites should all have a site record, unless they've been dead for as long as
// your site has existed. Since we don't know for sure what these sites are,
// call them unknown
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
call_hooks('queue_deliver', $arr);
if ($arr['handled']) {
return;
}
site_store_lowlevel(
[
'site_url' => $base,
'site_update' => datetime_convert(),
'site_dead' => 0,
'site_type' => ((in_array($outq['outq_driver'], [ 'post', 'activitypub' ])) ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN),
'site_crypto' => ''
]
);
}
}
// "post" queue driver - used for diaspora and friendica-over-diaspora communications.
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
call_hooks('queue_deliver',$arr);
if($arr['handled'])
return;
if ($outq['outq_driver'] === 'post') {
$result = z_post_url($outq['outq_posturl'], $outq['outq_msg']);
if ($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
if ($base) {
q(
"update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($base)
);
}
q(
"update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('accepted for delivery'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
self::remove($outq['outq_hash']);
// "post" queue driver - used for diaspora and friendica-over-diaspora communications.
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
if($outq['outq_driver'] === 'post') {
$result = z_post_url($outq['outq_posturl'],$outq['outq_msg']);
if($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
if($base) {
q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($base)
);
}
q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('accepted for delivery'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
self::remove($outq['outq_hash']);
if (!$immediate) {
$x = q(
"select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
$piled_up = [];
if ($x) {
foreach ($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if ($piled_up) {
// call do_delivery() with the force flag
do_delivery($piled_up, true);
}
}
} else {
logger('deliver: queue post returned ' . $result['return_code']
. ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
self::update($outq['outq_hash'], 10);
}
return;
}
if(! $immediate) {
$x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
if ($outq['outq_driver'] === 'asfetch') {
$channel = channelx_by_n($outq['outq_channel']);
if (!$channel) {
logger('missing channel: ' . $outq['outq_channel']);
return;
}
$piled_up = [];
if($x) {
foreach($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if($piled_up) {
// call do_delivery() with the force flag
do_delivery($piled_up, true);
}
}
}
else {
logger('deliver: queue post returned ' . $result['return_code']
. ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
self::update($outq['outq_hash'],10);
}
return;
}
if (!ActivityStreams::is_url($outq['outq_posturl'])) {
logger('fetch item is not url: ' . $outq['outq_posturl']);
self::remove($outq['outq_hash']);
return;
}
if ($outq['outq_driver'] === 'asfetch') {
$j = Activity::fetch($outq['outq_posturl'], $channel);
if ($j) {
$AS = new ActivityStreams($j, null, true);
if ($AS->is_valid() && isset($AS->data['type'])) {
if (ActivityStreams::is_an_actor($AS->data['type'])) {
Activity::actor_store($AS->data['id'], $AS->data);
}
if (strpos($AS->data['type'], 'Collection') !== false) {
// we are probably fetching a collection already - and do not support collection recursion at this time
self::remove($outq['outq_hash']);
return;
}
$item = Activity::decode_note($AS, true);
if ($item) {
Activity::store($channel, $channel['channnel_hash'], $AS, $item, true, true);
}
}
logger('deliver: queue fetch success from ' . $outq['outq_posturl'], LOGGER_DEBUG);
self::remove($outq['outq_hash']);
$channel = channelx_by_n($outq['outq_channel']);
if (! $channel) {
logger('missing channel: ' . $outq['outq_channel']);
return;
}
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
if (! ActivityStreams::is_url($outq['outq_posturl'])) {
logger('fetch item is not url: ' . $outq['outq_posturl']);
self::remove($outq['outq_hash']);
return;
}
if (!$immediate) {
$x = q(
"select outq_hash from outq where outq_driver = 'asfetch' and outq_channel = %d and outq_delivered = 0",
dbesc($outq['outq_channel'])
);
$j = Activity::fetch($outq['outq_posturl'],$channel);
if ($j) {
$AS = new ActivityStreams($j, null, true);
if ($AS->is_valid() && isset($AS->data['type'])) {
if (ActivityStreams::is_an_actor($AS->data['type'])) {
Activity::actor_store($AS->data['id'],$AS->data);
}
if (strpos($AS->data['type'],'Collection') !== false) {
// we are probably fetching a collection already - and do not support collection recursion at this time
self::remove($outq['outq_hash']);
return;
}
$item = Activity::decode_note($AS,true);
if ($item) {
Activity::store($channel,$channel['channnel_hash'],$AS,$item,true,true);
}
}
logger('deliver: queue fetch success from ' . $outq['outq_posturl'], LOGGER_DEBUG);
self::remove($outq['outq_hash']);
$piled_up = [];
if ($x) {
foreach ($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if ($piled_up) {
do_delivery($piled_up, true);
}
}
} else {
logger('deliver: queue fetch failed' . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
self::update($outq['outq_hash'], 10);
}
return;
}
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
if (! $immediate) {
$x = q("select outq_hash from outq where outq_driver = 'asfetch' and outq_channel = %d and outq_delivered = 0",
dbesc($outq['outq_channel'])
);
$piled_up = [];
if ($x) {
foreach ($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if ($piled_up) {
do_delivery($piled_up,true);
}
}
}
else {
logger('deliver: queue fetch failed' . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
self::update($outq['outq_hash'],10);
}
return;
}
if($outq['outq_driver'] === 'activitypub') {
$channel = channelx_by_n($outq['outq_channel']);
if (! $channel) {
logger('missing channel: ' . $outq['outq_channel']);
return;
}
if ($outq['outq_driver'] === 'activitypub') {
$channel = channelx_by_n($outq['outq_channel']);
if (!$channel) {
logger('missing channel: ' . $outq['outq_channel']);
return;
}
$retries = 0;
$m = parse_url($outq['outq_posturl']);
$retries = 0;
$m = parse_url($outq['outq_posturl']);
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$ret = $outq['outq_msg'];
logger('ActivityPub send: ' . jindent($ret), LOGGER_DATA);
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['Host'] = $m['host'];
$headers['(request-target)'] = 'post ' . get_request_string($outq['outq_posturl']);
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
$ret = $outq['outq_msg'];
logger('ActivityPub send: ' . jindent($ret), LOGGER_DATA);
$headers['Date'] = datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['Host'] = $m['host'];
$headers['(request-target)'] = 'post ' . get_request_string($outq['outq_posturl']);
$xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
if(strpos($outq['outq_posturl'],'http') !== 0) {
logger('bad url: ' . $outq['outq_posturl']);
self::remove($outq['outq_hash']);
}
$xhead = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel));
if (strpos($outq['outq_posturl'], 'http') !== 0) {
logger('bad url: ' . $outq['outq_posturl']);
self::remove($outq['outq_hash']);
}
$result = z_post_url($outq['outq_posturl'],$outq['outq_msg'],$retries,[ 'headers' => $xhead ]);
$result = z_post_url($outq['outq_posturl'], $outq['outq_msg'], $retries, ['headers' => $xhead]);
if($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
if($base) {
q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($base)
);
}
q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('accepted for delivery'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
self::remove($outq['outq_hash']);
if ($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
if ($base) {
q(
"update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
dbesc(datetime_convert()),
dbesc($base)
);
}
q(
"update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('accepted for delivery'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
self::remove($outq['outq_hash']);
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
// server is responding - see if anything else is going to this destination and is piled up
// and try to send some more. We're relying on the fact that do_delivery() results in an
// immediate delivery otherwise we could get into a queue loop.
if(! $immediate) {
$x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
if (!$immediate) {
$x = q(
"select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
$piled_up = [];
if($x) {
foreach($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if($piled_up) {
do_delivery($piled_up,true);
}
}
}
else {
if ($result['return_code'] >= 300) {
q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('delivery rejected' . ' ' . $result['return_code']),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
}
else {
$dr = q("select * from dreport where dreport_queue = '%s'",
dbesc($outq['outq_hash'])
);
if ($dr) {
// update every queue entry going to this site with the most recent communication error
q("update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc($dr[0]['dreport_site'])
);
}
}
logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
self::update($outq['outq_hash'],10);
}
return;
}
$piled_up = [];
if ($x) {
foreach ($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if ($piled_up) {
do_delivery($piled_up, true);
}
}
} else {
if ($result['return_code'] >= 300) {
q(
"update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc('delivery rejected' . ' ' . $result['return_code']),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
} else {
$dr = q(
"select * from dreport where dreport_queue = '%s'",
dbesc($outq['outq_hash'])
);
if ($dr) {
// update every queue entry going to this site with the most recent communication error
q(
"update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc($dr[0]['dreport_site'])
);
}
}
logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
self::update($outq['outq_hash'], 10);
}
return;
}
// normal zot delivery
// normal zot delivery
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
if($outq['outq_posturl'] === z_root() . '/zot') {
// local delivery
$zot = new \Zotlabs\Zot6\Receiver(new \Zotlabs\Zot6\Zot6Handler(),$outq['outq_notify']);
$result = $zot->run();
logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA);
logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']);
Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq);
if ($outq['outq_posturl'] === z_root() . '/zot') {
// local delivery
$zot = new Receiver(new Zot6Handler(), $outq['outq_notify']);
$result = $zot->run();
logger('returned_json: ' . json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DATA);
logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']);
Libzot::process_response($outq['outq_posturl'], ['success' => true, 'body' => json_encode($result)], $outq);
if(! $immediate) {
$x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
if (!$immediate) {
$x = q(
"select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0",
dbesc($outq['outq_posturl'])
);
$piled_up = [];
if($x) {
foreach($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if($piled_up) {
do_delivery($piled_up,true);
}
}
}
else {
logger('remote');
$channel = null;
$piled_up = [];
if ($x) {
foreach ($x as $xx) {
$piled_up[] = $xx['outq_hash'];
}
}
if ($piled_up) {
do_delivery($piled_up, true);
}
}
} else {
logger('remote');
$channel = null;
if($outq['outq_channel']) {
$channel = channelx_by_n($outq['outq_channel'],true);
}
if ($outq['outq_channel']) {
$channel = channelx_by_n($outq['outq_channel'], true);
}
$host_crypto = null;
$host_crypto = null;
if($channel && $base) {
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_network in ('nomad','zot6') order by hubloc_id desc limit 1",
dbesc($base)
);
if($h) {
$host_crypto = $h[0];
}
}
$msg = $outq['outq_notify'];
if ($channel && $base) {
$h = q(
"select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_network in ('zot6','nomad') order by hubloc_id desc limit 1",
dbesc($base)
);
if ($h) {
$host_crypto = $h[0];
}
}
$msg = $outq['outq_notify'];
if ($outq['outq_driver'] === 'nomad') {
$result = Libzot::nomad($outq['outq_posturl'],$msg,$channel,$host_crypto);
@ -471,27 +491,27 @@ class Queue {
$result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
}
if($result['success']) {
logger('deliver: remote nomad/zot delivery succeeded to ' . $outq['outq_posturl']);
Libzot::process_response($outq['outq_posturl'],$result, $outq);
}
else {
$dr = q("select * from dreport where dreport_queue = '%s'",
dbesc($outq['outq_hash'])
);
if ($result['success']) {
logger('deliver: remote nomad/zot delivery succeeded to ' . $outq['outq_posturl']);
Libzot::process_response($outq['outq_posturl'], $result, $outq);
} else {
$dr = q(
"select * from dreport where dreport_queue = '%s'",
dbesc($outq['outq_hash'])
);
// update every queue entry going to this site with the most recent communication error
q("update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc($dr[0]['dreport_site'])
);
// update every queue entry going to this site with the most recent communication error
q(
"update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc($dr[0]['dreport_site'])
);
logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA);
self::update($outq['outq_hash'],10);
}
}
return;
}
logger('deliver: remote nomad/zot delivery failed to ' . $outq['outq_posturl']);
logger('deliver: remote nomad/zot delivery fail data: ' . print_r($result, true), LOGGER_DATA);
self::update($outq['outq_hash'], 10);
}
}
return;
}
}

View file

@ -8,22 +8,26 @@ namespace Zotlabs\Lib;
* @see XConfig
*/
class SConfig {
class SConfig
{
static public function Load($server_id) {
return XConfig::Load('s_' . $server_id);
}
public static function Load($server_id)
{
return XConfig::Load('s_' . $server_id);
}
static public function Get($server_id,$family,$key,$default = false) {
return XConfig::Get('s_' . $server_id,$family,$key, $default);
}
public static function Get($server_id, $family, $key, $default = false)
{
return XConfig::Get('s_' . $server_id, $family, $key, $default);
}
static public function Set($server_id,$family,$key,$value) {
return XConfig::Set('s_' . $server_id,$family,$key,$value);
}
static public function Delete($server_id,$family,$key) {
return XConfig::Delete('s_' . $server_id,$family,$key);
}
public static function Set($server_id, $family, $key, $value)
{
return XConfig::Set('s_' . $server_id, $family, $key, $value);
}
public static function Delete($server_id, $family, $key)
{
return XConfig::Delete('s_' . $server_id, $family, $key);
}
}

View file

@ -6,222 +6,227 @@ use App;
use Zotlabs\Daemon\Run;
use Zotlabs\Lib\Libsync;
class Share {
class Share
{
private $item = null;
private $item = null;
public function __construct($post_id) {
public function __construct($post_id)
{
if (! $post_id) {
return;
}
if (! $post_id) {
return;
}
if (is_array($post_id)) {
$this->item = $post_id;
return;
}
if (is_array($post_id)) {
$this->item = $post_id;
return;
}
if (! (local_channel() || remote_channel())) {
return;
}
if (! (local_channel() || remote_channel())) {
return;
}
$r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1",
intval($post_id)
);
if (! $r) {
return;
}
$r = q(
"SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1",
intval($post_id)
);
if (! $r) {
return;
}
if (($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss')) {
return;
}
if (($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss')) {
return;
}
$sql_extra = item_permissions_sql($r[0]['uid']);
$sql_extra = item_permissions_sql($r[0]['uid']);
$r = q("select * from item where id = %d $sql_extra",
intval($post_id)
);
if (! $r) {
return;
}
$r = q(
"select * from item where id = %d $sql_extra",
intval($post_id)
);
if (! $r) {
return;
}
if (! in_array($r[0]['mimetype'], [ 'text/bbcode', 'text/x-multicode' ])) {
return;
}
if (! in_array($r[0]['mimetype'], [ 'text/bbcode', 'text/x-multicode' ])) {
return;
}
/** @FIXME eventually we want to post remotely via rpost on your home site */
// When that works remove this next bit:
/** @FIXME eventually we want to post remotely via rpost on your home site */
// When that works remove this next bit:
if (! local_channel()) {
return;
}
if (! local_channel()) {
return;
}
xchan_query($r);
xchan_query($r);
$this->item = array_shift($r);
$this->item = array_shift($r);
$arr = [];
$arr = [];
$owner_uid = $this->item['uid'];
$owner_aid = $this->item['aid'];
$owner_uid = $this->item['uid'];
$owner_aid = $this->item['aid'];
$channel = channelx_by_n($this->item['uid']);
$observer = App::get_observer();
$channel = channelx_by_n($this->item['uid']);
$observer = App::get_observer();
$can_comment = false;
if ((array_key_exists('owner',$this->item)) && intval($this->item['owner']['abook_self'])) {
$can_comment = perm_is_allowed($this->item['uid'],$observer['xchan_hash'],'post_comments');
}
else {
$can_comment = can_comment_on_post($observer['xchan_hash'],$this->item);
}
$can_comment = false;
if ((array_key_exists('owner', $this->item)) && intval($this->item['owner']['abook_self'])) {
$can_comment = perm_is_allowed($this->item['uid'], $observer['xchan_hash'], 'post_comments');
} else {
$can_comment = can_comment_on_post($observer['xchan_hash'], $this->item);
}
if (! $can_comment) {
return;
}
if (! $can_comment) {
return;
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['owner_xchan'])
);
$r = q(
"select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['owner_xchan'])
);
if ($r) {
$thread_owner = array_shift($r);
}
else {
return;
}
if ($r) {
$thread_owner = array_shift($r);
} else {
return;
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['author_xchan'])
);
if ($r) {
$item_author = array_shift($r);
}
else {
return;
}
$r = q(
"select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['author_xchan'])
);
if ($r) {
$item_author = array_shift($r);
} else {
return;
}
if ($item_author['network'] === 'activitypub') {
if ($item_author['network'] === 'activitypub') {
// for Mastodon compatibility, send back an ActivityPub Announce activity.
// We don't need or want these on our own network as there is no mechanism for providing
// a fair-use defense to copyright claims and frivolous lawsuits.
// for Mastodon compatibility, send back an ActivityPub Announce activity.
// We don't need or want these on our own network as there is no mechanism for providing
// a fair-use defense to copyright claims and frivolous lawsuits.
$arr['aid'] = $owner_aid;
$arr['uid'] = $owner_uid;
$arr['aid'] = $owner_aid;
$arr['uid'] = $owner_uid;
$arr['item_origin'] = 1;
$arr['item_wall'] = $this->item['item_wall'];
$arr['uuid'] = new_uuid();
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
$arr['mid'] = str_replace('/item/', '/activity/', $arr['mid']);
$arr['parent_mid'] = $this->item['mid'];
$arr['item_origin'] = 1;
$arr['item_wall'] = $this->item['item_wall'];
$arr['uuid'] = new_uuid();
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
$arr['mid'] = str_replace('/item/','/activity/',$arr['mid']);
$arr['parent_mid'] = $this->item['mid'];
$mention = '@[zrl=' . $this->item['author']['xchan_url'] . ']' . $this->item['author']['xchan_name'] . '[/zrl]';
$arr['body'] = sprintf(t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $this->item['obj_type']);
$mention = '@[zrl=' . $this->item['author']['xchan_url'] . ']' . $this->item['author']['xchan_name'] . '[/zrl]';
$arr['body'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $this->item['obj_type']);
$arr['author_xchan'] = $observer['xchan_hash'];
$arr['owner_xchan'] = $this->item['author_xchan'];
$arr['obj'] = $this->item['obj'];
$arr['obj_type'] = $this->item['obj_type'];
$arr['verb'] = 'Announce';
$arr['author_xchan'] = $observer['xchan_hash'];
$arr['owner_xchan'] = $this->item['author_xchan'];
$arr['obj'] = $this->item['obj'];
$arr['obj_type'] = $this->item['obj_type'];
$arr['verb'] = 'Announce';
$post = item_store($arr);
$post = item_store($arr);
$post_id = $post['item_id'];
$post_id = $post['item_id'];
$arr['id'] = $post_id;
$arr['id'] = $post_id;
call_hooks('post_local_end', $arr);
call_hooks('post_local_end', $arr);
$r = q(
"select * from item where id = %d",
intval($post_id)
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0], true) ] ]);
}
$r = q("select * from item where id = %d",
intval($post_id)
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
Run::Summon([ 'Notifier','like',$post_id ]);
}
Run::Summon([ 'Notifier','like',$post_id ]);
}
return;
}
return;
public function obj()
{
$obj = [];
}
if (! $this->item) {
return $obj;
}
public function obj() {
$obj = [];
$obj['type'] = $this->item['obj_type'];
$obj['id'] = $this->item['mid'];
$obj['content'] = bbcode($this->item['body']);
$obj['source'] = [
'mediaType' => $this->item['mimetype'],
'content' => $this->item['body']
];
if(! $this->item)
return $obj;
$obj['name'] = $this->item['title'];
$obj['published'] = $this->item['created'];
$obj['updated'] = $this->item['edited'];
$obj['attributedTo'] = ((strpos($this->item['author']['xchan_hash'], 'http') === 0)
? $this->item['author']['xchan_hash']
: $this->item['author']['xchan_url']);
$obj['type'] = $this->item['obj_type'];
$obj['id'] = $this->item['mid'];
$obj['content'] = bbcode($this->item['body']);
$obj['source'] = [
'mediaType' => $this->item['mimetype'],
'content' => $this->item['body']
];
return $obj;
}
$obj['name'] = $this->item['title'];
$obj['published'] = $this->item['created'];
$obj['updated'] = $this->item['edited'];
$obj['attributedTo'] = ((strpos($this->item['author']['xchan_hash'],'http') === 0)
? $this->item['author']['xchan_hash']
: $this->item['author']['xchan_url']);
public function bbcode()
{
$bb = EMPTY_STR;
return $obj;
}
if (! $this->item) {
return $bb;
}
public function bbcode() {
$bb = EMPTY_STR;
if (! $this->item['author']) {
$author = q(
"select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['author_xchan'])
);
if ($author) {
$this->item['author'] = array_shift($author);
}
}
if (! $this->item)
return $bb;
$special_object = (in_array($this->item['obj_type'], [ ACTIVITY_OBJ_PHOTO, 'Event', 'Question' ]) ? true : false);
if ($special_object) {
$object = json_decode($this->item['obj'], true);
$special = (($object['source']) ? $object['source']['content'] : $object['body']);
}
if (! $this->item['author']) {
$author = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($this->item['author_xchan'])
);
if ($author) {
$this->item['author'] = array_shift($author);
}
}
$special_object = (in_array($this->item['obj_type'], [ ACTIVITY_OBJ_PHOTO, 'Event', 'Question' ]) ? true : false);
if($special_object) {
$object = json_decode($this->item['obj'],true);
$special = (($object['source']) ? $object['source']['content'] : $object['body']);
}
if (strpos($this->item['body'], "[/share]") !== false) {
$pos = strpos($this->item['body'], "[share");
$bb = substr($this->item['body'], $pos);
} else {
$bb = "[share author='" . urlencode($this->item['author']['xchan_name']).
"' profile='" . $this->item['author']['xchan_url'] .
"' portable_id='" . $this->item['author']['xchan_hash'] .
"' avatar='" . $this->item['author']['xchan_photo_s'] .
"' link='" . $this->item['plink'] .
if (strpos($this->item['body'], "[/share]") !== false) {
$pos = strpos($this->item['body'], "[share");
$bb = substr($this->item['body'], $pos);
} else {
$bb = "[share author='" . urlencode($this->item['author']['xchan_name']) .
"' profile='" . $this->item['author']['xchan_url'] .
"' portable_id='" . $this->item['author']['xchan_hash'] .
"' avatar='" . $this->item['author']['xchan_photo_s'] .
"' link='" . $this->item['plink'] .
"' auth='" . (in_array($this->item['author']['network'],['nomad','zot6']) ? 'true' : 'false') .
"' posted='" . $this->item['created'] .
"' message_id='" . $this->item['mid'] .
"']";
if ($this->item['title']) {
$bb .= '[b]'.$this->item['title'].'[/b]'."\r\n";
}
if ($this->item['summary']) {
$bb .= $this->item['summary'] . "\r\n";
}
"' posted='" . $this->item['created'] .
"' message_id='" . $this->item['mid'] .
"']";
if ($this->item['title']) {
$bb .= '[b]' . $this->item['title'] . '[/b]' . "\r\n";
}
if ($this->item['summary']) {
$bb .= $this->item['summary'] . "\r\n";
}
$bb .= (($special_object) ? $special . "\r\n" . $this->item['body'] : $this->item['body']);
$bb .= "[/share]";
}
return $bb;
}
$bb .= (($special_object) ? $special . "\r\n" . $this->item['body'] : $this->item['body']);
$bb .= "[/share]";
}
return $bb;
}
}

View file

@ -16,141 +16,145 @@ use Zotlabs\Lib\Config;
* @license http://opensource.org/licenses/mit-license.php The MIT License
* @package svgsanitizer
*/
class SvgSanitizer
{
class SvgSanitizer {
private $xmlDoc; // PHP XML DOMDocument
private $xmlDoc; // PHP XML DOMDocument
private $removedattrs = [];
private $removedattrs = [];
private static $allowed_functions = ['matrix', 'url', 'translate', 'rgb'];
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
// defines the allowlist of elements and attributes allowed.
private static $allowlist = [
'a' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title'],
'circle' => ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'clipPath' => ['class', 'clipPathUnits', 'id'],
'defs' => [],
'style' => ['type'],
'desc' => [],
'ellipse' => ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'feGaussianBlur' => ['class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation'],
'filter' => ['class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
'foreignObject' => ['class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y'],
'g' => ['class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'],
'image' => ['class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y'],
'line' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2'],
'linearGradient' => ['class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'],
'marker' => ['id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox'],
'mask' => ['class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
'metadata' => ['class', 'id'],
'path' => ['class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'pattern' => ['class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'],
'polygon' => ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'polyline' => ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'radialGradient' => ['class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
'rect' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y'],
'stop' => ['class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage'],
'svg' => ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y'],
'switch' => ['class', 'id', 'requiredFeatures', 'systemLanguage'],
'symbol' => ['class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox'],
'text' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y'],
'textPath' => ['class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href'],
'title' => [],
'tspan' => ['class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y'],
'use' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y'],
];
// defines the allowlist of elements and attributes allowed.
private static $allowlist = [
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
'defs' => [ ],
'style' => [ 'type' ],
'desc' => [ ],
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
'metadata' => [ 'class', 'id' ],
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
'title' => [ ],
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
];
public function __construct()
{
$this->xmlDoc = new DOMDocument('1.0', 'UTF-8');
$this->xmlDoc->preserveWhiteSpace = false;
libxml_use_internal_errors(true);
}
function __construct() {
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
$this->xmlDoc->preserveWhiteSpace = false;
libxml_use_internal_errors(true);
}
// load XML SVG
public function load($file)
{
$this->xmlDoc->load($file);
}
// load XML SVG
function load($file) {
$this->xmlDoc->load($file);
}
public function loadXML($str)
{
if (!$str) {
logger('loadxml: empty input', LOGGER_DEBUG);
return false;
}
if (!$this->xmlDoc->loadXML($str)) {
logger('loadxml: ' . print_r(array_slice(libxml_get_errors(), 0, Config::Get('system', 'svg_backtrace_limit', 3)), true), LOGGER_DEBUG);
return false;
}
return true;
}
function loadXML($str) {
if (! $str) {
logger('loadxml: empty input', LOGGER_DEBUG);
return false;
}
if (! $this->xmlDoc->loadXML($str)) {
logger('loadxml: ' . print_r(array_slice(libxml_get_errors(),0,Config::Get('system','svg_backtrace_limit',3)),true), LOGGER_DEBUG);
return false;
}
return true;
}
public function sanitize()
{
// all elements in xml doc
$allElements = $this->xmlDoc->getElementsByTagName('*');
function sanitize()
{
// all elements in xml doc
$allElements = $this->xmlDoc->getElementsByTagName('*');
// loop through all elements
for ($i = 0; $i < $allElements->length; $i++) {
$this->removedattrs = [];
// loop through all elements
for($i = 0; $i < $allElements->length; $i++)
{
$this->removedattrs = [];
$currentNode = $allElements->item($i);
$currentNode = $allElements->item($i);
// logger('current_node: ' . print_r($currentNode,true));
// logger('current_node: ' . print_r($currentNode,true));
// array of allowed attributes in specific element
$allowlist_attr_arr = self::$allowlist[$currentNode->tagName];
// array of allowed attributes in specific element
$allowlist_attr_arr = self::$allowlist[$currentNode->tagName];
// does element exist in allowlist?
if (isset($allowlist_attr_arr)) {
$total = $currentNode->attributes->length;
// does element exist in allowlist?
if(isset($allowlist_attr_arr)) {
$total = $currentNode->attributes->length;
for ($x = 0; $x < $total; $x++) {
// get attributes name
$attrName = $currentNode->attributes->item($x)->nodeName;
for($x = 0; $x < $total; $x++) {
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
$matches = false;
// get attributes name
$attrName = $currentNode->attributes->item($x)->nodeName;
// check if attribute isn't in allowlist
if (!in_array($attrName, $allowlist_attr_arr)) {
$this->removedattrs[] = $attrName;
} // check for disallowed functions
elseif (
preg_match_all(
'/([a-zA-Z0-9]+)[\s]*\(/',
$currentNode->attributes->item($x)->textContent,
$matches,
PREG_SET_ORDER
)
) {
if ($attrName === 'text') {
continue;
}
foreach ($matches as $match) {
if (!in_array($match[1], self::$allowed_functions)) {
logger('queue_remove_function: ' . $match[1], LOGGER_DEBUG);
$this->removedattrs[] = $attrName;
}
}
}
}
if ($this->removedattrs) {
foreach ($this->removedattrs as $attr) {
$currentNode->removeAttribute($attr);
logger('removed: ' . $attr, LOGGER_DEBUG);
}
}
} // else remove element
else {
logger('remove_node: ' . print_r($currentNode, true));
$currentNode->parentNode->removeChild($currentNode);
}
}
return true;
}
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
$matches = false;
// check if attribute isn't in allowlist
if(! in_array($attrName, $allowlist_attr_arr)) {
$this->removedattrs[] = $attrName;
}
// check for disallowed functions
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
if ($attrName === 'text') {
continue;
}
foreach ($matches as $match) {
if(! in_array($match[1],self::$allowed_functions)) {
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
$this->removedattrs[] = $attrName;
}
}
}
}
if ($this->removedattrs) {
foreach ($this->removedattrs as $attr) {
$currentNode->removeAttribute($attr);
logger('removed: ' . $attr, LOGGER_DEBUG);
}
}
}
// else remove element
else {
logger('remove_node: ' . print_r($currentNode,true));
$currentNode->parentNode->removeChild($currentNode);
}
}
return true;
}
function saveSVG() {
$this->xmlDoc->formatOutput = true;
return($this->xmlDoc->saveXML());
}
public function saveSVG()
{
$this->xmlDoc->formatOutput = true;
return ($this->xmlDoc->saveXML());
}
}

View file

@ -4,116 +4,145 @@ namespace Zotlabs\Lib;
use App;
class System {
class System
{
static public function get_platform_name() {
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('platform_name',App::$config['system']))
return App::$config['system']['platform_name'];
return PLATFORM_NAME;
}
public static function get_platform_name()
{
if (is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('platform_name', App::$config['system'])) {
return App::$config['system']['platform_name'];
}
return PLATFORM_NAME;
}
static public function get_site_name() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['sitename'])
return App::$config['system']['sitename'];
return '';
}
public static function get_site_name()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['sitename']) {
return App::$config['system']['sitename'];
}
return '';
}
static public function get_banner() {
public static function get_banner()
{
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('banner',App::$config['system']) && App::$config['system']['banner']) {
return App::$config['system']['banner'];
if (is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('banner', App::$config['system']) && App::$config['system']['banner']) {
return App::$config['system']['banner'];
}
return self::get_site_name();
}
public static function get_project_icon()
{
if (is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('icon', App::$config['system'])) {
return App::$config['system']['icon'];
}
return z_root() . '/images/' . PLATFORM_NAME . '-64.png';
}
public static function get_project_favicon()
{
if (is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('favicon', App::$config['system'])) {
return App::$config['system']['favicon'];
}
return z_root() . '/images/' . PLATFORM_NAME . '.ico';
}
public static function get_project_version()
{
if (array_path_exists('system/hide_version', App::$config) && intval(App::$config['system']['hide_version'])) {
return '';
}
if (is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('std_version', App::$config['system'])) {
return App::$config['system']['std_version'];
}
return self::get_std_version();
}
public static function get_update_version()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['hide_version']) {
return EMPTY_STR;
}
return DB_UPDATE_VERSION;
}
public static function get_notify_icon()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['email_notify_icon_url']) {
return App::$config['system']['email_notify_icon_url'];
}
return self::get_project_icon();
}
public static function get_site_icon()
{
if (is_array(App::$config) && is_array(App::$config['system']) && isset(App::$config['system']['site_icon_url']) && App::$config['system']['site_icon_url']) {
return App::$config['system']['site_icon_url'];
}
return self::get_project_icon();
}
public static function get_site_favicon()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['site_favicon_url']) {
return App::$config['system']['site_favicon_url'];
}
return self::get_project_favicon();
}
public static function get_project_link()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_link']) {
return App::$config['system']['project_link'];
}
return 'https://zotlabs.com/' . PLATFORM_NAME;
}
public static function get_project_srclink()
{
if (is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_srclink']) {
return App::$config['system']['project_srclink'];
}
if (PLATFORM_NAME === 'streams') {
return 'https://codeberg.org/streams/' . PLATFORM_NAME;
}
return self::get_site_name();
}
static public function get_project_icon() {
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('icon',App::$config['system'])) {
return App::$config['system']['icon'];
}
return z_root() . '/images/' . PLATFORM_NAME . '-64.png';
}
return 'https://codeberg.org/zot/' . PLATFORM_NAME;
}
static public function get_project_favicon() {
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('favicon',App::$config['system'])) {
return App::$config['system']['favicon'];
}
return z_root() . '/images/' . PLATFORM_NAME . '.ico';
}
public static function ebs()
{
if (defined('EBSSTATE')) {
return EBSSTATE;
}
return 'armed';
}
public static function get_zot_revision()
{
$x = [ 'revision' => ZOT_REVISION ];
call_hooks('zot_revision', $x);
return $x['revision'];
}
static public function get_project_version() {
if(array_path_exists('system/hide_version', App::$config) && intval(App::$config['system']['hide_version']))
return '';
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('std_version',App::$config['system']))
return App::$config['system']['std_version'];
public static function get_std_version()
{
if (defined('STD_VERSION')) {
return STD_VERSION;
}
return '0.0.0';
}
return self::get_std_version();
}
public static function compatible_project($p)
{
static public function get_update_version() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['hide_version'])
return EMPTY_STR;
return DB_UPDATE_VERSION;
}
static public function get_notify_icon() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['email_notify_icon_url'])
return App::$config['system']['email_notify_icon_url'];
return self::get_project_icon();
}
static public function get_site_icon() {
if(is_array(App::$config) && is_array(App::$config['system']) && isset(App::$config['system']['site_icon_url']) && App::$config['system']['site_icon_url'])
return App::$config['system']['site_icon_url'];
return self::get_project_icon();
}
static public function get_site_favicon() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['site_favicon_url'])
return App::$config['system']['site_favicon_url'];
return self::get_project_favicon();
}
static public function get_project_link() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_link'])
return App::$config['system']['project_link'];
return 'https://zotlabs.com/' . PLATFORM_NAME;
}
static public function get_project_srclink() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_srclink'])
return App::$config['system']['project_srclink'];
if (PLATFORM_NAME === 'streams') {
return 'https://codeberg.org/streams/' . PLATFORM_NAME;
}
return 'https://codeberg.org/zot/' . PLATFORM_NAME;
}
static public function ebs() {
if(defined('EBSSTATE')) {
return EBSSTATE;
}
return 'armed';
}
static public function get_zot_revision() {
$x = [ 'revision' => ZOT_REVISION ];
call_hooks('zot_revision',$x);
return $x['revision'];
}
static public function get_std_version() {
if(defined('STD_VERSION'))
return STD_VERSION;
return '0.0.0';
}
static public function compatible_project($p) {
if (in_array(strtolower($p),['hubzilla', 'zap', 'red', 'misty', 'mistpark', 'redmatrix', 'osada', 'roadhouse', 'streams'])) {
return true;
}
return false;
}
if (in_array(strtolower($p), ['hubzilla', 'zap', 'red', 'misty', 'mistpark', 'redmatrix', 'osada', 'roadhouse','streams'])) {
return true;
}
return false;
}
}

File diff suppressed because it is too large Load diff

View file

@ -2,52 +2,62 @@
namespace Zotlabs\Lib;
class ThreadListener {
class ThreadListener
{
static public function store($target_id,$portable_id,$ltype = 0) {
$x = self::fetch($target_id,$portable_id,$ltype = 0);
if(! $x) {
$r = q("insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ",
dbesc($target_id),
dbesc($portable_id),
intval($ltype)
);
}
}
public static function store($target_id, $portable_id, $ltype = 0)
{
$x = self::fetch($target_id, $portable_id, $ltype = 0);
if (! $x) {
$r = q(
"insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ",
dbesc($target_id),
dbesc($portable_id),
intval($ltype)
);
}
}
static public function fetch($target_id,$portable_id,$ltype = 0) {
$x = q("select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1",
dbesc($target_id),
dbesc($portable_id),
intval($ltype)
);
if($x) {
return $x[0];
}
return false;
}
public static function fetch($target_id, $portable_id, $ltype = 0)
{
$x = q(
"select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1",
dbesc($target_id),
dbesc($portable_id),
intval($ltype)
);
if ($x) {
return $x[0];
}
return false;
}
static public function fetch_by_target($target_id,$ltype = 0) {
$x = q("select * from listeners where target_id = '%s' and ltype = %d",
dbesc($target_id),
intval($ltype)
);
public static function fetch_by_target($target_id, $ltype = 0)
{
$x = q(
"select * from listeners where target_id = '%s' and ltype = %d",
dbesc($target_id),
intval($ltype)
);
return $x;
}
return $x;
}
static public function delete_by_target($target_id, $ltype = 0) {
return q("delete from listeners where target_id = '%s' and ltype = %d",
dbesc($target_id),
intval($ltype)
);
}
static public function delete_by_pid($portable_id, $ltype = 0) {
return q("delete from listeners where portable_id = '%s' and ltype = %d",
dbesc($portable_id),
intval($ltype)
);
}
public static function delete_by_target($target_id, $ltype = 0)
{
return q(
"delete from listeners where target_id = '%s' and ltype = %d",
dbesc($target_id),
intval($ltype)
);
}
public static function delete_by_pid($portable_id, $ltype = 0)
{
return q(
"delete from listeners where portable_id = '%s' and ltype = %d",
dbesc($portable_id),
intval($ltype)
);
}
}

View file

@ -1,7 +1,11 @@
<?php /** @file */
<?php
/** @file */
namespace Zotlabs\Lib;
use App;
require_once('boot.php');
require_once('include/text.php');
@ -10,240 +14,257 @@ require_once('include/text.php');
*
*/
class ThreadStream {
class ThreadStream
{
private $threads = [];
private $mode = null;
private $observer = null;
private $writable = false;
private $commentable = false;
private $uploadable = false;
private $profile_owner = 0;
private $preview = false;
private $prepared_item = '';
public $reload = '';
private $cipher = 'AES-128-CCM';
private $threads = [];
private $mode = null;
private $observer = null;
private $writable = false;
private $commentable = false;
private $uploadable = false;
private $profile_owner = 0;
private $preview = false;
private $prepared_item = '';
public $reload = '';
private $cipher = 'AES-128-CCM';
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
// a normal "post" item
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
// a normal "post" item
public function __construct($mode, $preview, $uploadable, $prepared_item = '') {
$this->set_mode($mode);
$this->preview = $preview;
$this->uploadable = $uploadable;
$this->prepared_item = $prepared_item;
$c = ((local_channel()) ? get_pconfig(local_channel(),'system','default_cipher') : '');
if($c)
$this->cipher = $c;
}
public function __construct($mode, $preview, $uploadable, $prepared_item = '')
{
$this->set_mode($mode);
$this->preview = $preview;
$this->uploadable = $uploadable;
$this->prepared_item = $prepared_item;
$c = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'default_cipher') : '');
if ($c) {
$this->cipher = $c;
}
}
/**
* Set the mode we'll be displayed on
*/
private function set_mode($mode) {
if($this->get_mode() == $mode)
return;
/**
* Set the mode we'll be displayed on
*/
private function set_mode($mode)
{
if ($this->get_mode() == $mode) {
return;
}
$this->observer = \App::get_observer();
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
$this->observer = App::get_observer();
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
switch($mode) {
case 'stream':
$this->profile_owner = local_channel();
$this->writable = true;
break;
case 'pubstream':
$this->profile_owner = local_channel();
$this->writable = ((local_channel()) ? true : false);
break;
case 'hq':
$this->profile_owner = local_channel();
$this->writable = true;
break;
case 'channel':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
case 'cards':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->reload = $_SESSION['return_url'];
break;
case 'articles':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->reload = $_SESSION['return_url'];
break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then
// pull some trickery which allows us to re-invoke this function afterward
// it's an ugly hack so @FIXME
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->uploadable = perm_is_allowed($this->profile_owner,$ob_hash,'write_storage');
break;
case 'page':
$this->profile_owner = \App::$profile['uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
default:
logger('[ERROR] Conversation::set_mode : Unhandled mode ('. $mode .').', LOGGER_DEBUG);
return false;
break;
}
$this->mode = $mode;
}
switch ($mode) {
case 'stream':
$this->profile_owner = local_channel();
$this->writable = true;
break;
case 'pubstream':
$this->profile_owner = local_channel();
$this->writable = ((local_channel()) ? true : false);
break;
case 'hq':
$this->profile_owner = local_channel();
$this->writable = true;
break;
case 'channel':
$this->profile_owner = App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments');
break;
case 'cards':
$this->profile_owner = App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments');
$this->reload = $_SESSION['return_url'];
break;
case 'articles':
$this->profile_owner = App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments');
$this->reload = $_SESSION['return_url'];
break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then
// pull some trickery which allows us to re-invoke this function afterward
// it's an ugly hack so @FIXME
$this->writable = perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments');
$this->uploadable = perm_is_allowed($this->profile_owner, $ob_hash, 'write_storage');
break;
case 'page':
$this->profile_owner = App::$profile['uid'];
$this->writable = perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments');
break;
default:
logger('[ERROR] Conversation::set_mode : Unhandled mode (' . $mode . ').', LOGGER_DEBUG);
return false;
break;
}
$this->mode = $mode;
}
/**
* Get mode
*/
public function get_mode() {
return $this->mode;
}
/**
* Get mode
*/
public function get_mode()
{
return $this->mode;
}
/**
* Check if page is writable
*/
public function is_writable() {
return $this->writable;
}
/**
* Check if page is writable
*/
public function is_writable()
{
return $this->writable;
}
public function is_commentable() {
return $this->commentable;
}
public function is_commentable()
{
return $this->commentable;
}
public function is_uploadable() {
return $this->uploadable;
}
public function is_uploadable()
{
return $this->uploadable;
}
/**
* Check if page is a preview
*/
public function is_preview() {
return $this->preview;
}
/**
* Check if page is a preview
*/
public function is_preview()
{
return $this->preview;
}
/**
* Get profile owner
*/
public function get_profile_owner() {
return $this->profile_owner;
}
/**
* Get profile owner
*/
public function get_profile_owner()
{
return $this->profile_owner;
}
public function set_profile_owner($uid) {
$this->profile_owner = $uid;
$mode = $this->get_mode();
$this->mode = null;
$this->set_mode($mode);
}
public function set_profile_owner($uid)
{
$this->profile_owner = $uid;
$mode = $this->get_mode();
$this->mode = null;
$this->set_mode($mode);
}
public function get_observer() {
return $this->observer;
}
public function get_observer()
{
return $this->observer;
}
public function get_cipher() {
return $this->cipher;
}
public function get_cipher()
{
return $this->cipher;
}
/**
* Add a thread to the conversation
*
* Returns:
* _ The inserted item on success
* _ false on failure
*/
public function add_thread($item) {
$item_id = $item->get_id();
if(!$item_id) {
logger('Item has no ID!!', LOGGER_DEBUG, LOG_ERR);
return false;
}
if($this->get_thread($item->get_id())) {
logger('Thread already exists ('. $item->get_id() .').', LOGGER_DEBUG, LOG_WARNING);
return false;
}
/**
* Add a thread to the conversation
*
* Returns:
* _ The inserted item on success
* _ false on failure
*/
public function add_thread($item)
{
$item_id = $item->get_id();
if (!$item_id) {
logger('Item has no ID!!', LOGGER_DEBUG, LOG_ERR);
return false;
}
if ($this->get_thread($item->get_id())) {
logger('Thread already exists (' . $item->get_id() . ').', LOGGER_DEBUG, LOG_WARNING);
return false;
}
/*
* Only add things that will be displayed
*/
/*
* Only add things that will be displayed
*/
if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) {
return false;
}
if (($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'), ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'), ACTIVITY_DISLIKE))) {
return false;
}
$item->set_commentable(false);
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
$item->set_commentable(false);
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
if(! comments_are_now_closed($item->get_data())) {
if(($item->get_data_value('author_xchan') === $ob_hash) || ($item->get_data_value('owner_xchan') === $ob_hash))
$item->set_commentable(true);
if (! comments_are_now_closed($item->get_data())) {
if (($item->get_data_value('author_xchan') === $ob_hash) || ($item->get_data_value('owner_xchan') === $ob_hash)) {
$item->set_commentable(true);
}
if(intval($item->get_data_value('item_nocomment'))) {
$item->set_commentable(false);
}
elseif(! $item->is_commentable()) {
if((array_key_exists('owner',$item->data)) && intval($item->data['owner']['abook_self']))
$item->set_commentable(perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'));
else
$item->set_commentable(can_comment_on_post($ob_hash,$item->data));
}
}
if($this->mode === 'pubstream' && (! local_channel())) {
$item->set_commentable(false);
}
if (intval($item->get_data_value('item_nocomment'))) {
$item->set_commentable(false);
} elseif (! $item->is_commentable()) {
if ((array_key_exists('owner', $item->data)) && intval($item->data['owner']['abook_self'])) {
$item->set_commentable(perm_is_allowed($this->profile_owner, $ob_hash, 'post_comments'));
} else {
$item->set_commentable(can_comment_on_post($ob_hash, $item->data));
}
}
}
if ($this->mode === 'pubstream' && (! local_channel())) {
$item->set_commentable(false);
}
$item->set_conversation($this);
$this->threads[] = $item;
return end($this->threads);
}
$item->set_conversation($this);
$this->threads[] = $item;
return end($this->threads);
}
/**
* Get data in a form usable by a conversation template
*
* We should find a way to avoid using those arguments (at least most of them)
*
* Returns:
* _ The data requested on success
* _ false on failure
*/
public function get_template_data($conv_responses) {
$result = [];
/**
* Get data in a form usable by a conversation template
*
* We should find a way to avoid using those arguments (at least most of them)
*
* Returns:
* _ The data requested on success
* _ false on failure
*/
public function get_template_data($conv_responses)
{
$result = [];
foreach($this->threads as $item) {
foreach ($this->threads as $item) {
if (($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
$item_data = $this->prepared_item;
} else {
$item_data = $item->get_template_data($conv_responses);
}
if (!$item_data) {
logger('Failed to get item template data (' . $item->get_id() . ').', LOGGER_DEBUG, LOG_ERR);
return false;
}
$result[] = $item_data;
}
if(($item->get_data_value('id') == $item->get_data_value('parent')) && $this->prepared_item) {
$item_data = $this->prepared_item;
}
else {
$item_data = $item->get_template_data($conv_responses);
}
if(!$item_data) {
logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR);
return false;
}
$result[] = $item_data;
}
return $result;
}
return $result;
}
/**
* Get a thread based on its item id
*
* Returns:
* _ The found item on success
* _ false on failure
*/
private function get_thread($id)
{
foreach ($this->threads as $item) {
if ($item->get_id() == $id) {
return $item;
}
}
/**
* Get a thread based on its item id
*
* Returns:
* _ The found item on success
* _ false on failure
*/
private function get_thread($id) {
foreach($this->threads as $item) {
if($item->get_id() == $id)
return $item;
}
return false;
}
return false;
}
}

View file

@ -2,62 +2,71 @@
namespace Zotlabs\Lib;
class Verify
{
class Verify {
public static function create($type, $channel_id, $token, $meta)
{
return q(
"insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )",
dbesc($type),
intval($channel_id),
dbesc($token),
dbesc($meta),
dbesc(datetime_convert())
);
}
static function create($type,$channel_id,$token,$meta) {
return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )",
dbesc($type),
intval($channel_id),
dbesc($token),
dbesc($meta),
dbesc(datetime_convert())
);
}
public static function match($type, $channel_id, $token, $meta)
{
$r = q(
"select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1",
dbesc($type),
intval($channel_id),
dbesc($token),
dbesc($meta)
);
if ($r) {
q(
"delete from verify where id = %d",
intval($r[0]['id'])
);
return true;
}
return false;
}
static function match($type,$channel_id,$token,$meta) {
$r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1",
dbesc($type),
intval($channel_id),
dbesc($token),
dbesc($meta)
);
if($r) {
q("delete from verify where id = %d",
intval($r[0]['id'])
);
return true;
}
return false;
}
static function get_meta($type,$channel_id,$token) {
$r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
dbesc($type),
intval($channel_id),
dbesc($token)
);
if($r) {
q("delete from verify where id = %d",
intval($r[0]['id'])
);
return $r[0]['meta'];
}
return false;
}
/**
* @brief Purge entries of a verify-type older than interval.
*
* @param string $type Verify type
* @param string $interval SQL compatible time interval
*/
static function purge($type, $interval) {
q("delete from verify where vtype = '%s' and created < ( %s - INTERVAL %s )",
dbesc($type),
db_utcnow(),
db_quoteinterval($interval)
);
}
public static function get_meta($type, $channel_id, $token)
{
$r = q(
"select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
dbesc($type),
intval($channel_id),
dbesc($token)
);
if ($r) {
q(
"delete from verify where id = %d",
intval($r[0]['id'])
);
return $r[0]['meta'];
}
return false;
}
/**
* @brief Purge entries of a verify-type older than interval.
*
* @param string $type Verify type
* @param string $interval SQL compatible time interval
*/
public static function purge($type, $interval)
{
q(
"delete from verify where vtype = '%s' and created < ( %s - INTERVAL %s )",
dbesc($type),
db_utcnow(),
db_quoteinterval($interval)
);
}
}

View file

@ -6,104 +6,104 @@ namespace Zotlabs\Lib;
* @brief Fetch and return a webfinger for a resource
*
* @param string $resource - The resource
* @return boolean|string false or associative array from result JSON
* @return bool|string false or associative array from result JSON
*/
class Webfinger
{
class Webfinger {
private static $server = EMPTY_STR;
private static $resource = EMPTY_STR;
static private $server = EMPTY_STR;
static private $resource = EMPTY_STR;
public static function exec($resource)
{
static function exec($resource) {
if (!$resource) {
return false;
}
if (! $resource) {
return false;
}
self::parse_resource($resource);
self::parse_resource($resource);
if (!(self::$server && self::$resource)) {
return false;
}
if (! ( self::$server && self::$resource)) {
return false;
}
if (!check_siteallowed(self::$server)) {
logger('denied: ' . self::$server);
return false;
}
if (! check_siteallowed(self::$server)) {
logger('denied: ' . self::$server);
return false;
}
logger('fetching resource: ' . self::$resource . ' from ' . self::$server, LOGGER_DEBUG, LOG_INFO);
logger('fetching resource: ' . self::$resource . ' from ' . self::$server, LOGGER_DEBUG, LOG_INFO);
$url = 'https://' . self::$server . '/.well-known/webfinger?f=&resource=' . self::$resource;
$url = 'https://' . self::$server . '/.well-known/webfinger?f=&resource=' . self::$resource ;
$counter = 0;
$s = z_fetch_url($url, false, $counter, ['headers' => ['Accept: application/jrd+json, */*']]);
$counter = 0;
$s = z_fetch_url($url, false, $counter, [ 'headers' => [ 'Accept: application/jrd+json, */*' ] ]);
if ($s['success']) {
$j = json_decode($s['body'], true);
return ($j);
}
if ($s['success']) {
$j = json_decode($s['body'], true);
return($j);
}
return false;
}
return false;
}
public static function parse_resource($resource)
{
static function parse_resource($resource) {
self::$resource = urlencode($resource);
self::$resource = urlencode($resource);
if (strpos($resource, 'http') === 0) {
$m = parse_url($resource);
if ($m) {
if ($m['scheme'] !== 'https') {
return false;
}
self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
} else {
return false;
}
} elseif (strpos($resource, 'tag:') === 0) {
$arr = explode(':', $resource); // split the tag
$h = explode(',', $arr[1]); // split the host,date
self::$server = $h[0];
} else {
$x = explode('@', $resource);
if (!strlen($x[0])) {
// e.g. @dan@pixelfed.org
array_shift($x);
}
$username = $x[0];
if (count($x) > 1) {
self::$server = $x[1];
} else {
return false;
}
if (strpos($resource, 'acct:') !== 0) {
self::$resource = urlencode('acct:' . $resource);
}
}
}
if (strpos($resource,'http') === 0) {
$m = parse_url($resource);
if ($m) {
if ($m['scheme'] !== 'https') {
return false;
}
self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
}
else {
return false;
}
}
elseif (strpos($resource,'tag:') === 0) {
$arr = explode(':',$resource); // split the tag
$h = explode(',',$arr[1]); // split the host,date
self::$server = $h[0];
}
else {
$x = explode('@',$resource);
if (! strlen($x[0])) {
// e.g. @dan@pixelfed.org
array_shift($x);
}
$username = $x[0];
if (count($x) > 1) {
self::$server = $x[1];
}
else {
return false;
}
if (strpos($resource,'acct:') !== 0) {
self::$resource = urlencode('acct:' . $resource);
}
}
}
/**
* @brief fetch a webfinger resource and return a zot6 discovery url if present
*
*/
/**
* @brief fetch a webfinger resource and return a zot6 discovery url if present
*
*/
public static function zot_url($resource)
{
static function zot_url($resource) {
$arr = self::exec($resource);
$arr = self::exec($resource);
if (is_array($arr) && array_key_exists('links',$arr)) {
foreach ($arr['links'] as $link) {
if (is_array($arr) && array_key_exists('links', $arr)) {
foreach ($arr['links'] as $link) {
if (array_key_exists('rel',$link) && in_array($link['rel'], [ PROTOCOL_NOMAD, PROTOCOL_ZOT6 ])) {
if (array_key_exists('href',$link) && $link['href'] !== EMPTY_STR) {
return $link['href'];
}
}
}
}
return false;
}
if (array_key_exists('href', $link) && $link['href'] !== EMPTY_STR) {
return $link['href'];
}
}
}
}
return false;
}
}

View file

@ -24,153 +24,169 @@ use App;
* $var = get_xconfig($observer, 'category', 'key');
* }@endcode
*/
class XConfig {
class XConfig
{
/**
* @brief Loads a full xchan's configuration into a cached storage.
*
* All configuration values of the given observer hash are stored in global
* cache which is available under the global variable App::$config[$xchan].
*
* @param string $xchan
* The observer's hash
* @return void|false Returns false if xchan is not set
*/
static public function Load($xchan) {
/**
* @brief Loads a full xchan's configuration into a cached storage.
*
* All configuration values of the given observer hash are stored in global
* cache which is available under the global variable App::$config[$xchan].
*
* @param string $xchan
* The observer's hash
* @return void|false Returns false if xchan is not set
*/
public static function Load($xchan)
{
if(! $xchan)
return false;
if (! $xchan) {
return false;
}
if(! array_key_exists($xchan, App::$config))
App::$config[$xchan] = [];
if (! array_key_exists($xchan, App::$config)) {
App::$config[$xchan] = [];
}
$r = q("SELECT * FROM xconfig WHERE xchan = '%s'",
dbesc($xchan)
);
$r = q(
"SELECT * FROM xconfig WHERE xchan = '%s'",
dbesc($xchan)
);
if($r) {
foreach($r as $rr) {
$k = $rr['k'];
$c = $rr['cat'];
if(! array_key_exists($c, App::$config[$xchan])) {
App::$config[$xchan][$c] = [];
App::$config[$xchan][$c]['config_loaded'] = true;
}
App::$config[$xchan][$c][$k] = $rr['v'];
}
}
}
if ($r) {
foreach ($r as $rr) {
$k = $rr['k'];
$c = $rr['cat'];
if (! array_key_exists($c, App::$config[$xchan])) {
App::$config[$xchan][$c] = [];
App::$config[$xchan][$c]['config_loaded'] = true;
}
App::$config[$xchan][$c][$k] = $rr['v'];
}
}
}
/**
* @brief Get a particular observer's config variable given the category
* name ($family) and a key.
*
* Get a particular observer's config value from the given category ($family)
* and the $key from a cached storage in App::$config[$xchan].
*
* Returns false if not set.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param boolean $default (optional) default false
* @return mixed Stored $value or false if it does not exist
*/
static public function Get($xchan, $family, $key, $default = false) {
/**
* @brief Get a particular observer's config variable given the category
* name ($family) and a key.
*
* Get a particular observer's config value from the given category ($family)
* and the $key from a cached storage in App::$config[$xchan].
*
* Returns false if not set.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
* @param bool $default (optional) default false
* @return mixed Stored $value or false if it does not exist
*/
public static function Get($xchan, $family, $key, $default = false)
{
if(! $xchan)
return $default;
if (! $xchan) {
return $default;
}
if(! array_key_exists($xchan, App::$config))
load_xconfig($xchan);
if (! array_key_exists($xchan, App::$config)) {
load_xconfig($xchan);
}
if((! array_key_exists($family, App::$config[$xchan])) || (! array_key_exists($key, App::$config[$xchan][$family])))
return $default;
if ((! array_key_exists($family, App::$config[$xchan])) || (! array_key_exists($key, App::$config[$xchan][$family]))) {
return $default;
}
return unserialise(App::$config[$xchan][$family][$key]);
}
return unserialise(App::$config[$xchan][$family][$key]);
}
/**
* @brief Sets a configuration value for an observer.
*
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the observer's $xchan hash.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param string $value
* The value to store
* @return mixed Stored $value or false
*/
static public function Set($xchan, $family, $key, $value) {
/**
* @brief Sets a configuration value for an observer.
*
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the observer's $xchan hash.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to set
* @param string $value
* The value to store
* @return mixed Stored $value or false
*/
public static function Set($xchan, $family, $key, $value)
{
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
// manage array value
$dbvalue = ((is_array($value)) ? serialise($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($xchan, $family, $key) === false) {
if(! array_key_exists($xchan, App::$config))
App::$config[$xchan] = [];
if(! array_key_exists($family, App::$config[$xchan]))
App::$config[$xchan][$family] = [];
if (self::Get($xchan, $family, $key) === false) {
if (! array_key_exists($xchan, App::$config)) {
App::$config[$xchan] = [];
}
if (! array_key_exists($family, App::$config[$xchan])) {
App::$config[$xchan][$family] = [];
}
$ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' )",
dbesc($xchan),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
}
else {
$ret = q("UPDATE xconfig SET v = '%s' WHERE xchan = '%s' and cat = '%s' AND k = '%s'",
dbesc($dbvalue),
dbesc($xchan),
dbesc($family),
dbesc($key)
);
}
$ret = q(
"INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' )",
dbesc($xchan),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
);
} else {
$ret = q(
"UPDATE xconfig SET v = '%s' WHERE xchan = '%s' and cat = '%s' AND k = '%s'",
dbesc($dbvalue),
dbesc($xchan),
dbesc($family),
dbesc($key)
);
}
App::$config[$xchan][$family][$key] = $value;
App::$config[$xchan][$family][$key] = $value;
if($ret)
return $value;
if ($ret) {
return $value;
}
return $ret;
}
return $ret;
}
/**
* @brief Deletes the given key from the observer's config.
*
* Removes the configured value from the stored cache in App::$config[$xchan]
* and removes it from the database.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
static public function Delete($xchan, $family, $key) {
/**
* @brief Deletes the given key from the observer's config.
*
* Removes the configured value from the stored cache in App::$config[$xchan]
* and removes it from the database.
*
* @param string $xchan
* The observer's hash
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to delete
* @return mixed
*/
public static function Delete($xchan, $family, $key)
{
if(isset(App::$config[$xchan]) && isset(App::$config[$xchan][$family]) && isset(App::$config[$xchan][$family][$key]))
unset(App::$config[$xchan][$family][$key]);
if (isset(App::$config[$xchan]) && isset(App::$config[$xchan][$family]) && isset(App::$config[$xchan][$family][$key])) {
unset(App::$config[$xchan][$family][$key]);
}
$ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
dbesc($xchan),
dbesc($family),
dbesc($key)
);
return $ret;
}
$ret = q(
"DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
dbesc($xchan),
dbesc($family),
dbesc($key)
);
return $ret;
}
}

View file

@ -4,123 +4,124 @@ namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig;
class ZotURL
{
class ZotURL {
public static function fetch($url, $channel, $hub = null)
{
static public function fetch($url,$channel,$hub = null) {
$ret = [ 'success' => false ];
$ret = [ 'success' => false ];
if(strpos($url,'x-zot:') !== 0) {
return $ret;
}
if (strpos($url, 'x-zot:') !== 0) {
return $ret;
}
if(! $url) {
return $ret;
}
if (! $url) {
return $ret;
}
$portable_url = substr($url,6);
$u = explode('/',$portable_url);
$portable_id = $u[0];
$portable_url = substr($url, 6);
$u = explode('/', $portable_url);
$portable_id = $u[0];
$hosts = self::lookup($portable_id,$hub);
$hosts = self::lookup($portable_id, $hub);
if(! $hosts) {
return $ret;
}
if (! $hosts) {
return $ret;
}
foreach($hosts as $h) {
$newurl = $h . '/id/' . $portable_url;
foreach ($hosts as $h) {
$newurl = $h . '/id/' . $portable_url;
$m = parse_url($newurl);
$m = parse_url($newurl);
$data = json_encode([ 'zot_token' => random_string() ]);
$data = json_encode([ 'zot_token' => random_string() ]);
if($channel && $m) {
$headers = [
if ($channel && $m) {
$headers = [
'Accept' => 'application/x-nomad+json, application/x-zot+json',
'Content-Type' => 'application/x-nomad+json',
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Host' => $m['host'],
'(request-target)' => 'post ' . get_request_string($newurl)
];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
}
else {
$h = [ 'Accept: application/x-nomad+json' ];
}
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Host' => $m['host'],
'(request-target)' => 'post ' . get_request_string($newurl)
];
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false);
} else {
$h = [ 'Accept: application/x-nomad+json, application/x-zot+json' ];
}
$result = [];
$result = [];
$redirects = 0;
$x = z_post_url($newurl,$data,$redirects, [ 'headers' => $h ] );
if($x['success']) {
return $x;
}
}
$redirects = 0;
$x = z_post_url($newurl, $data, $redirects, [ 'headers' => $h ]);
if ($x['success']) {
return $x;
}
}
return $ret;
return $ret;
}
}
public static function is_zoturl($s)
{
static public function is_zoturl($s) {
if(strpos($url,'x-zot:') === 0) {
return true;
}
return false;
}
if (strpos($url, 'x-zot:') === 0) {
return true;
}
return false;
}
static public function lookup($portable_id,$hub) {
public static function lookup($portable_id, $hub)
{
$r = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0 order by hubloc_primary desc",
dbesc($portable_id)
);
$r = q(
"select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0 order by hubloc_primary desc",
dbesc($portable_id)
);
if(! $r) {
if (! $r) {
// extend to network lookup
// extend to network lookup
$path = '/q/' . $portable_id;
$path = '/q/' . $portable_id;
// first check sending hub since they have recently communicated with this object
// first check sending hub since they have recently communicated with this object
$redirects = 0;
$redirects = 0;
if ($hub) {
$x = z_fetch_url($hub['hubloc_url'] . $path, false, $redirects);
$u = self::parse_response($x);
if ($u) {
return $u;
}
}
if($hub) {
$x = z_fetch_url($hub['hubloc_url'] . $path, false, $redirects);
$u = self::parse_response($x);
if($u) {
return $u;
}
}
// If this fails, fallback on directory servers
// If this fails, fallback on directory servers
return false;
}
return ids_to_array($r,'hubloc_url');
}
return false;
}
return ids_to_array($r, 'hubloc_url');
}
static public function parse_response($arr) {
if(! $arr['success']) {
return false;
}
$a = json_decode($arr['body'],true);
if($a['success'] && array_key_exists('results', $a) && is_array($a['results']) && count($a['results'])) {
foreach($a['results'] as $b) {
$m = discover_by_webbie($b);
if($m) {
return([ $b ]);
}
}
}
return false;
}
public static function parse_response($arr)
{
if (! $arr['success']) {
return false;
}
$a = json_decode($arr['body'], true);
if ($a['success'] && array_key_exists('results', $a) && is_array($a['results']) && count($a['results'])) {
foreach ($a['results'] as $b) {
$m = discover_by_webbie($b);
if ($m) {
return([ $b ]);
}
}
}
return false;
}
}

View file

@ -4,60 +4,59 @@ namespace Zotlabs\Lib;
use Zotlabs\Web\HTTPSig;
class Zotfinger {
class Zotfinger
{
static function exec($resource,$channel = null,$verify = true) {
public static function exec($resource, $channel = null, $verify = true)
{
if (! $resource) {
return false;
}
if (!$resource) {
return false;
}
$m = parse_url($resource);
$m = parse_url($resource);
if ($m['host'] !== punify($m['host'])) {
$url = str_replace($m['host'],punify($m['host']),$url);
$m['host'] = punify($m['host']);
}
if ($m['host'] !== punify($m['host'])) {
$url = str_replace($m['host'], punify($m['host']), $url);
$m['host'] = punify($m['host']);
}
$data = json_encode([ 'zot_token' => random_string() ]);
$data = json_encode(['zot_token' => random_string()]);
if ($channel && $m) {
if ($channel && $m) {
$headers = [
'Accept' => 'application/x-nomad+json, application/x-zot+json',
'Content-Type' => 'application/x-nomad+json',
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Host' => $m['host'],
'(request-target)' => 'post ' . get_request_string($resource)
];
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false);
} else {
$h = ['Accept: application/x-nomad+json, application/x-zot+json'];
}
$headers = [
'Accept' => 'application/x-nomad+json, application/x-zot+json',
'Content-Type' => 'application/x-nomad+json',
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Host' => $m['host'],
'(request-target)' => 'post ' . get_request_string($resource)
];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
}
else {
$h = [ 'Accept: application/x-nomad+json, application/x-zot+json' ];
}
$result = [];
$result = [];
$redirects = 0;
$x = z_post_url($resource, $data, $redirects, ['headers' => $h]);
$redirects = 0;
$x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] );
if ($x['success']) {
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');
}
if ($x['success']) {
$result['data'] = json_decode($x['body'], true);
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');
}
if ($result['data'] && is_array($result['data']) && array_key_exists('encrypted', $result['data']) && $result['data']['encrypted']) {
$result['data'] = json_decode(Crypto::unencapsulate($result['data'], get_config('system', 'prvkey')), true);
}
$result['data'] = json_decode($x['body'],true);
if ($result['data'] && is_array($result['data']) && array_key_exists('encrypted',$result['data']) && $result['data']['encrypted']) {
$result['data'] = json_decode(Crypto::unencapsulate($result['data'],get_config('system','prvkey')),true);
}
return $result;
}
return false;
}
return $result;
}
return false;
}
}

View file

@ -23,101 +23,98 @@ require_once('include/acl_selectors.php');
* keys however this functionality has grown in an ad-hoc manner and has gotten
* quite messy over time.
*/
class Acl extends Controller
{
class Acl extends Controller {
public function init()
{
function init() {
// logger('mod_acl: ' . print_r($_REQUEST,true),LOGGER_DATA);
// 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);
$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 =
// '' => 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.
// $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.
// 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.
// 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.
if (array_key_exists('query',$_REQUEST)) {
$search = $_REQUEST['query'];
}
if (array_key_exists('query', $_REQUEST)) {
$search = $_REQUEST['query'];
}
if ( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ]))) {
killme();
}
if ((!local_channel()) && (!in_array($type, ['x', 'c', 'f']))) {
killme();
}
$permitted = [];
$permitted = [];
if (in_array($type, [ 'm', 'a', 'f' ])) {
if (in_array($type, ['m', 'a', 'f'])) {
// 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.
// 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.
$x = q(
"select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s'",
intval(local_channel()),
dbesc(($type === 'm') ? '%post_mail%' : '%tag_deliver%')
);
$x = q("select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s'",
intval(local_channel()),
dbesc(($type === 'm') ? '%post_mail%' : '%tag_deliver%')
);
$permitted = ids_to_array($x,'xchan');
}
$permitted = ids_to_array($x, 'xchan');
}
if ($search) {
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
// 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) ? "%@%'" : "%'")) . ") ";
if ($search) {
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf("'%" . dbesc($search) . "%'") . " ";
// 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) ? "%@%'" : "%'")) . ") ";
// 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)).
// 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))
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
$order_extra2 = "CASE WHEN xchan_name LIKE "
. protect_sprintf( "'%" . dbesc($search) . "%'" )
. " then POSITION('" . protect_sprintf(dbesc($search))
. "' 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) . "%'") . " ) ";
$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) . "%'" ) . " ) ";
$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) . "%'") . ") ";
$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 {
$sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = "";
}
}
else {
$sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = "";
}
$groups = [];
$contacts = [];
if ($type == '' || $type == 'g') {
// Normal privacy groups
$groups = [];
$contacts = [];
if ($type == '' || $type == 'g') {
// Normal privacy groups
$r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname
$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
@ -125,238 +122,226 @@ class Acl extends Controller {
GROUP BY pgrp.id
ORDER BY pgrp.gname
LIMIT %d OFFSET %d",
intval(local_channel()),
intval($count),
intval($start)
);
intval(local_channel()),
intval($count),
intval($start)
);
if ($r) {
foreach ($r as $g) {
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id']));
$groups[] = [
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
"uids" => AccessList::members_xchan(local_channel(),$g['id']),
"link" => ''
];
}
}
}
if ($r) {
foreach ($r as $g) {
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id']));
$groups[] = [
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
"uids" => AccessList::members_xchan(local_channel(), $g['id']),
"link" => ''
];
}
}
}
if ($type == '' || $type == 'c' || $type === 'f') {
if ($type == '' || $type == 'c' || $type === 'f') {
// Getting info from the abook is better for local users because it contains info about permissions
if (local_channel()) {
// add connections
// Getting info from the abook is better for local users because it contains info about permissions
if (local_channel()) {
// add connections
$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
$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
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc limit $count" ,
intval(local_channel())
);
}
else { // Visitors
$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
WHERE abook_channel = %d AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc limit $count",
intval(local_channel())
);
} else { // Visitors
$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
FROM xchan left join xlink on xlink_link = xchan_hash
WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc limit $count" ,
dbesc(get_observer_hash())
);
}
if ((count($r) < 100) && $type == 'c') {
$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
FROM xchan WHERE xchan_deleted = 0 and xchan_network != 'unknown' $sql_extra2 order by $order_extra2 xchan_name asc limit $count"
);
if ($r2) {
$r = array_merge($r,$r2);
$r = unique_multidim_array($r,'hash');
}
}
}
elseif ($type == 'm') {
$r = [];
$z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc limit $count",
dbesc(get_observer_hash())
);
}
if ((count($r) < 100) && $type == 'c') {
$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
FROM xchan WHERE xchan_deleted = 0 and xchan_network != 'unknown' $sql_extra2 order by $order_extra2 xchan_name asc limit $count");
if ($r2) {
$r = array_merge($r, $r2);
$r = unique_multidim_array($r, 'hash');
}
}
} elseif ($type == 'm') {
$r = [];
$z = q(
"SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d
and xchan_deleted = 0
$sql_extra3
ORDER BY xchan_name ASC ",
intval(local_channel())
);
if ($z) {
foreach ($z as $zz) {
if (in_array($zz['hash'],$permitted)) {
$r[] = $zz;
}
}
}
}
elseif ($type == 'a') {
$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
intval(local_channel())
);
if ($z) {
foreach ($z as $zz) {
if (in_array($zz['hash'], $permitted)) {
$r[] = $zz;
}
}
}
} elseif ($type == 'a') {
$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
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
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())
);
}
intval(local_channel())
);
} elseif ($type == 'x') {
$contacts = [];
$r = $this->navbar_complete();
if ($r) {
foreach ($r as $g) {
$contacts[] = [
"photo" => $g['photo'],
"name" => $g['name'],
"nick" => $g['address'],
'link' => (($g['address']) ? $g['address'] : $g['url']),
'xchan' => $g['hash']
];
}
}
elseif ($type == 'x') {
$contacts = [];
$r = $this->navbar_complete();
if ($r) {
foreach ($r as $g) {
$contacts[] = [
"photo" => $g['photo'],
"name" => $g['name'],
"nick" => $g['address'],
'link' => (($g['address']) ? $g['address'] : $g['url']),
'xchan' => $g['hash']
];
}
}
$o = [
'start' => $start,
'count' => $count,
'items' => $contacts,
];
json_return_and_die($o);
} else {
$r = [];
}
$o = [
'start' => $start,
'count' => $count,
'items' => $contacts,
];
json_return_and_die($o);
}
else {
$r = [];
}
if ($r) {
foreach ($r as $g) {
if (isset($g['network']) && in_array($g['network'], ['rss', 'anon', 'unknown']) && ($type != 'a')) {
continue;
}
if ($r) {
foreach ($r as $g) {
// 'z' (activity_filter autocomplete) requires an un-encoded hash to prevent double encoding
if (isset($g['network']) && in_array($g['network'],['rss','anon','unknown']) && ($type != 'a')) {
continue;
}
if ($type !== 'z') {
$g['hash'] = urlencode($g['hash']);
}
// 'z' (activity_filter autocomplete) requires an un-encoded hash to prevent double encoding
if (!$g['nick']) {
$g['nick'] = $g['url'];
}
if ($type !== 'z') {
$g['hash'] = urlencode($g['hash']);
}
if (in_array($g['hash'], $permitted) && $type === 'f' && (!$noforums)) {
$contacts[] = [
"type" => "c",
"photo" => "images/twopeople.png",
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => substr($g['nick'], 0, strpos($g['nick'], '@')),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => 'taggable',
"label" => t('network')
];
}
if ($type !== 'f') {
$contacts[] = [
"type" => "c",
"photo" => $g['micro'],
"name" => $g['name'],
"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" => '',
];
}
}
}
if (! $g['nick']) {
$g['nick'] = $g['url'];
}
$items = array_merge($groups, $contacts);
if (in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) {
$contacts[] = [
"type" => "c",
"photo" => "images/twopeople.png",
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => 'taggable',
"label" => t('network')
];
}
if ($type !== 'f') {
$contacts[] = [
"type" => "c",
"photo" => $g['micro'],
"name" => $g['name'],
"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" => '',
];
}
}
}
$o = [
'start' => $start,
'count' => $count,
'items' => $items,
];
$items = array_merge($groups, $contacts);
$o = [
'start' => $start,
'count' => $count,
'items' => $items,
];
json_return_and_die($o);
}
json_return_and_die($o);
}
function navbar_complete() {
public function navbar_complete()
{
// logger('navbar_complete');
// logger('navbar_complete');
if (observer_prohibited()) {
return;
}
if (observer_prohibited()) {
return;
}
$dirmode = intval(get_config('system','directory_mode'));
$search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : '');
if (! $search || mb_strlen($search) < 2) {
return [];
}
$dirmode = intval(get_config('system', 'directory_mode'));
$search = ((x($_REQUEST, 'search')) ? htmlentities($_REQUEST['search'], ENT_COMPAT, 'UTF-8', false) : '');
if (!$search || mb_strlen($search) < 2) {
return [];
}
$star = false;
$address = false;
$star = false;
$address = false;
if (substr($search,0,1) === '@') {
$search = substr($search,1);
}
if (substr($search, 0, 1) === '@') {
$search = substr($search, 1);
}
if (substr($search,0,1) === '*') {
$star = true;
$search = substr($search,1);
}
if (substr($search, 0, 1) === '*') {
$star = true;
$search = substr($search, 1);
}
if (strpos($search,'@') !== false) {
$address = true;
}
if (strpos($search, '@') !== false) {
$address = true;
}
$url = z_root() . '/dirsearch';
$url = z_root() . '/dirsearch';
$results = [];
$results = [];
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 100);
if ($url) {
$query = $url . '?f=';
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
if ($url) {
$query = $url . '?f=';
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
$x = z_fetch_url($query);
if ($x['success']) {
$t = 0;
$j = json_decode($x['body'],true);
if ($j && $j['results']) {
$results = $j['results'];
}
}
}
return $results;
}
$x = z_fetch_url($query);
if ($x['success']) {
$t = 0;
$j = json_decode($x['body'], true);
if ($j && $j['results']) {
$results = $j['results'];
}
}
}
return $results;
}
}

View file

@ -1,4 +1,5 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
@ -10,280 +11,292 @@ use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\ThreadListener;
use App;
class Activity extends Controller {
class Activity extends Controller
{
function init() {
public function init()
{
if (ActivityStreams::is_as_request()) {
$item_id = argv(1);
if (ActivityStreams::is_as_request()) {
$item_id = argv(1);
if (! $item_id) {
return;
}
if (!$item_id) {
return;
}
$ob_authorise = false;
$item_uid = 0;
$ob_authorise = false;
$item_uid = 0;
$bear = ZlibActivity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
$t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'",
dbesc($item_id)
);
if ($t) {
foreach ($t as $token) {
if ($token['v'] === $bear) {
$ob_authorize = true;
$item_uid = $token['uid'];
break;
}
}
}
}
$bear = ZlibActivity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
$t = q(
"select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'",
dbesc($item_id)
);
if ($t) {
foreach ($t as $token) {
if ($token['v'] === $bear) {
$ob_authorize = true;
$item_uid = $token['uid'];
break;
}
}
}
}
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
and item.item_delayed = 0 and item.item_blocked = 0 ";
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (! check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (! check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
}
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
}
// if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking
// Give ocap tokens priority
// if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking
// Give ocap tokens priority
if ($ob_authorize) {
$sql_extra = " and item.uid = " . intval($token['uid']) . " ";
}
else {
$sql_extra = item_permissions_sql(0);
}
if ($ob_authorize) {
$sql_extra = " and item.uid = " . intval($token['uid']) . " ";
} else {
$sql_extra = item_permissions_sql(0);
}
$r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal $sql_extra limit 1",
dbesc($item_id),
dbesc(z_root() . '/activity/' . $item_id),
dbesc(z_root() . '/item/' . $item_id)
);
$r = q(
"select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal $sql_extra limit 1",
dbesc($item_id),
dbesc(z_root() . '/activity/' . $item_id),
dbesc(z_root() . '/item/' . $item_id)
);
if (! $r) {
$r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal limit 1",
dbesc($item_id),
dbesc(z_root() . '/activity/' . $item_id),
dbesc(z_root() . '/item/' . $item_id)
);
if (!$r) {
$r = q(
"select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal limit 1",
dbesc($item_id),
dbesc(z_root() . '/activity/' . $item_id),
dbesc(z_root() . '/item/' . $item_id)
);
if ($r) {
http_status_exit(403, 'Forbidden');
}
http_status_exit(404, 'Not found');
}
if ($r) {
http_status_exit(403, 'Forbidden');
}
http_status_exit(404, 'Not found');
}
xchan_query($r,true);
$items = fetch_post_tags($r,false);
xchan_query($r, true);
$items = fetch_post_tags($r, false);
if ($portable_id && (! intval($items[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (! $c) {
ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
}
}
if ($portable_id && (!intval($items[0]['item_private']))) {
$c = q(
"select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id);
}
}
$channel = channelx_by_n($items[0]['uid']);
$channel = channelx_by_n($items[0]['uid']);
as_return_and_die(ZlibActivity::encode_activity($items[0],true),$channel);
as_return_and_die(ZlibActivity::encode_activity($items[0], true), $channel);
}
}
if (Libzot::is_zot_request()) {
$item_id = argv(1);
if (Libzot::is_zot_request()) {
if (!$item_id) {
http_status_exit(404, 'Not found');
}
$item_id = argv(1);
$portable_id = EMPTY_STR;
if (! $item_id) {
http_status_exit(404, 'Not found');
}
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) ";
$portable_id = EMPTY_STR;
$i = null;
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) ";
// do we have the item (at all)?
$i = null;
$r = q(
"select * from item where mid = '%s' $item_normal limit 1",
dbesc(z_root() . '/activity/' . $item_id)
);
// do we have the item (at all)?
if (!$r) {
$r = q(
"select * from item where mid = '%s' $item_normal limit 1",
dbesc(z_root() . '/item/' . $item_id)
);
if ($r) {
goaway(z_root() . '/item/' . $item_id);
}
http_status_exit(404, 'Not found');
}
$r = q("select * from item where mid = '%s' $item_normal limit 1",
dbesc(z_root() . '/activity/' . $item_id)
);
// process an authenticated fetch
if (! $r) {
$r = q("select * from item where mid = '%s' $item_normal limit 1",
dbesc(z_root() . '/item/' . $item_id)
);
if ($r) {
goaway(z_root() . '/item/' . $item_id);
}
http_status_exit(404,'Not found');
}
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
observer_auth($portable_id);
// process an authenticated fetch
// first see if we have a copy of this item's parent owned by the current signer
// include xchans for all zot-like networks - these will have the same guid and public key
$sigdata = HTTPSig::verify(EMPTY_STR);
if($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
observer_auth($portable_id);
$x = q(
"select * from xchan where xchan_hash = '%s'",
dbesc($sigdata['portable_id'])
);
// first see if we have a copy of this item's parent owned by the current signer
// include xchans for all zot-like networks - these will have the same guid and public key
if ($x) {
$xchans = q(
"select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
dbesc($sigdata['portable_id']),
dbesc($x[0]['xchan_guid']),
dbesc($x[0]['xchan_pubkey'])
);
$x = q("select * from xchan where xchan_hash = '%s'",
dbesc($sigdata['portable_id'])
);
if ($xchans) {
$hashes = ids_to_querystr($xchans, 'xchan_hash', true);
$i = q(
"select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1",
dbesc($r[0]['parent_mid'])
);
}
}
}
if ($x) {
$xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
dbesc($sigdata['portable_id']),
dbesc($x[0]['xchan_guid']),
dbesc($x[0]['xchan_pubkey'])
);
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
if ($xchans) {
$hashes = ids_to_querystr($xchans,'xchan_hash',true);
$i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1",
dbesc($r[0]['parent_mid'])
);
}
}
}
$sql_extra = item_permissions_sql(0);
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
if (!$i) {
$i = q(
"select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
$sql_extra = item_permissions_sql(0);
if (! $i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
$bear = ZlibActivity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
if (! $i) {
$t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
dbesc($bear)
);
if ($t) {
$i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
dbesc($item_id),
intval($t[0]['iid'])
);
}
}
}
$bear = ZlibActivity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
if (!$i) {
$t = q(
"select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
dbesc($bear)
);
if ($t) {
$i = q(
"select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
dbesc($item_id),
intval($t[0]['iid'])
);
}
}
}
if (! $i) {
http_status_exit(403,'Forbidden');
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
$parents_str = ids_to_querystr($i,'item_id');
$parents_str = ids_to_querystr($i, 'item_id');
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ",
dbesc($parents_str)
);
$items = q(
"SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ",
dbesc($parents_str)
);
if(! $items) {
http_status_exit(404, 'Not found');
}
if (!$items) {
http_status_exit(404, 'Not found');
}
xchan_query($items,true);
$items = fetch_post_tags($items,true);
xchan_query($items, true);
$items = fetch_post_tags($items, true);
$observer = App::get_observer();
$parent = $items[0];
$recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []);
$to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null);
$nitems = [];
foreach($items as $i) {
$observer = App::get_observer();
$parent = $items[0];
$recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'], 'activitypub', 'recips', []) : []);
$to = (($recips && array_key_exists('to', $recips) && is_array($recips['to'])) ? $recips['to'] : null);
$nitems = [];
foreach ($items as $i) {
$mids = [];
$mids = [];
if (intval($i['item_private'])) {
if (!$observer) {
continue;
}
// ignore private reshare, possibly from hubzilla
if ($i['verb'] === 'Announce') {
if (!in_array($i['thr_parent'], $mids)) {
$mids[] = $i['thr_parent'];
}
continue;
}
// also ignore any children of the private reshares
if (in_array($i['thr_parent'], $mids)) {
continue;
}
if(intval($i['item_private'])) {
if(! $observer) {
continue;
}
// ignore private reshare, possibly from hubzilla
if($i['verb'] === 'Announce') {
if(! in_array($i['thr_parent'],$mids)) {
$mids[] = $i['thr_parent'];
}
continue;
}
// also ignore any children of the private reshares
if(in_array($i['thr_parent'],$mids)) {
continue;
}
if ((!$to) || (!in_array($observer['xchan_url'], $to))) {
continue;
}
}
$nitems[] = $i;
}
if((! $to) || (! in_array($observer['xchan_url'],$to))) {
continue;
}
if (!$nitems) {
http_status_exit(404, 'Not found');
}
}
$nitems[] = $i;
}
$chan = channelx_by_n($nitems[0]['uid']);
if(! $nitems)
http_status_exit(404, 'Not found');
if (!$chan) {
http_status_exit(404, 'Not found');
}
$chan = channelx_by_n($nitems[0]['uid']);
if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) {
http_status_exit(403, 'Forbidden');
}
if(! $chan)
http_status_exit(404, 'Not found');
$i = ZlibActivity::encode_item_collection($nitems, 'conversation/' . $item_id, 'OrderedCollection', true, count($nitems));
if ($portable_id && (!intval($items[0]['item_private']))) {
ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id);
}
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
if (!$i) {
http_status_exit(404, 'Not found');
}
$i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',true, count($nitems));
if ($portable_id && (! intval($items[0]['item_private']))) {
ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
}
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
ZlibActivity::ap_schema()
]], $i);
if(! $i)
http_status_exit(404, 'Not found');
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
ZlibActivity::ap_schema()
]], $i);
$headers = [];
$headers['Content-Type'] = 'application/x-nomad+json' ;
$x['signature'] = LDSignatures::sign($x,$chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
$headers = [];
$headers['Content-Type'] = 'application/x-nomad+json';
$x['signature'] = LDSignatures::sign($x, $chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
goaway(z_root() . '/item/' . argv(1));
}
goaway(z_root() . '/item/' . argv(1));
}
}

View file

@ -1,4 +1,5 @@
<?php
/**
* @file Zotlabs/Module/Admin.php
* @brief Hubzilla's admin controller.
@ -13,179 +14,181 @@ use Zotlabs\Web\Controller;
use Zotlabs\Web\SubModule;
use Zotlabs\Lib\Config;
/**
* @brief Admin area.
*
*/
class Admin extends Controller
{
class Admin extends Controller {
private $sm = null;
private $sm = null;
public function __construct()
{
$this->sm = new SubModule();
}
function __construct() {
$this->sm = new SubModule();
}
public function init()
{
function init() {
logger('admin_init', LOGGER_DEBUG);
logger('admin_init', LOGGER_DEBUG);
if (!is_site_admin()) {
logger('admin denied.');
return;
}
if (! is_site_admin()) {
logger('admin denied.');
return;
}
if (argc() > 1) {
$this->sm->call('init');
}
}
if (argc() > 1) {
$this->sm->call('init');
}
}
function post() {
public function post()
{
logger('admin_post', LOGGER_DEBUG);
logger('admin_post', LOGGER_DEBUG);
if (! is_site_admin()) {
logger('admin denied.');
return;
}
if (!is_site_admin()) {
logger('admin denied.');
return;
}
if (argc() > 1) {
$this->sm->call('post');
}
if (argc() > 1) {
$this->sm->call('post');
}
// goaway(z_root() . '/admin' );
}
// goaway(z_root() . '/admin' );
}
/**
* @return string
*/
/**
* @return string
*/
function get() {
public function get()
{
logger('admin_content', LOGGER_DEBUG);
logger('admin_content', LOGGER_DEBUG);
if (! is_site_admin()) {
logger('admin denied.');
return login(false);
}
if (!is_site_admin()) {
logger('admin denied.');
return login(false);
}
/*
* Page content
*/
/*
* Page content
*/
nav_set_selected('Admin');
nav_set_selected('Admin');
$o = '';
$o = '';
if (argc() > 1) {
$o = $this->sm->call('get');
if ($o === false) {
notice( t('Item not found.') );
}
}
else {
$o = $this->admin_page_summary();
}
if (argc() > 1) {
$o = $this->sm->call('get');
if ($o === false) {
notice(t('Item not found.'));
}
} else {
$o = $this->admin_page_summary();
}
if (is_ajax()) {
echo $o;
killme();
}
else {
return $o;
}
}
if (is_ajax()) {
echo $o;
killme();
} else {
return $o;
}
}
/**
* @brief Returns content for Admin Summary Page.
*
* @return string HTML from parsed admin_summary.tpl
*/
/**
* @brief Returns content for Admin Summary Page.
*
* @return string HTML from parsed admin_summary.tpl
*/
function admin_page_summary() {
public function admin_page_summary()
{
// list total user accounts, expirations etc.
$accounts = [];
$r = q("SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
db_utcnow(),
db_utcnow(),
dbesc(NULL_DATE),
intval(ACCOUNT_BLOCKED)
);
if ($r) {
$accounts['total'] = [ 'label' => t('Accounts'), 'val' => $r[0]['total'] ];
$accounts['blocked'] = [ 'label' => t('Blocked accounts'), 'val' => $r[0]['blocked'] ];
$accounts['expired'] = [ 'label' => t('Expired accounts'), 'val' => $r[0]['expired'] ];
$accounts['expiring'] = [ 'label' => t('Expiring accounts'), 'val' => $r[0]['expiring'] ];
}
// list total user accounts, expirations etc.
$accounts = [];
$r = q(
"SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
db_utcnow(),
db_utcnow(),
dbesc(NULL_DATE),
intval(ACCOUNT_BLOCKED)
);
if ($r) {
$accounts['total'] = ['label' => t('Accounts'), 'val' => $r[0]['total']];
$accounts['blocked'] = ['label' => t('Blocked accounts'), 'val' => $r[0]['blocked']];
$accounts['expired'] = ['label' => t('Expired accounts'), 'val' => $r[0]['expired']];
$accounts['expiring'] = ['label' => t('Expiring accounts'), 'val' => $r[0]['expiring']];
}
// pending registrations
// pending registrations
$pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
intval(ACCOUNT_PENDING)
);
$pdg = q(
"SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
intval(ACCOUNT_PENDING)
);
$pending = (($pdg) ? count($pdg) : 0);
$pending = (($pdg) ? count($pdg) : 0);
// available channels, primary and clones
$channels = [];
$r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0 and channel_system = 0");
if ($r) {
$channels['total'] = [ 'label' => t('Channels'), 'val' => $r[0]['total'] ];
$channels['main'] = [ 'label' => t('Primary'), 'val' => $r[0]['main'] ];
$channels['clones'] = [ 'label' => t('Clones'), 'val' => $r[0]['clones'] ];
}
// available channels, primary and clones
$channels = [];
$r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0 and channel_system = 0");
if ($r) {
$channels['total'] = ['label' => t('Channels'), 'val' => $r[0]['total']];
$channels['main'] = ['label' => t('Primary'), 'val' => $r[0]['main']];
$channels['clones'] = ['label' => t('Clones'), 'val' => $r[0]['clones']];
}
// We can do better, but this is a quick queue status
$r = q("SELECT COUNT(outq_delivered) AS total FROM outq WHERE outq_delivered = 0");
$queue = (($r) ? $r[0]['total'] : 0);
$queues = [ 'label' => t('Message queues'), 'queue' => $queue ];
// We can do better, but this is a quick queue status
$r = q("SELECT COUNT(outq_delivered) AS total FROM outq WHERE outq_delivered = 0");
$queue = (($r) ? $r[0]['total'] : 0);
$queues = ['label' => t('Message queues'), 'queue' => $queue];
$plugins = [];
$plugins = [];
if (is_array(App::$plugins) && App::$plugins) {
foreach (App::$plugins as $p) {
if ($p) {
$plugins[] = $p;
}
}
sort($plugins);
}
else {
$plugins = 0;
}
if (is_array(App::$plugins) && App::$plugins) {
foreach (App::$plugins as $p) {
if ($p) {
$plugins[] = $p;
}
}
sort($plugins);
} else {
$plugins = 0;
}
// Could be extended to provide also other alerts to the admin
// Could be extended to provide also other alerts to the admin
$alertmsg = '';
$alertmsg = '';
$upgrade = EMPTY_STR;
$upgrade = EMPTY_STR;
if((! defined('PLATFORM_ARCHITECTURE')) || (PLATFORM_ARCHITECTURE === 'zap')) {
$vrelease = get_repository_version('release');
$vdev = get_repository_version('dev');
$upgrade = ((version_compare(STD_VERSION,$vrelease) < 0) ? t('Your software should be updated') : '');
}
$t = get_markup_template('admin_summary.tpl');
return replace_macros($t, [
'$title' => t('Administration'),
'$page' => t('Summary'),
'$adminalertmsg' => $alertmsg,
'$queues' => $queues,
'$accounts' => [ t('Registered accounts'), $accounts ],
'$pending' => [ t('Pending registrations'), $pending ],
'$channels' => [ t('Registered channels'), $channels ],
'$plugins' => (($plugins) ? [ t('Active addons'), $plugins ] : EMPTY_STR),
'$version' => [ t('Version'), STD_VERSION ],
'$vmaster' => [ t('Repository version (release)'), $vrelease ],
'$vdev' => [ t('Repository version (dev)'), $vdev ],
'$upgrade' => $upgrade,
'$build' => Config::Get('system', 'db_version')
]);
}
if ((!defined('PLATFORM_ARCHITECTURE')) || (PLATFORM_ARCHITECTURE === 'zap')) {
$vrelease = get_repository_version('release');
$vdev = get_repository_version('dev');
$upgrade = ((version_compare(STD_VERSION, $vrelease) < 0) ? t('Your software should be updated') : '');
}
$t = get_markup_template('admin_summary.tpl');
return replace_macros($t, [
'$title' => t('Administration'),
'$page' => t('Summary'),
'$adminalertmsg' => $alertmsg,
'$queues' => $queues,
'$accounts' => [t('Registered accounts'), $accounts],
'$pending' => [t('Pending registrations'), $pending],
'$channels' => [t('Registered channels'), $channels],
'$plugins' => (($plugins) ? [t('Active addons'), $plugins] : EMPTY_STR),
'$version' => [t('Version'), STD_VERSION],
'$vmaster' => [t('Repository version (release)'), $vrelease],
'$vdev' => [t('Repository version (dev)'), $vdev],
'$upgrade' => $upgrade,
'$build' => Config::Get('system', 'db_version')
]);
}
}

View file

@ -2,80 +2,82 @@
namespace Zotlabs\Module\Admin;
class Account_edit
{
public function post()
{
class Account_edit {
$account_id = $_REQUEST['aid'];
function post() {
if (!$account_id) {
return;
}
$account_id = $_REQUEST['aid'];
if(! $account_id)
return;
$pass1 = trim($_REQUEST['pass1']);
$pass2 = trim($_REQUEST['pass2']);
if($pass1 && $pass2 && ($pass1 === $pass2)) {
$salt = random_string(32);
$password_encoded = hash('whirlpool', $salt . $pass1);
$r = q("update account set account_salt = '%s', account_password = '%s',
$pass1 = trim($_REQUEST['pass1']);
$pass2 = trim($_REQUEST['pass2']);
if ($pass1 && $pass2 && ($pass1 === $pass2)) {
$salt = random_string(32);
$password_encoded = hash('whirlpool', $salt . $pass1);
$r = q(
"update account set account_salt = '%s', account_password = '%s',
account_password_changed = '%s' where account_id = %d",
dbesc($salt),
dbesc($password_encoded),
dbesc(datetime_convert()),
intval($account_id)
);
if($r)
info( sprintf( t('Password changed for account %d.'), $account_id). EOL);
dbesc($salt),
dbesc($password_encoded),
dbesc(datetime_convert()),
intval($account_id)
);
if ($r) {
info(sprintf(t('Password changed for account %d.'), $account_id) . EOL);
}
}
}
$service_class = trim($_REQUEST['service_class']);
$account_language = trim($_REQUEST['account_language']);
$service_class = trim($_REQUEST['service_class']);
$account_language = trim($_REQUEST['account_language']);
$r = q("update account set account_service_class = '%s', account_language = '%s'
$r = q(
"update account set account_service_class = '%s', account_language = '%s'
where account_id = %d",
dbesc($service_class),
dbesc($account_language),
intval($account_id)
);
dbesc($service_class),
dbesc($account_language),
intval($account_id)
);
if($r)
info( t('Account settings updated.') . EOL);
if ($r) {
info(t('Account settings updated.') . EOL);
}
goaway(z_root() . '/admin/accounts');
}
goaway(z_root() . '/admin/accounts');
}
function get() {
if(argc() > 2)
$account_id = argv(2);
public function get()
{
if (argc() > 2) {
$account_id = argv(2);
}
$x = q("select * from account where account_id = %d limit 1",
intval($account_id)
);
$x = q(
"select * from account where account_id = %d limit 1",
intval($account_id)
);
if(! $x) {
notice ( t('Account not found.') . EOL);
return '';
}
if (!$x) {
notice(t('Account not found.') . EOL);
return '';
}
$a = replace_macros(get_markup_template('admin_account_edit.tpl'), [
'$account' => $x[0],
'$title' => t('Account Edit'),
'$pass1' => [ 'pass1', t('New Password'), ' ','' ],
'$pass2' => [ 'pass2', t('New Password again'), ' ','' ],
'$account_language' => [ 'account_language' , t('Account language (for emails)'), $x[0]['account_language'], '', language_list() ],
'$service_class' => [ 'service_class', t('Service class'), $x[0]['account_service_class'], '' ],
'$submit' => t('Submit'),
]
);
return $a;
}
$a = replace_macros(get_markup_template('admin_account_edit.tpl'), [
'$account' => $x[0],
'$title' => t('Account Edit'),
'$pass1' => ['pass1', t('New Password'), ' ', ''],
'$pass2' => ['pass2', t('New Password again'), ' ', ''],
'$account_language' => ['account_language', t('Account language (for emails)'), $x[0]['account_language'], '', language_list()],
'$service_class' => ['service_class', t('Service class'), $x[0]['account_service_class'], ''],
'$submit' => t('Submit'),
]);
return $a;
}
}

View file

@ -4,199 +4,208 @@ namespace Zotlabs\Module\Admin;
use App;
class Accounts {
class Accounts
{
/**
* @brief Handle POST actions on accounts admin page.
*
* This function is called when on the admin user/account page the form was
* submitted to handle multiple operations at once. If one of the icons next
* to an entry are pressed the function admin_page_accounts() will handle this.
*
*/
/**
* @brief Handle POST actions on accounts admin page.
*
* This function is called when on the admin user/account page the form was
* submitted to handle multiple operations at once. If one of the icons next
* to an entry are pressed the function admin_page_accounts() will handle this.
*
*/
function post() {
public function post()
{
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : [] );
$users = ( x($_POST, 'user') ? $_POST['user'] : [] );
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : [] );
$pending = (x($_POST, 'pending') ? $_POST['pending'] : []);
$users = (x($_POST, 'user') ? $_POST['user'] : []);
$blocked = (x($_POST, 'blocked') ? $_POST['blocked'] : []);
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
for ($i = 0; $i < count($users); $i++) {
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
$op = ($blocked[$i]) ? '& ~' : '| ';
q("UPDATE account SET account_flags = (account_flags $op %d) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($users[$i])
);
}
notice( sprintf( tt("%s account blocked/unblocked", "%s accounts blocked/unblocked", count($users)), count($users)) );
}
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
for ($i = 0; $i < count($users); $i++) {
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
$op = ($blocked[$i]) ? '& ~' : '| ';
q(
"UPDATE account SET account_flags = (account_flags $op %d) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($users[$i])
);
}
notice(sprintf(tt("%s account blocked/unblocked", "%s accounts blocked/unblocked", count($users)), count($users)));
}
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
foreach ($users as $uid){
account_remove($uid, true, false);
}
notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
}
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
foreach ($users as $uid) {
account_remove($uid, true, false);
}
notice(sprintf(tt("%s account deleted", "%s accounts deleted", count($users)), count($users)));
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
foreach ($pending as $hash) {
account_allow($hash);
}
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
foreach ($pending as $hash) {
account_allow($hash);
}
}
// registration deny button was submitted
if (x($_POST, 'page_accounts_deny')) {
foreach ($pending as $hash) {
account_deny($hash);
}
}
// registration deny button was submitted
if (x($_POST, 'page_accounts_deny')) {
foreach ($pending as $hash) {
account_deny($hash);
}
}
goaway(z_root() . '/admin/accounts' );
}
goaway(z_root() . '/admin/accounts');
}
/**
* @brief Generate accounts admin page and handle single item operations.
*
* This function generates the accounts/account admin page and handles the actions
* if an icon next to an entry was clicked. If several items were selected and
* the form was submitted it is handled by the function admin_page_accounts_post().
*
* @return string
*/
/**
* @brief Generate accounts admin page and handle single item operations.
*
* This function generates the accounts/account admin page and handles the actions
* if an icon next to an entry was clicked. If several items were selected and
* the form was submitted it is handled by the function admin_page_accounts_post().
*
* @return string
*/
function get(){
if (argc() > 2) {
$uid = argv(3);
$account = q("SELECT * FROM account WHERE account_id = %d",
intval($uid)
);
public function get()
{
if (argc() > 2) {
$uid = argv(3);
$account = q(
"SELECT * FROM account WHERE account_id = %d",
intval($uid)
);
if (! $account) {
notice( t('Account not found') . EOL);
goaway(z_root() . '/admin/accounts' );
}
if (!$account) {
notice(t('Account not found') . EOL);
goaway(z_root() . '/admin/accounts');
}
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
switch (argv(2)) {
case 'delete':
// delete user
account_remove($uid,true,false);
switch (argv(2)) {
case 'delete':
// delete user
account_remove($uid, true, false);
notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
break;
case 'block':
q("UPDATE account SET account_flags = ( account_flags | %d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice(sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
break;
case 'block':
q(
"UPDATE account SET account_flags = ( account_flags | %d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL);
break;
case 'unblock':
q("UPDATE account SET account_flags = ( account_flags & ~ %d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice(sprintf(t("Account '%s' blocked"), $account[0]['account_email']) . EOL);
break;
case 'unblock':
q(
"UPDATE account SET account_flags = ( account_flags & ~ %d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
break;
}
notice(sprintf(t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
break;
}
goaway(z_root() . '/admin/accounts' );
}
goaway(z_root() . '/admin/accounts');
}
/* get pending */
$pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) != 0 ",
intval(ACCOUNT_PENDING)
);
/* get pending */
$pending = q(
"SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) != 0 ",
intval(ACCOUNT_PENDING)
);
/* get accounts */
/* get accounts */
$total = q("SELECT count(*) as total FROM account");
if (count($total)) {
App::set_pager_total($total[0]['total']);
App::set_pager_itemspage(100);
}
$total = q("SELECT count(*) as total FROM account");
if (count($total)) {
App::set_pager_total($total[0]['total']);
App::set_pager_itemspage(100);
}
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
$dir = 'asc';
if (array_key_exists('dir',$_REQUEST)) {
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
}
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
$dir = 'asc';
if (array_key_exists('dir', $_REQUEST)) {
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
}
$base = z_root() . '/admin/accounts?f=';
$odir = (($dir === 'asc') ? '0' : '1');
$base = z_root() . '/admin/accounts?f=';
$odir = (($dir === 'asc') ? '0' : '1');
$users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
$users = q(
"SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
(SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac
where true $serviceclass and account_flags != %d order by $key $dir limit %d offset %d ",
intval(ACCOUNT_BLOCKED),
db_concat('ch.channel_address', ' '),
intval(ACCOUNT_BLOCKED | ACCOUNT_PENDING),
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
intval(ACCOUNT_BLOCKED),
db_concat('ch.channel_address', ' '),
intval(ACCOUNT_BLOCKED | ACCOUNT_PENDING),
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
if ($users) {
for($x = 0; $x < count($users); $x ++) {
$channel_arr = explode(' ',$users[$x]['channels']);
if ($channel_arr) {
$linked = [];
foreach ( $channel_arr as $c) {
$linked[] = '<a href="' . z_root() . '/channel/' . $c . '">' . $c . '</a>';
}
$users[$x]['channels'] = implode(' ',$linked);
}
}
}
if ($users) {
for ($x = 0; $x < count($users); $x++) {
$channel_arr = explode(' ', $users[$x]['channels']);
if ($channel_arr) {
$linked = [];
foreach ($channel_arr as $c) {
$linked[] = '<a href="' . z_root() . '/channel/' . $c . '">' . $c . '</a>';
}
$users[$x]['channels'] = implode(' ', $linked);
}
}
}
$t =
$o = replace_macros(get_markup_template('admin_accounts.tpl'), [
'$title' => t('Administration'),
'$page' => t('Accounts'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
'$h_pending' => t('Registrations waiting for confirm'),
'$th_pending' => array( t('Request date'), t('Email') ),
'$no_pending' => t('No registrations.'),
'$approve' => t('Approve'),
'$deny' => t('Deny'),
'$delete' => t('Delete'),
'$block' => t('Block'),
'$unblock' => t('Unblock'),
'$odir' => $odir,
'$base' => $base,
'$h_users' => t('Accounts'),
'$th_users' => [
[ t('ID'), 'account_id' ],
[ t('Email'), 'account_email' ],
[ t('All Channels'), 'channels' ],
[ t('Register date'), 'account_created' ],
[ t('Last login'), 'account_lastlog' ],
[ t('Expires'), 'account_expires' ],
[ t('Service Class'), 'account_service_class']
],
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => get_form_security_token("admin_accounts"),
'$baseurl' => z_root(),
'$pending' => $pending,
'$users' => $users,
]);
$t =
$o = replace_macros(get_markup_template('admin_accounts.tpl'), [
'$title' => t('Administration'),
'$page' => t('Accounts'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
'$h_pending' => t('Registrations waiting for confirm'),
'$th_pending' => array(t('Request date'), t('Email')),
'$no_pending' => t('No registrations.'),
'$approve' => t('Approve'),
'$deny' => t('Deny'),
'$delete' => t('Delete'),
'$block' => t('Block'),
'$unblock' => t('Unblock'),
'$odir' => $odir,
'$base' => $base,
'$h_users' => t('Accounts'),
'$th_users' => [
[t('ID'), 'account_id'],
[t('Email'), 'account_email'],
[t('All Channels'), 'channels'],
[t('Register date'), 'account_created'],
[t('Last login'), 'account_lastlog'],
[t('Expires'), 'account_expires'],
[t('Service Class'), 'account_service_class']
],
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => get_form_security_token("admin_accounts"),
'$baseurl' => z_root(),
'$pending' => $pending,
'$users' => $users,
]);
$o .= paginate($a);
$o .= paginate($a);
return $o;
}
return $o;
}
}

View file

@ -2,479 +2,486 @@
namespace Zotlabs\Module\Admin;
use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra;
use App;
use PHPGit\Exception\GitException;
use Zotlabs\Storage\GitRepo;
use Michelf\MarkdownExtra;
class Addons {
class Addons
{
/**
* @brief
*
*/
function post() {
/**
* @brief
*
*/
public function post()
{
if(argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")) {
@include_once("addon/" . argv(2) . "/" . argv(2) . ".php");
if(function_exists(argv(2).'_plugin_admin_post')) {
$func = argv(2) . '_plugin_admin_post';
$func($a);
}
if (argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")) {
@include_once("addon/" . argv(2) . "/" . argv(2) . ".php");
if (function_exists(argv(2) . '_plugin_admin_post')) {
$func = argv(2) . '_plugin_admin_post';
$func($a);
}
goaway(z_root() . '/admin/addons/' . argv(2) );
}
elseif(argc() > 2) {
switch(argv(2)) {
case 'updaterepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
}
else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
}
else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'cache/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
$git = new GitRepo('sys', null, false, $repoName, $repoDir);
try {
if ($git->pull()) {
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
} catch (\PHPGit\Exception\GitException $e) {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
case 'removerepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'cache/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
/// @TODO remove directory and unlink /addon/files
if (rrmdir($repoDir)) {
json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
}
case 'installrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_writable($extendDir)) {
logger('Directory not writable to web server: ' . $extendDir);
json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
}
$repoDir = $addonDir . '/' . $repoName;
$tempRepoBaseDir = 'cache/git/sys/temp/';
$tempAddonDir = $tempRepoBaseDir . $repoName;
goaway(z_root() . '/admin/addons/' . argv(2));
} elseif (argc() > 2) {
switch (argv(2)) {
case 'updaterepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'cache/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
$git = new GitRepo('sys', null, false, $repoName, $repoDir);
try {
if ($git->pull()) {
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
} catch (GitException $e) {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
case 'removerepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'cache/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
/// @TODO remove directory and unlink /addon/files
if (rrmdir($repoDir)) {
json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
}
case 'installrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_writable($extendDir)) {
logger('Directory not writable to web server: ' . $extendDir);
json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
}
$repoDir = $addonDir . '/' . $repoName;
$tempRepoBaseDir = 'cache/git/sys/temp/';
$tempAddonDir = $tempRepoBaseDir . $repoName;
if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
}
rename($tempAddonDir, $repoDir);
if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
}
rename($tempAddonDir, $repoDir);
if (!is_writable(realpath('addon/'))) {
logger('/addon directory not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
}
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
$git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
$repo = $git->probeRepo();
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
}
case 'addrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
$tempAddonDir = realpath('cache') . '/git/sys/temp';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_dir($tempAddonDir)) {
if (!mkdir($tempAddonDir, 0770, true)) {
logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
}
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
}
$repoDir = $tempAddonDir . '/' . $repoName;
if (!is_writable($tempAddonDir)) {
logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
}
// clone the repo if new automatically
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
if (!is_writable(realpath('addon/'))) {
logger('/addon directory not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
}
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
$git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
$repo = $git->probeRepo();
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
}
case 'addrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'cache/git/sys/extend';
$addonDir = $extendDir . '/addon';
$tempAddonDir = realpath('cache') . '/git/sys/temp';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_dir($tempAddonDir)) {
if (!mkdir($tempAddonDir, 0770, true)) {
logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
}
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
}
$repoDir = $tempAddonDir . '/' . $repoName;
if (!is_writable($tempAddonDir)) {
logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
}
// clone the repo if new automatically
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
$remotes = $git->git->remote();
$fetchURL = $remotes['origin']['fetch'];
if ($fetchURL !== $git->url) {
if (rrmdir($repoDir)) {
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
} else {
json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
}
}
$repo = $git->probeRepo();
$repo['readme'] = $repo['manifest'] = null;
foreach ($git->git->tree('master') as $object) {
if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
$repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
} else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
$repo['manifest'] = $git->git->cat->blob($object['hash']);
}
}
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
} else {
json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
}
break;
default:
break;
}
}
}
$remotes = $git->git->remote();
$fetchURL = $remotes['origin']['fetch'];
if ($fetchURL !== $git->url) {
if (rrmdir($repoDir)) {
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
} else {
json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
}
}
$repo = $git->probeRepo();
$repo['readme'] = $repo['manifest'] = null;
foreach ($git->git->tree('master') as $object) {
if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
$repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
} elseif ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
$repo['manifest'] = $git->git->cat->blob($object['hash']);
}
}
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
} else {
json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
}
break;
default:
break;
}
}
}
/**
* @brief Addons admin page.
*
* @return string with parsed HTML
*/
function get() {
/**
* @brief Addons admin page.
*
* @return string with parsed HTML
*/
public function get()
{
/*
* Single plugin
*/
/*
* Single plugin
*/
if (\App::$argc == 3){
$plugin = \App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")){
notice( t("Item not found.") );
return '';
}
if (App::$argc == 3) {
$plugin = App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")) {
notice(t("Item not found."));
return '';
}
$enabled = in_array($plugin,\App::$plugins);
$info = get_plugin_info($plugin);
$x = check_plugin_versions($info);
$enabled = in_array($plugin, App::$plugins);
$info = get_plugin_info($plugin);
$x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions
// disable plugins which are installed but incompatible versions
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($plugin, \App::$plugins);
if ($idz !== false) {
unset(\App::$plugins[$idz]);
uninstall_plugin($plugin);
set_config("system","addon", implode(", ",\App::$plugins));
}
}
$info['disabled'] = 1-intval($x);
if ($enabled && !$x) {
$enabled = false;
$idz = array_search($plugin, App::$plugins);
if ($idz !== false) {
unset(App::$plugins[$idz]);
uninstall_plugin($plugin);
set_config("system", "addon", implode(", ", App::$plugins));
}
}
$info['disabled'] = 1 - intval($x);
if (x($_GET,"a") && $_GET['a']=="t"){
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false;
// Toggle plugin status
$idx = array_search($plugin, \App::$plugins);
if ($idx !== false){
unset(\App::$plugins[$idx]);
uninstall_plugin($plugin);
$pinstalled = false;
info( sprintf( t("Plugin %s disabled."), $plugin ) );
} else {
\App::$plugins[] = $plugin;
install_plugin($plugin);
$pinstalled = true;
info( sprintf( t("Plugin %s enabled."), $plugin ) );
}
set_config("system","addon", implode(", ",\App::$plugins));
if (x($_GET, "a") && $_GET['a'] == "t") {
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false;
// Toggle plugin status
$idx = array_search($plugin, App::$plugins);
if ($idx !== false) {
unset(App::$plugins[$idx]);
uninstall_plugin($plugin);
$pinstalled = false;
info(sprintf(t("Plugin %s disabled."), $plugin));
} else {
App::$plugins[] = $plugin;
install_plugin($plugin);
$pinstalled = true;
info(sprintf(t("Plugin %s enabled."), $plugin));
}
set_config("system", "addon", implode(", ", App::$plugins));
if($pinstalled) {
@require_once("addon/$plugin/$plugin.php");
if(function_exists($plugin.'_plugin_admin'))
goaway(z_root() . '/admin/addons/' . $plugin);
}
goaway(z_root() . '/admin/addons' );
}
if ($pinstalled) {
@require_once("addon/$plugin/$plugin.php");
if (function_exists($plugin . '_plugin_admin')) {
goaway(z_root() . '/admin/addons/' . $plugin);
}
}
goaway(z_root() . '/admin/addons');
}
// display plugin details
// display plugin details
if (in_array($plugin, \App::$plugins)){
$status = 'on';
$action = t('Disable');
} else {
$status = 'off';
$action = t('Enable');
}
if (in_array($plugin, App::$plugins)) {
$status = 'on';
$action = t('Disable');
} else {
$status = 'off';
$action = t('Enable');
}
$readme = null;
if (is_file("addon/$plugin/README.md")){
$readme = file_get_contents("addon/$plugin/README.md");
$readme = MarkdownExtra::defaultTransform($readme);
} else if (is_file("addon/$plugin/README")){
$readme = "<pre>". file_get_contents("addon/$plugin/README") ."</pre>";
}
$readme = null;
if (is_file("addon/$plugin/README.md")) {
$readme = file_get_contents("addon/$plugin/README.md");
$readme = MarkdownExtra::defaultTransform($readme);
} elseif (is_file("addon/$plugin/README")) {
$readme = "<pre>" . file_get_contents("addon/$plugin/README") . "</pre>";
}
$admin_form = '';
$admin_form = '';
$r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1",
dbesc($plugin)
);
$r = q(
"select * from addon where plugin_admin = 1 and aname = '%s' limit 1",
dbesc($plugin)
);
if($r) {
@require_once("addon/$plugin/$plugin.php");
if(function_exists($plugin.'_plugin_admin')) {
$func = $plugin.'_plugin_admin';
$func($a, $admin_form);
}
}
if ($r) {
@require_once("addon/$plugin/$plugin.php");
if (function_exists($plugin . '_plugin_admin')) {
$func = $plugin . '_plugin_admin';
$func($a, $admin_form);
}
}
$t = get_markup_template('admin_plugins_details.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Addons'),
'$toggle' => t('Toggle'),
'$settings' => t('Settings'),
'$baseurl' => z_root(),
$t = get_markup_template('admin_plugins_details.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Addons'),
'$toggle' => t('Toggle'),
'$settings' => t('Settings'),
'$baseurl' => z_root(),
'$plugin' => $plugin,
'$status' => $status,
'$action' => $action,
'$info' => $info,
'$str_author' => t('Author: '),
'$str_maintainer' => t('Maintainer: '),
'$str_minversion' => t('Minimum project version: '),
'$str_maxversion' => t('Maximum project version: '),
'$str_minphpversion' => t('Minimum PHP version: '),
'$str_serverroles' => t('Compatible Server Roles: '),
'$str_requires' => t('Requires: '),
'$disabled' => t('Disabled - version incompatibility'),
'$plugin' => $plugin,
'$status' => $status,
'$action' => $action,
'$info' => $info,
'$str_author' => t('Author: '),
'$str_maintainer' => t('Maintainer: '),
'$str_minversion' => t('Minimum project version: '),
'$str_maxversion' => t('Maximum project version: '),
'$str_minphpversion' => t('Minimum PHP version: '),
'$str_serverroles' => t('Compatible Server Roles: '),
'$str_requires' => t('Requires: '),
'$disabled' => t('Disabled - version incompatibility'),
'$admin_form' => $admin_form,
'$function' => 'addons',
'$screenshot' => '',
'$readme' => $readme,
'$admin_form' => $admin_form,
'$function' => 'addons',
'$screenshot' => '',
'$readme' => $readme,
'$form_security_token' => get_form_security_token('admin_addons'),
));
}
'$form_security_token' => get_form_security_token('admin_addons'),
));
}
/*
* List plugins
*/
$plugins = [];
$files = glob('addon/*/');
if($files) {
foreach($files as $file) {
if ($file === 'addon/vendor/') {
continue;
}
if (is_dir($file)){
list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id);
$enabled = in_array($id,\App::$plugins);
$x = check_plugin_versions($info);
/*
* List plugins
*/
$plugins = [];
$files = glob('addon/*/');
if ($files) {
foreach ($files as $file) {
if ($file === 'addon/vendor/') {
continue;
}
if (is_dir($file)) {
list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id);
$enabled = in_array($id, App::$plugins);
$x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions
// disable plugins which are installed but incompatible versions
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($id, \App::$plugins);
if ($idz !== false) {
unset(\App::$plugins[$idz]);
uninstall_plugin($id);
set_config("system","addon", implode(", ",\App::$plugins));
}
}
$info['disabled'] = 1-intval($x);
if ($enabled && !$x) {
$enabled = false;
$idz = array_search($id, App::$plugins);
if ($idz !== false) {
unset(App::$plugins[$idz]);
uninstall_plugin($id);
set_config("system", "addon", implode(", ", App::$plugins));
}
}
$info['disabled'] = 1 - intval($x);
$plugins[] = array( $id, (($enabled)?"on":"off") , $info);
}
}
}
$plugins[] = array($id, (($enabled) ? "on" : "off"), $info);
}
}
}
usort($plugins,'self::plugin_sort');
usort($plugins, 'self::plugin_sort');
$allowManageRepos = false;
if(is_writable('extend/addon') && is_writable('cache')) {
$allowManageRepos = true;
}
$allowManageRepos = false;
if (is_writable('extend/addon') && is_writable('cache')) {
$allowManageRepos = true;
}
$admin_plugins_add_repo_form= replace_macros(
get_markup_template('admin_plugins_addrepo.tpl'), array(
'$post' => 'admin/addons/addrepo',
'$desc' => t('Enter the public git repository URL of the addon repo.'),
'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
'$submit' => t('Download Addon Repo')
)
);
$newRepoModalID = random_string(3);
$newRepoModal = replace_macros(
get_markup_template('generic_modal.tpl'), array(
'$id' => $newRepoModalID,
'$title' => t('Install new repo'),
'$ok' => t('Install'),
'$cancel' => t('Cancel')
)
);
$admin_plugins_add_repo_form = replace_macros(
get_markup_template('admin_plugins_addrepo.tpl'),
array(
'$post' => 'admin/addons/addrepo',
'$desc' => t('Enter the public git repository URL of the addon repo.'),
'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
'$submit' => t('Download Addon Repo')
)
);
$newRepoModalID = random_string(3);
$newRepoModal = replace_macros(
get_markup_template('generic_modal.tpl'),
array(
'$id' => $newRepoModalID,
'$title' => t('Install new repo'),
'$ok' => t('Install'),
'$cancel' => t('Cancel')
)
);
$reponames = $this->listAddonRepos();
$addonrepos = [];
foreach($reponames as $repo) {
$addonrepos[] = array('name' => $repo, 'description' => '');
/// @TODO Parse repo info to provide more information about repos
}
$reponames = $this->listAddonRepos();
$addonrepos = [];
foreach ($reponames as $repo) {
$addonrepos[] = array('name' => $repo, 'description' => '');
/// @TODO Parse repo info to provide more information about repos
}
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Addons'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$function' => 'addons',
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_addons'),
'$allowManageRepos' => $allowManageRepos,
'$managerepos' => t('Manage Repos'),
'$installedtitle' => t('Installed Addon Repositories'),
'$addnewrepotitle' => t('Install a New Addon Repository'),
'$expandform' => false,
'$form' => $admin_plugins_add_repo_form,
'$newRepoModal' => $newRepoModal,
'$newRepoModalID' => $newRepoModalID,
'$addonrepos' => $addonrepos,
'$repoUpdateButton' => t('Update'),
'$repoBranchButton' => t('Switch branch'),
'$repoRemoveButton' => t('Remove')
));
}
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Addons'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$function' => 'addons',
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_addons'),
'$allowManageRepos' => $allowManageRepos,
'$managerepos' => t('Manage Repos'),
'$installedtitle' => t('Installed Addon Repositories'),
'$addnewrepotitle' => t('Install a New Addon Repository'),
'$expandform' => false,
'$form' => $admin_plugins_add_repo_form,
'$newRepoModal' => $newRepoModal,
'$newRepoModalID' => $newRepoModalID,
'$addonrepos' => $addonrepos,
'$repoUpdateButton' => t('Update'),
'$repoBranchButton' => t('Switch branch'),
'$repoRemoveButton' => t('Remove')
));
}
function listAddonRepos() {
$addonrepos = [];
$addonDir = 'extend/addon/';
if(is_dir($addonDir)) {
if ($handle = opendir($addonDir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$addonrepos[] = $entry;
}
}
closedir($handle);
}
}
return $addonrepos;
}
static public function plugin_sort($a,$b) {
return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
}
public function listAddonRepos()
{
$addonrepos = [];
$addonDir = 'extend/addon/';
if (is_dir($addonDir)) {
if ($handle = opendir($addonDir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$addonrepos[] = $entry;
}
}
closedir($handle);
}
}
return $addonrepos;
}
public static function plugin_sort($a, $b)
{
return (strcmp(strtolower($a[2]['name']), strtolower($b[2]['name'])));
}
}

View file

@ -9,175 +9,191 @@ use Zotlabs\Daemon\Run;
* @brief Admin Module for Channels.
*
*/
class Channels
{
class Channels {
/**
* @brief Handle POST actions on channels admin page.
*
*/
public function post()
{
/**
* @brief Handle POST actions on channels admin page.
*
*/
function post() {
$channels = (x($_POST, 'channel') ? $_POST['channel'] : array());
$channels = ( x($_POST, 'channel') ? $_POST['channel'] : Array() );
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels');
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels');
$xor = db_getfunc('^');
$xor = db_getfunc('^');
if (x($_POST, 'page_channels_block')) {
foreach ($channels as $uid) {
q(
"UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d",
intval(PAGE_CENSORED),
intval($uid)
);
Run::Summon(['Directory', $uid, 'nopush']);
}
notice(sprintf(tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)));
}
if (x($_POST, 'page_channels_code')) {
foreach ($channels as $uid) {
q(
"UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d",
intval(PAGE_ALLOWCODE),
intval($uid)
);
}
notice(sprintf(tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels)));
}
if (x($_POST, 'page_channels_delete')) {
foreach ($channels as $uid) {
channel_remove($uid, true);
}
notice(sprintf(tt("%s channel deleted", "%s channels deleted", count($channels)), count($channels)));
}
if(x($_POST, 'page_channels_block')) {
foreach($channels as $uid) {
q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d",
intval(PAGE_CENSORED),
intval( $uid )
);
Run::Summon( [ 'Directory', $uid, 'nopush' ] );
}
notice( sprintf( tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)) );
}
if(x($_POST, 'page_channels_code')) {
foreach($channels as $uid) {
q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d",
intval(PAGE_ALLOWCODE),
intval( $uid )
);
}
notice( sprintf( tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels)) );
}
if(x($_POST, 'page_channels_delete')) {
foreach($channels as $uid) {
channel_remove($uid, true);
}
notice( sprintf( tt("%s channel deleted", "%s channels deleted", count($channels)), count($channels)) );
}
goaway(z_root() . '/admin/channels');
}
goaway(z_root() . '/admin/channels' );
}
/**
* @brief Generate channels admin page and handle single item operations.
*
* @return string with parsed HTML
*/
public function get()
{
if (argc() > 2) {
$uid = argv(3);
$channel = q(
"SELECT * FROM channel WHERE channel_id = %d",
intval($uid)
);
/**
* @brief Generate channels admin page and handle single item operations.
*
* @return string with parsed HTML
*/
function get() {
if(argc() > 2) {
$uid = argv(3);
$channel = q("SELECT * FROM channel WHERE channel_id = %d",
intval($uid)
);
if (!$channel) {
notice(t('Channel not found') . EOL);
goaway(z_root() . '/admin/channels');
}
if(! $channel) {
notice( t('Channel not found') . EOL);
goaway(z_root() . '/admin/channels' );
}
switch (argv(2)) {
case "delete":
{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
// delete channel
channel_remove($uid, true);
switch(argv(2)) {
case "delete":{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
// delete channel
channel_remove($uid,true);
notice(sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL);
}
break;
notice( sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL);
}; break;
case "block":
{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
$pflags = $channel[0]['channel_pageflags'] ^ PAGE_CENSORED;
q(
"UPDATE channel SET channel_pageflags = %d where channel_id = %d",
intval($pflags),
intval($uid)
);
Run::Summon(['Directory', $uid, 'nopush']);
case "block":{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
$pflags = $channel[0]['channel_pageflags'] ^ PAGE_CENSORED;
q("UPDATE channel SET channel_pageflags = %d where channel_id = %d",
intval($pflags),
intval( $uid )
);
Run::Summon( [ 'Directory', $uid, 'nopush' ]);
notice(sprintf((($pflags & PAGE_CENSORED) ? t("Channel '%s' censored") : t("Channel '%s' uncensored")), $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')') . EOL);
}
break;
notice( sprintf( (($pflags & PAGE_CENSORED) ? t("Channel '%s' censored"): t("Channel '%s' uncensored")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL);
}; break;
case "code":
{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
$pflags = $channel[0]['channel_pageflags'] ^ PAGE_ALLOWCODE;
q(
"UPDATE channel SET channel_pageflags = %d where channel_id = %d",
intval($pflags),
intval($uid)
);
case "code":{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
$pflags = $channel[0]['channel_pageflags'] ^ PAGE_ALLOWCODE;
q("UPDATE channel SET channel_pageflags = %d where channel_id = %d",
intval($pflags),
intval( $uid )
);
notice(sprintf((($pflags & PAGE_ALLOWCODE) ? t("Channel '%s' code allowed") : t("Channel '%s' code disallowed")), $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')') . EOL);
}
break;
notice( sprintf( (($pflags & PAGE_ALLOWCODE) ? t("Channel '%s' code allowed"): t("Channel '%s' code disallowed")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL);
}; break;
default:
break;
}
goaway(z_root() . '/admin/channels');
}
default:
break;
}
goaway(z_root() . '/admin/channels' );
}
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id');
$dir = 'asc';
if (array_key_exists('dir', $_REQUEST)) {
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
}
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id');
$dir = 'asc';
if(array_key_exists('dir',$_REQUEST))
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
$base = z_root() . '/admin/channels?f=';
$odir = (($dir === 'asc') ? '0' : '1');
$base = z_root() . '/admin/channels?f=';
$odir = (($dir === 'asc') ? '0' : '1');
/* get channels */
/* get channels */
$total = q("SELECT count(*) as total FROM channel where channel_removed = 0 and channel_system = 0");
if ($total) {
App::set_pager_total($total[0]['total']);
App::set_pager_itemspage(100);
}
$total = q("SELECT count(*) as total FROM channel where channel_removed = 0 and channel_system = 0");
if($total) {
App::set_pager_total($total[0]['total']);
App::set_pager_itemspage(100);
}
$channels = q(
"SELECT * from channel where channel_removed = 0 and channel_system = 0 order by $key $dir limit %d offset %d ",
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
$channels = q("SELECT * from channel where channel_removed = 0 and channel_system = 0 order by $key $dir limit %d offset %d ",
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
if ($channels) {
for ($x = 0; $x < count($channels); $x++) {
if ($channels[$x]['channel_pageflags'] & PAGE_CENSORED) {
$channels[$x]['blocked'] = true;
} else {
$channels[$x]['blocked'] = false;
}
if($channels) {
for($x = 0; $x < count($channels); $x ++) {
if($channels[$x]['channel_pageflags'] & PAGE_CENSORED)
$channels[$x]['blocked'] = true;
else
$channels[$x]['blocked'] = false;
if ($channels[$x]['channel_pageflags'] & PAGE_ALLOWCODE) {
$channels[$x]['allowcode'] = true;
} else {
$channels[$x]['allowcode'] = false;
}
if($channels[$x]['channel_pageflags'] & PAGE_ALLOWCODE)
$channels[$x]['allowcode'] = true;
else
$channels[$x]['allowcode'] = false;
$channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address'];
}
}
$channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address'];
}
}
call_hooks('admin_channels', $channels);
call_hooks('admin_channels',$channels);
$o = replace_macros(get_markup_template('admin_channels.tpl'), [
// strings //
'$title' => t('Administration'),
'$page' => t('Channels'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
'$delete' => t('Delete'),
'$block' => t('Censor'),
'$unblock' => t('Uncensor'),
'$code' => t('Allow Code'),
'$uncode' => t('Disallow Code'),
'$h_channels' => t('Channel'),
'$base' => $base,
'$odir' => $odir,
'$th_channels' => array(
[t('UID'), 'channel_id'],
[t('Name'), 'channel_name'],
[t('Address'), 'channel_address']),
$o = replace_macros(get_markup_template('admin_channels.tpl'), [
// strings //
'$title' => t('Administration'),
'$page' => t('Channels'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
'$delete' => t('Delete'),
'$block' => t('Censor'),
'$unblock' => t('Uncensor'),
'$code' => t('Allow Code'),
'$uncode' => t('Disallow Code'),
'$h_channels' => t('Channel'),
'$base' => $base,
'$odir' => $odir,
'$th_channels' => array(
[ t('UID'), 'channel_id' ],
[ t('Name'), 'channel_name' ],
[ t('Address'), 'channel_address' ]),
'$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => get_form_security_token('admin_channels'),
'$form_security_token' => get_form_security_token('admin_channels'),
// values //
'$baseurl' => z_root(),
'$channels' => $channels,
]);
$o .= paginate($a);
return $o;
}
// values //
'$baseurl' => z_root(),
'$channels' => $channels,
]);
$o .= paginate($a);
return $o;
}
}

View file

@ -1,4 +1,5 @@
<?php
namespace Zotlabs\Module\Admin;
use App;
@ -25,422 +26,419 @@ require_once('include/photos.php');
* @return void
*
*/
class Cover_photo {
function init() {
if (! is_site_admin()) {
return;
}
$channel = get_sys_channel();
Libprofile::load($channel['channel_address']);
}
/**
* @brief Evaluate posted values
*
* @return void
*
*/
function post() {
if (! is_site_admin()) {
return;
}
$channel = get_sys_channel();
check_form_security_token_redirectOnErr('/admin/cover_photo', 'cover_photo');
if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
// phase 2 - we have finished cropping
if (argc() != 3) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(2);
if (substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
$srcH = intval($_POST['yfinal']) - $srcY;
$r = q("select gender from profile where uid = %d and is_default = 1 limit 1",
intval($channel['channel_id'])
);
if ($r) {
$profile = array_shift($r);
}
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1",
dbesc($image_id),
intval($channel['channel_id'])
);
if ($r) {
$max_thumb = intval(get_config('system','max_thumbnail',1600));
$iscaled = false;
if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
$fname = dbunescbin($r[0]['content']);
$tmp_name = $fname . '-001';
$newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
// logger('imagick thumbnail command: ' . $cmd);
for ($x = 0; $x < 4; $x ++) {
exec($cmd);
if (file_exists($tmp_name)) {
break;
}
}
if (file_exists($tmp_name)) {
$base_image = $r[0];
$gis = getimagesize($tmp_name);
logger('gis: ' . print_r($gis,true));
$base_image['width'] = $gis[0];
$base_image['height'] = $gis[1];
$base_image['content'] = @file_get_contents($tmp_name);
$iscaled = true;
@unlink($tmp_name);
}
}
}
if (! $iscaled) {
$base_image = $r[0];
$base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
}
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if ($im->is_valid()) {
// We are scaling and cropping the relative pixel locations to the original photo instead of the
// scaled photo we operated on.
// First load the scaled photo to check its size. (Should probably pass this in the post form and save
// a query.)
$g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3",
dbesc($image_id),
intval($channel['channel_id'])
);
$scaled_width = $g[0]['width'];
$scaled_height = $g[0]['height'];
if ((! $scaled_width) || (! $scaled_height)) {
logger('potential divide by zero scaling cover photo');
return;
}
// unset all other cover photos
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval($channel['channel_id'])
);
$orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX;
$orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY;
$orig_srcw = ( $srcW / $scaled_width ) * $base_image['width'];
$orig_srch = ( $srcH / $scaled_height ) * $base_image['height'];
$im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch);
$aid = get_account_id();
$p = [
'aid' => 0,
'uid' => $channel['channel_id'],
'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'],
'album' => t('Cover Photos'),
'os_path' => $base_image['os_path'],
'display_path' => $base_image['display_path'],
'created' => $base_image['created'],
'edited' => $base_image['edited']
];
$p['imgscale'] = 7;
$p['photo_usage'] = PHOTO_COVER;
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
$im->doScaleImage(850,310);
$p['imgscale'] = 8;
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
$im->doScaleImage(425,160);
$p['imgscale'] = 9;
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ",
dbesc($base_image['resource_id']),
intval($channel['channel_id'])
);
return;
}
}
else
notice( t('Unable to process image') . EOL);
}
goaway(z_root() . '/admin');
}
$hash = photo_new_resource();
$smallest = 0;
$matches = [];
$partial = false;
if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
if ($pm) {
logger('Content-Range: ' . print_r($matches,true));
$partial = true;
}
}
if ($partial) {
$x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($x);
}
else {
header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
$_FILES['userfile'] = [
'name' => $x['name'],
'type' => $x['type'],
'tmp_name' => $x['tmp_name'],
'error' => $x['error'],
'size' => $x['size']
];
}
}
else {
if (! array_key_exists('userfile',$_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
'tmp_name' => $_FILES['files']['tmp_name'],
'error' => $_FILES['files']['error'],
'size' => $_FILES['files']['size']
];
}
}
$res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Cover Photos'), 'hash' => $hash));
logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG);
json_return_and_die([ 'message' => $hash ]);
}
/**
* @brief Generate content of profile-photo view
*
* @return string
*
*/
function get() {
if (! is_site_admin()) {
notice( t('Permission denied.') . EOL );
return;
}
$channel = get_sys_channel();
$newuser = false;
if (argc() == 3 && argv(1) === 'new')
$newuser = true;
if (argv(2) === 'reset') {
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval($channel['channel_id'])
);
}
if (argv(2) === 'use') {
if (argc() < 4) {
notice( t('Permission denied.') . EOL );
return;
};
// check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
$resource_id = argv(3);
$r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC",
intval($channel['channel_id']),
dbesc($resource_id)
);
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
$havescale = false;
foreach ($r as $rr) {
if ($rr['imgscale'] == 7) {
$havescale = true;
}
}
$r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
intval($r[0]['id']),
intval($channel['channel_id'])
);
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
}
else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($r[0]['resource_id']),
intval($channel['channel_id'])
);
if ($i) {
$hash = $i[0]['resource_id'];
foreach ($i as $ii) {
$smallest = intval($ii['imgscale']);
}
}
}
$this->cover_photo_crop_ui_head($ph, $hash, $smallest);
}
if(! array_key_exists('imagecrop',App::$data)) {
$o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [
'$user' => $channel['channel_address'],
'$channel_id' => $channel['channel_id'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo($channel['channel_id'],'array',PHOTO_RES_COVER_850),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => t('Change Cover Photo'),
'$submit' => t('Upload'),
'$profiles' => $profiles,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$select' => t('Select previously uploaded photo'),
]);
call_hooks('cover_photo_content_end', $o);
return $o;
}
else {
$filename = App::$data['imagecrop'] . '-3';
$resolution = 3;
$o .= replace_macros(get_markup_template('admin_cropcover.tpl'), [
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-3',
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$done' => t('Done Editing')
]);
return $o;
}
}
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
* @param $ph Photo-Factory
* @return void
*
*/
function cover_photo_crop_ui_head($ph, $hash, $smallest){
$max_length = get_config('system','max_image_length', MAX_IMAGE_LENGTH);
if ($max_length > 0) {
$ph->scaleImage($max_length);
}
$width = $ph->getWidth();
$height = $ph->getHeight();
if ($width < 300 || $height < 300) {
$ph->scaleImageUp(240);
$width = $ph->getWidth();
$height = $ph->getHeight();
}
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []);
return;
}
class Cover_photo
{
public function init()
{
if (!is_site_admin()) {
return;
}
$channel = get_sys_channel();
Libprofile::load($channel['channel_address']);
}
/**
* @brief Evaluate posted values
*
* @return void
*
*/
public function post()
{
if (!is_site_admin()) {
return;
}
$channel = get_sys_channel();
check_form_security_token_redirectOnErr('/admin/cover_photo', 'cover_photo');
if ((array_key_exists('cropfinal', $_POST)) && ($_POST['cropfinal'] == 1)) {
// phase 2 - we have finished cropping
if (argc() != 3) {
notice(t('Image uploaded but image cropping failed.') . EOL);
return;
}
$image_id = argv(2);
if (substr($image_id, -2, 1) == '-') {
$scale = substr($image_id, -1, 1);
$image_id = substr($image_id, 0, -2);
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
$srcH = intval($_POST['yfinal']) - $srcY;
$r = q(
"select gender from profile where uid = %d and is_default = 1 limit 1",
intval($channel['channel_id'])
);
if ($r) {
$profile = array_shift($r);
}
$r = q(
"SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1",
dbesc($image_id),
intval($channel['channel_id'])
);
if ($r) {
$max_thumb = intval(get_config('system', 'max_thumbnail', 1600));
$iscaled = false;
if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
$imagick_path = get_config('system', 'imagick_convert_path');
if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
$fname = dbunescbin($r[0]['content']);
$tmp_name = $fname . '-001';
$newsize = photo_calculate_scale(array_merge(getimagesize($fname), ['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
// logger('imagick thumbnail command: ' . $cmd);
for ($x = 0; $x < 4; $x++) {
exec($cmd);
if (file_exists($tmp_name)) {
break;
}
}
if (file_exists($tmp_name)) {
$base_image = $r[0];
$gis = getimagesize($tmp_name);
logger('gis: ' . print_r($gis, true));
$base_image['width'] = $gis[0];
$base_image['height'] = $gis[1];
$base_image['content'] = @file_get_contents($tmp_name);
$iscaled = true;
@unlink($tmp_name);
}
}
}
if (!$iscaled) {
$base_image = $r[0];
$base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
}
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if ($im->is_valid()) {
// We are scaling and cropping the relative pixel locations to the original photo instead of the
// scaled photo we operated on.
// First load the scaled photo to check its size. (Should probably pass this in the post form and save
// a query.)
$g = q(
"select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3",
dbesc($image_id),
intval($channel['channel_id'])
);
$scaled_width = $g[0]['width'];
$scaled_height = $g[0]['height'];
if ((!$scaled_width) || (!$scaled_height)) {
logger('potential divide by zero scaling cover photo');
return;
}
// unset all other cover photos
q(
"update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval($channel['channel_id'])
);
$orig_srcx = ($base_image['width'] / $scaled_width) * $srcX;
$orig_srcy = ($base_image['height'] / $scaled_height) * $srcY;
$orig_srcw = ($srcW / $scaled_width) * $base_image['width'];
$orig_srch = ($srcH / $scaled_height) * $base_image['height'];
$im->cropImageRect(1200, 435, $orig_srcx, $orig_srcy, $orig_srcw, $orig_srch);
$aid = get_account_id();
$p = [
'aid' => 0,
'uid' => $channel['channel_id'],
'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'],
'album' => t('Cover Photos'),
'os_path' => $base_image['os_path'],
'display_path' => $base_image['display_path'],
'created' => $base_image['created'],
'edited' => $base_image['edited']
];
$p['imgscale'] = 7;
$p['photo_usage'] = PHOTO_COVER;
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
$im->doScaleImage(850, 310);
$p['imgscale'] = 8;
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
$im->doScaleImage(425, 160);
$p['imgscale'] = 9;
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice(t('Image resize failed.') . EOL);
$x = q(
"delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ",
dbesc($base_image['resource_id']),
intval($channel['channel_id'])
);
return;
}
} else {
notice(t('Unable to process image') . EOL);
}
}
goaway(z_root() . '/admin');
}
$hash = photo_new_resource();
$smallest = 0;
$matches = [];
$partial = false;
if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches);
if ($pm) {
logger('Content-Range: ' . print_r($matches, true));
$partial = true;
}
}
if ($partial) {
$x = save_chunk($channel, $matches[1], $matches[2], $matches[3]);
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($x);
} else {
header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
$_FILES['userfile'] = [
'name' => $x['name'],
'type' => $x['type'],
'tmp_name' => $x['tmp_name'],
'error' => $x['error'],
'size' => $x['size']
];
}
} else {
if (!array_key_exists('userfile', $_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
'tmp_name' => $_FILES['files']['tmp_name'],
'error' => $_FILES['files']['error'],
'size' => $_FILES['files']['size']
];
}
}
$res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Cover Photos'), 'hash' => $hash));
logger('attach_store: ' . print_r($res, true), LOGGER_DEBUG);
json_return_and_die(['message' => $hash]);
}
/**
* @brief Generate content of profile-photo view
*
* @return string
*
*/
public function get()
{
if (!is_site_admin()) {
notice(t('Permission denied.') . EOL);
return;
}
$channel = get_sys_channel();
$newuser = false;
if (argc() == 3 && argv(1) === 'new') {
$newuser = true;
}
if (argv(2) === 'reset') {
q(
"update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval($channel['channel_id'])
);
}
if (argv(2) === 'use') {
if (argc() < 4) {
notice(t('Permission denied.') . EOL);
return;
}
// check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
$resource_id = argv(3);
$r = q(
"SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC",
intval($channel['channel_id']),
dbesc($resource_id)
);
if (!$r) {
notice(t('Photo not available.') . EOL);
return;
}
$havescale = false;
foreach ($r as $rr) {
if ($rr['imgscale'] == 7) {
$havescale = true;
}
}
$r = q(
"SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
intval($r[0]['id']),
intval($channel['channel_id'])
);
if (!$r) {
notice(t('Photo not available.') . EOL);
return;
}
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
} else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q(
"select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($r[0]['resource_id']),
intval($channel['channel_id'])
);
if ($i) {
$hash = $i[0]['resource_id'];
foreach ($i as $ii) {
$smallest = intval($ii['imgscale']);
}
}
}
$this->cover_photo_crop_ui_head($ph, $hash, $smallest);
}
if (!array_key_exists('imagecrop', App::$data)) {
$o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [
'$user' => $channel['channel_address'],
'$channel_id' => $channel['channel_id'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo($channel['channel_id'], 'array', PHOTO_RES_COVER_850),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => t('Change Cover Photo'),
'$submit' => t('Upload'),
'$profiles' => $profiles,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$select' => t('Select previously uploaded photo'),
]);
call_hooks('cover_photo_content_end', $o);
return $o;
} else {
$filename = App::$data['imagecrop'] . '-3';
$resolution = 3;
$o .= replace_macros(get_markup_template('admin_cropcover.tpl'), [
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => App::$data['imagecrop'] . '-3',
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$done' => t('Done Editing')
]);
return $o;
}
}
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
* @param $ph Photo-Factory
* @return void
*
*/
public function cover_photo_crop_ui_head($ph, $hash, $smallest)
{
$max_length = get_config('system', 'max_image_length', MAX_IMAGE_LENGTH);
if ($max_length > 0) {
$ph->scaleImage($max_length);
}
$width = $ph->getWidth();
$height = $ph->getHeight();
if ($width < 300 || $height < 300) {
$ph->scaleImageUp(240);
$width = $ph->getWidth();
$height = $ph->getHeight();
}
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []);
return;
}
}

Some files were not shown because too many files have changed in this diff Show more