diff options
Diffstat (limited to 'Zotlabs')
35 files changed, 850 insertions, 621 deletions
diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php index c8cdafdf5..55d485a5b 100644 --- a/Zotlabs/Daemon/Directory.php +++ b/Zotlabs/Daemon/Directory.php @@ -2,6 +2,10 @@ namespace Zotlabs\Daemon; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Libzotdir; +use Zotlabs\Lib\Queue; + require_once('include/zot.php'); require_once('include/dir_fns.php'); require_once('include/queue_fn.php'); @@ -42,7 +46,7 @@ class Directory { // this is an in-memory update and we don't need to send a network packet. - local_dir_update($argv[1],$force); + Libzotdir::local_dir_update($argv[1],$force); q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), @@ -58,13 +62,15 @@ class Directory { // otherwise send the changes upstream - $directory = find_upstream_directory($dirmode); + $directory = Libzotdir::find_upstream_directory($dirmode); $url = $directory['url'] . '/post'; // ensure the upstream directory is updated - $packet = zot_build_packet($channel,(($force) ? 'force_refresh' : 'refresh')); - $z = zot_zot($url,$packet); + + $packet = Libzot::build_packet($channel,(($force) ? 'force_refresh' : 'refresh')); + $z = Libzot::zot($url,$packet,$channel); + // re-queue if unsuccessful @@ -76,7 +82,7 @@ class Directory { $hash = random_string(); - queue_insert(array( + Queue::insert(array( 'hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php index f1ffb2d81..6951aa1d4 100644 --- a/Zotlabs/Daemon/Gprobe.php +++ b/Zotlabs/Daemon/Gprobe.php @@ -2,7 +2,9 @@ namespace Zotlabs\Daemon; -require_once('include/zot.php'); +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Webfinger; +use Zotlabs\Lib\Zotfinger; // performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress @@ -22,12 +24,16 @@ class Gprobe { ); if(! $r) { - $j = \Zotlabs\Zot\Finger::run($url,null); - if($j['success']) { - $y = import_xchan($j); + $href = Webfinger::zot_url(punify($url)); + if($href) { + $zf = Zotfinger::exec($href, null); + } + 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']); } } return; + } } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 0efa93cce..8ea75af61 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -45,18 +45,18 @@ require_once('include/bbcode.php'); * * where COMMAND is one of the following: * - * activity (in diaspora.php, dfrn_confirm.php, profiles.php) - * comment-import (in diaspora.php, items.php) - * comment-new (in item.php) - * drop (in diaspora.php, items.php, photos.php) - * edit_post (in item.php) - * event (in events.php) - * expire (in items.php) - * like (in like.php, poke.php) - * mail (in message.php) - * tag (in photos.php, poke.php, tagger.php) - * tgroup (in items.php) - * wall-new (in photos.php, item.php) + * activity (in diaspora.php, dfrn_confirm.php, profiles.php) + * comment-import (in diaspora.php, items.php) + * comment-new (in item.php) + * drop (in diaspora.php, items.php, photos.php) + * edit_post (in item.php) + * event (in events.php) + * expire (in items.php) + * like (in like.php, poke.php) + * mail (in message.php) + * tag (in photos.php, poke.php, tagger.php) + * tgroup (in items.php) + * wall-new (in photos.php, item.php) * * and ITEM_ID is the id of the item in the database that needs to be sent to others. * @@ -66,9 +66,10 @@ require_once('include/bbcode.php'); * permission_reject abook_id * permission_update abook_id * refresh_all channel_id + * purge channel_id xchan_hash * purge_all channel_id * expire channel_id - * relay item_id (item was relayed to owner, we will deliver it as owner) + * relay item_id (item was relayed to owner, we will deliver it as owner) * single_activity item_id (deliver to a singleton network from the appropriate clone) * single_mail mail_id (deliver to a singleton network from the appropriate clone) * location channel_id @@ -240,25 +241,40 @@ class Notifier { $packet_type = 'location'; $location = true; } + elseif($cmd === 'purge') { + $xchan = $argv[3]; + logger('notifier: purge: ' . $item_id . ' => ' . $xchan); + if (! $xchan) { + return; + } + + $channel = channelx_by_n($item_id); + $recipients[] = $xchan; + $private = true; + $packet_type = 'purge'; + $packet_recips[] = ['hash' => $xchan]; + } elseif($cmd === 'purge_all') { + logger('notifier: purge_all: ' . $item_id); - $s = q("select * from channel where channel_id = %d limit 1", - intval($item_id) - ); - if($s) - $channel = $s[0]; - $uid = $item_id; - $recipients = array(); + $channel = channelx_by_n($item_id); + + $recipients = []; $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0", intval($item_id) ); - if($r) { - foreach($r as $rr) { - $recipients[] = $rr['abook_xchan']; - } + if (! $r) { + return; + } + foreach ($r as $rr) { + $recipients[] = $rr['abook_xchan']; + $packet_recips[] = ['hash' => $rr['abook_xchan']]; } + $private = false; $packet_type = 'purge'; + + } else { @@ -278,6 +294,12 @@ class Notifier { $r = fetch_post_tags($r); $target_item = $r[0]; + + if(in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) { + logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG); + return; + } + $deleted_item = false; if(intval($target_item['item_deleted'])) { @@ -379,7 +401,6 @@ class Notifier { logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG); logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG); - // Send comments to the owner to re-deliver to everybody in the conversation // We only do this if the item in question originated on this site. This prevents looping. // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay. @@ -542,17 +563,40 @@ class Notifier { // Now we have collected recipients (except for external mentions, FIXME) // Let's reduce this to a set of hubs; checking that the site is not dead. - $r = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ") - and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) " + $hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc left join site on site_url = hubloc_url + where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ") + and hubloc_error = 0 and hubloc_deleted = 0" ); + + // public posts won't make it to the local public stream unless there's a recipient on this site. + // This code block sees if it's a public post and localhost is missing, and if so adds an entry for the local sys channel to the $hubs list + + if (! $private) { + $found_localhost = false; + if ($hubs) { + foreach ($hubs as $h) { + if ($h['hubloc_url'] === z_root()) { + $found_localhost = true; + break; + } + } + } + if (! $found_localhost) { + $localhub = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_version, site.site_project, site.site_dead from hubloc + left join site on site_url = hubloc_url where hubloc_id_url = '%s' and hubloc_error = 0 and hubloc_deleted = 0", + dbesc(z_root() . '/channel/sys') + ); + if ($localhub) { + $hubs = array_merge($hubs, $localhub); + } + } + } - if(! $r) { + if(! $hubs) { logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE); return; } - $hubs = $r; - /** * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, * since it may have been a re-install which has not yet been detected and pruned. @@ -565,8 +609,15 @@ class Notifier { $keys = []; // array of keys to check uniquness for zot hubs $urls = []; // array of urls to check uniqueness of hubs from other networks $hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all + $dead = []; // known dead hubs - report them as undeliverable foreach($hubs as $hub) { + + if (intval($hub['site_dead'])) { + $dead[] = $hub; + continue; + } + if($env_recips) { foreach($env_recips as $er) { if($hub['hubloc_hash'] === $er['hash']) { @@ -793,6 +844,24 @@ class Notifier { logger('notifier: basic loop complete.', LOGGER_DEBUG); + if ($dead) { + foreach ($dead as $deceased) { + if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue ) + values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ", + dbesc($target_item['mid']), + dbesc($deceased['hubloc_host']), + dbesc($deceased['hubloc_host']), + dbesc($deceased['hubloc_host']), + dbesc('undeliverable/unresponsive site'), + dbesc(datetime_convert()), + dbesc($channel['channel_hash']), + dbesc(random_string(48)) + ); + } + } + } + call_hooks('notifier_end',$target_item); logger('notifer: complete.'); diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 83c04c042..08e5ffaca 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -168,7 +168,7 @@ class Activity { if($r) { xchan_query($r,true); $r = fetch_post_tags($r,true); - if ($r[0]['verb'] === 'Create' && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) { + if (in_array($r[0]['verb'], ['Create', 'Invite']) && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) { $r[0]['verb'] = 'Invite'; return self::encode_activity($r[0]); } @@ -319,6 +319,26 @@ class Activity { $ret = Activity::encode_object($i['obj']); } + if (intval($i['item_deleted'])) { + $ret['type'] = 'Tombstone'; + $ret['formerType'] = $objtype; + $ret['id'] = $i['mid']; + if($i['id'] != $i['parent']) + $ret['inReplyTo'] = $i['thr_parent']; + + $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + return $ret; + } + + if ($i['obj']) { + if (is_array($i['obj'])) { + $ret = $i['obj']; + } + else { + $ret = json_decode($i['obj'],true); + } + } + $ret['type'] = $objtype; if ($objtype === 'Question') { @@ -632,7 +652,7 @@ class Activity { - static function encode_activity($i) { + static function encode_activity($i, $recurse = false) { $ret = []; $reply = false; @@ -643,41 +663,47 @@ class Activity { $ret['obj'] = []; } - if (intval($i['item_deleted'])) { - $ret['type'] = 'Delete'; - $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . '#delete'; + $ret['type'] = self::activity_mapper($i['verb']); + $fragment = ''; + + if (intval($i['item_deleted']) && !$recurse) { + $is_response = false; + + if (ActivityStreams::is_response_activity($ret['type'])) { + $ret['type'] = 'Undo'; + $fragment = 'undo'; + $is_response = true; + } + else { + $ret['type'] = 'Delete'; + $fragment = 'delete'; + } + + $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . '#' . $fragment; $actor = self::encode_person($i['author'],false); if ($actor) $ret['actor'] = $actor; else return []; - if ($i['obj']) { - if (! is_array($i['obj'])) { - $i['obj'] = json_decode($i['obj'],true); + $obj = (($is_response) ? self::encode_activity($i,true) : self::encode_item($i,true)); + if ($obj) { + if (array_path_exists('object/id',$obj)) { + $obj['object'] = $obj['object']['id']; } - $obj = self::encode_object($i['obj']); - if ($obj) - $ret['object'] = $obj; - else - return []; - } - else { - $obj = self::encode_item($i); - if ($obj) - $ret['object'] = $obj; - else - return []; + unset($obj['cc']); + $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + $ret['object'] = $obj; } + else + return []; $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; + return $ret; } - - $ret['type'] = self::activity_mapper($i['verb']); - if($ret['type'] === 'emojiReaction') { // There may not be an object for these items for legacy reasons - it should be the conversation parent. $p = q("select * from item where mid = '%s' and uid = %d", @@ -1072,6 +1098,8 @@ class Activity { 'http://purl.org/zot/activity/attendno' => 'Reject', 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_mapper',$acts); @@ -1119,6 +1147,8 @@ class Activity { 'http://purl.org/zot/activity/attendno' => 'Reject', 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_decode_mapper',$acts); @@ -1155,7 +1185,9 @@ class Activity { 'Question' => 'Question', 'Document' => 'Document', 'Audio' => 'Audio', - 'Video' => 'Video' + 'Video' => 'Video', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_obj_decode_mapper',$objs); @@ -1192,7 +1224,9 @@ class Activity { 'Invite' => 'Invite', 'Question' => 'Question', 'Audio' => 'Audio', - 'Video' => 'Video' + 'Video' => 'Video', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_obj_mapper',$objs); @@ -1702,6 +1736,23 @@ class Activity { $s['aid'] = $channel['channel_account_id']; $s['uid'] = $channel['channel_id']; + + // Make sure we use the zot6 identity where applicable + + $s['author_xchan'] = self::find_best_identity($s['author_xchan']); + $s['owner_xchan'] = self::find_best_identity($s['owner_xchan']); + + if(!$s['author_xchan']) { + logger('No author: ' . print_r($act, true)); + } + + if(!$s['owner_xchan']) { + logger('No owner: ' . print_r($act, true)); + } + + if(!$s['author_xchan'] || !$s['owner_xchan']) + return; + $s['mid'] = urldecode($act->obj['id']); $s['uuid'] = $act->obj['diaspora:guid']; $s['plink'] = urldecode($act->obj['id']); @@ -2017,13 +2068,13 @@ class Activity { $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); } - if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) { + if(ActivityStreams::is_response_activity($act->type)) { $response_activity = true; $s['mid'] = $act->id; - $s['parent_mid'] = $act->obj['id']; - $s['uuid'] = $act->{'diaspora:guid'}; + // $s['parent_mid'] = $act->obj['id']; + $s['uuid'] = $act->data['diaspora:guid']; // over-ride the object timestamp with the activity @@ -2089,12 +2140,10 @@ class Activity { $s['edited'] = datetime_convert(); } - if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { + if(in_array($act->type, [ 'Delete', 'Undo', 'Tombstone' ]) || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) { $s['item_deleted'] = 1; } - - $s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']); if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { $s['obj_type'] = ACTIVITY_OBJ_COMMENT; @@ -2445,11 +2494,22 @@ class Activity { $item['aid'] = $channel['channel_account_id']; $item['uid'] = $channel['channel_id']; - if(! ( $item['author_xchan'] && $item['owner_xchan'])) { - logger('owner or author missing.'); - return; + // Make sure we use the zot6 identity where applicable + + $item['author_xchan'] = self::find_best_identity($item['author_xchan']); + $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); + + if(!$item['author_xchan']) { + logger('No author: ' . print_r($act, true)); + } + + if(!$item['owner_xchan']) { + logger('No owner: ' . print_r($act, true)); } + if(!$item['author_xchan'] || !$item['owner_xchan']) + return; + if($channel['channel_system']) { if(! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { logger('post is filtered'); @@ -2645,6 +2705,7 @@ class Activity { static public function fetch_and_store_replies($channel, $arr) { logger('fetching replies'); + logger(print_r($arr,true)); $p = []; @@ -2889,7 +2950,7 @@ class Activity { $s['parent_mid'] = $s['mid']; - $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('status')); + $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('post')); $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $parent_item['plink'])); $objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); @@ -3106,5 +3167,45 @@ class Activity { return $content; } + // Find either an Authorization: Bearer token or 'token' request variable + // in the current web request and return it + + static function token_from_request() { + + foreach ( [ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $s ) { + $auth = ((array_key_exists($s,$_SERVER) && strpos($_SERVER[$s],'Bearer ') === 0) + ? str_replace('Bearer ', EMPTY_STR, $_SERVER[$s]) + : EMPTY_STR + ); + if ($auth) { + break; + } + } + + if (! $auth) { + if (array_key_exists('token',$_REQUEST) && $_REQUEST['token']) { + $auth = $_REQUEST['token']; + } + } + + return $auth; + } + + static function find_best_identity($xchan) { + + if(filter_var($xchan, FILTER_VALIDATE_URL)) { + $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' and hubloc_network in ('zot6', 'zot') and hubloc_deleted = 0", + dbesc($xchan) + ); + if ($r) { + $r = Libzot::zot_record_preferred($r); + logger('find_best_identity: ' . $xchan . ' > ' . $r['hubloc_hash']); + return $r['hubloc_hash']; + } + } + + return $xchan; + + } } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index b1ef59364..a0ba52aa6 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -274,12 +274,19 @@ class ActivityStreams { return self::fetch($url); } - static function fetch($url,$channel = null) { - return Activity::fetch($url,$channel); + static function fetch($url, $channel = null) { + return Activity::fetch($url, $channel); } static function is_an_actor($s) { - return(in_array($s,[ 'Application','Group','Organization','Person','Service' ])); + 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' ])); } /** @@ -402,7 +409,6 @@ class ActivityStreams { return $x; } - static function is_as_request() { $x = getBestSupportedMimeType([ @@ -415,5 +421,4 @@ class ActivityStreams { } - } diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php index caac30f7a..481b02ce2 100644 --- a/Zotlabs/Lib/Connect.php +++ b/Zotlabs/Lib/Connect.php @@ -187,12 +187,8 @@ class Connect { // Always set these "remote" permissions for feeds since we cannot interact with them // to negotiate a suitable permission response - $p = get_abconfig($uid,$xchan_hash,'system','their_perms',EMPTY_STR); - if ($p) { - $p .= ','; - } - $p .= 'view_stream,republish'; - set_abconfig($uid,$xchan_hash,'system','their_perms',$p); + set_abconfig($uid,$xchan_hash,'their_perms','view_stream',1); + set_abconfig($uid,$xchan_hash,'their_perms','republish',1); } diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 03a824b9b..c78325ee3 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -966,8 +966,8 @@ class Enotify { 'url' => $rr['xchan_url'], 'photo' => $rr['xchan_photo_s'], 'when' => $when, - 'hclass' => ('notify-unseen'), - 'message' => t('posted an event') + 'hclass' => (($today) ? 'notify-unseen bg-warning' : 'notify-unseen'), + 'message' => t('created an event') ]; return $x; diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index b7cda1770..cff320e11 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -819,9 +819,9 @@ class Libsync { } if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) { - $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d", + $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) + dbesc($r[0]['hubloc_id_url']) ); $r[0]['hubloc_primary'] = intval($location['primary']); hubloc_change_primary($r[0]); @@ -848,18 +848,18 @@ class Libsync { } } if(intval($r[0]['hubloc_deleted']) && (! intval($location['deleted']))) { - $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d", + $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) + dbesc($r[0]['hubloc_id_url']) ); $what .= 'undelete_hub '; $changed = true; } elseif((! intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) { logger('deleting hubloc: ' . $r[0]['hubloc_addr']); - $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", + $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) + dbesc($r[0]['hubloc_id_url']) ); $what .= 'delete_hub '; $changed = true; @@ -918,9 +918,9 @@ class Libsync { foreach($xisting as $x) { if(! array_key_exists('updated',$x)) { logger('Deleting unreferenced hub location ' . $x['hubloc_addr']); - $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", + $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id_url = '%s'", dbesc(datetime_convert()), - intval($x['hubloc_id']) + dbesc($x['hubloc_id_url']) ); $what .= 'removed_hub '; $changed = true; diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index f4eb26463..f0fe3ab24 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -326,14 +326,10 @@ class Libzot { if($permissions && is_array($permissions)) { $old_read_stream_perm = get_abconfig($channel['channel_id'],$x['hash'],'their_perms','view_stream'); - // We need to reset their_perms prior to setting the new ones. - // Otherwise withdrawn permissions will not take effect locally. - q("DELETE FROM abconfig WHERE chan = %d AND xchan = '%s' AND cat = 'their_perms'", - intval($channel['channel_id']), - dbesc($x['hash']) - ); - foreach($permissions as $p) { - set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$p,'1'); + $permissions = Permissions::FilledPerms($permissions); + + foreach($permissions as $k => $v) { + set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$k,$v); } } @@ -1141,6 +1137,7 @@ class Libzot { } logger($AS->debug(),LOGGER_DATA); + } @@ -1201,10 +1198,6 @@ class Libzot { if(in_array($env['type'],['activity','response'])) { - $arr = Activity::decode_note($AS); - - //logger($AS->debug()); - $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' ", dbesc($AS->actor['id']) ); @@ -1215,6 +1208,10 @@ class Libzot { $arr['author_xchan'] = $r['hubloc_hash']; } + if (! $arr['author_xchan']) { + logger('No author!'); + return; + } $s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", dbesc($env['sender']) @@ -1496,13 +1493,14 @@ class Libzot { // Try again using the delivery channel credentials. // We will also need to re-parse the $item array, // but preserve any values that were set during anonymous parsing. - + $o = Activity::fetch($act->obj,$channel); if($o) { $act->obj = $o; $arr = array_merge(Activity::decode_note($act),$arr); } else { + $DR->update('Incomplete or corrupt activity'); $result[] = $DR->get(); continue; @@ -1725,7 +1723,7 @@ class Libzot { $arr['aid'] = $channel['channel_account_id']; $arr['uid'] = $channel['channel_id']; - $item_id = self::delete_imported_item($sender,$arr,$channel['channel_id'],$relay); + $item_id = self::delete_imported_item($sender,$act,$arr,$channel['channel_id'],$relay); $DR->update(($item_id) ? 'deleted' : 'delete_failed'); $result[] = $DR->get(); @@ -1739,11 +1737,15 @@ class Libzot { continue; } + // reactions such as like and dislike could have an mid with /activity/ in it. + // Check for both forms in order to prevent duplicates. - $r = q("select * from item where mid = '%s' and uid = %d limit 1", + $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1", dbesc($arr['mid']), + dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])), intval($channel['channel_id']) ); + if($r) { // We already have this post. $item_id = $r[0]['id']; @@ -2104,7 +2106,7 @@ class Libzot { * @return boolean|int post_id */ - static function delete_imported_item($sender, $item, $uid, $relay) { + static function delete_imported_item($sender, $act, $item, $uid, $relay) { logger('invoked', LOGGER_DEBUG); @@ -2112,38 +2114,39 @@ class Libzot { $item_found = false; $post_id = 0; + if ($item['verb'] === 'Tombstone') { + // The id of the deleted thing is the item mid (activity id) + $mid = $item['mid']; + } + else { + // The id is the object id if the type is Undo or Delete + $mid = ((is_array($act->obj)) ? $act->obj['id'] : $act->obj); + } + + // we may have stored either the object id or the activity id if it was a response activity (like, dislike, etc.) + $r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) - and mid = '%s' and uid = %d limit 1", + and mid IN ('%s', '%s') and uid = %d limit 1", dbesc($sender), dbesc($sender), dbesc($sender), - dbesc($item['mid']), + dbesc($mid), + dbesc(str_replace('/activity/','/item/',$mid)), intval($uid) ); if($r) { $stored = $r[0]; - if($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender) - $ownership_valid = true; + // we proved ownership in the sql query + $ownership_valid = true; $post_id = $stored['id']; $item_found = true; } else { - - // perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set. - // item_store() won't try to deliver any notifications or start delivery chains if this flag is set. - // This means we won't end up with potentially even more delivery threads trying to push this delete notification. - // But this will ensure that if the (undeleted) original post comes in at a later date, we'll reject it because it will have an older timestamp. - - logger('delete received for non-existent item - storing item data.'); - - if($item['author_xchan'] === $sender || $item['owner_xchan'] === $sender || $item['source_xchan'] === $sender) { - $ownership_valid = true; - $item_result = item_store($item); - $post_id = $item_result['item_id']; - } + // this will fail with an ownership issue, so explain the real reason + logger('delete received for non-existent item or not owned by sender - ignoring.'); } if($ownership_valid === false) { diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index 1cb52275c..b02516a98 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -3,6 +3,8 @@ namespace Zotlabs\Lib; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Zotfinger; +use Zotlabs\Lib\Webfinger; require_once('include/permissions.php'); @@ -307,9 +309,9 @@ class Libzotdir { if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { $success = false; - $href = \Zotlabs\Lib\Webfinger::zot_url(punify($ud['ud_addr'])); + $href = Webfinger::zot_url(punify($ud['ud_addr'])); if($href) { - $zf = \Zotlabs\Lib\Zotfinger::exec($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); @@ -339,7 +341,7 @@ class Libzotdir { logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); - $p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", + $p = q("select channel.channel_hash, channel_address, channel_timezone, channel_portable_id, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", intval($uid) ); @@ -348,6 +350,7 @@ class Libzotdir { if ($p) { $hash = $p[0]['channel_hash']; + $legacy_hash = $p[0]['channel_portable_id']; $profile['description'] = $p[0]['pdesc']; $profile['birthday'] = $p[0]['dob']; @@ -381,14 +384,15 @@ class Libzotdir { logger('hidden: ' . $hidden); - $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1", + $r = q("select xchan_hidden from xchan where xchan_hash = '%s'", dbesc($p[0]['channel_hash']) ); if(intval($r[0]['xchan_hidden']) != $hidden) { - $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", + $r = q("update xchan set xchan_hidden = %d where xchan_hash in ('%s', '%s')", intval($hidden), - dbesc($p[0]['channel_hash']) + dbesc($hash), + dbesc($legacy_hash) ); } @@ -402,11 +406,13 @@ class Libzotdir { } else { // they may have made it private - $r = q("delete from xprof where xprof_hash = '%s'", - dbesc($hash) + q("delete from xprof where xprof_hash in ('%s', '%s')", + dbesc($hash), + dbesc($legacy_hash) ); - $r = q("delete from xtag where xtag_hash = '%s'", - dbesc($hash) + q("delete from xtag where xtag_hash in ('%s', '%s')", + dbesc($hash), + dbesc($legacy_hash) ); } diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php index f8b636c10..419e6ed5f 100644 --- a/Zotlabs/Lib/Share.php +++ b/Zotlabs/Lib/Share.php @@ -128,7 +128,7 @@ class Share { "' profile='" . $this->item['author']['xchan_url'] . "' avatar='" . $this->item['author']['xchan_photo_s'] . "' link='" . $this->item['plink'] . - "' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') . + "' auth='" . ((in_array($this->item['author']['xchan_network'], ['zot6', 'zot'])) ? 'true' : 'false') . "' posted='" . $this->item['created'] . "' message_id='" . $this->item['mid'] . "']"; diff --git a/Zotlabs/Lib/Webfinger.php b/Zotlabs/Lib/Webfinger.php index c2364ac4d..611c36889 100644 --- a/Zotlabs/Lib/Webfinger.php +++ b/Zotlabs/Lib/Webfinger.php @@ -106,4 +106,4 @@ class Webfinger { -}
\ No newline at end of file +} diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php index 2d2e6796b..722e34dfc 100644 --- a/Zotlabs/Lib/Zotfinger.php +++ b/Zotlabs/Lib/Zotfinger.php @@ -60,4 +60,4 @@ class Zotfinger { -}
\ No newline at end of file +} diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php index 9971ee60f..b75f0b245 100644 --- a/Zotlabs/Module/Activity.php +++ b/Zotlabs/Module/Activity.php @@ -21,7 +21,6 @@ class Activity extends Controller { if (Libzot::is_zot_request()) { $item_id = argv(1); - if (! $item_id) http_status_exit(404, 'Not found'); @@ -170,6 +169,99 @@ class Activity extends Controller { } + if(ActivityStreams::is_as_request()) { + + $item_id = argv(1); + + if (! $item_id) { + return; + } + + $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; + } + } + } + } + + $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); + } + + // 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); + } + + $r = q("select * from item where uuid = '%s' $item_normal $sql_extra limit 1", + dbesc($item_id) + ); + + if (! $r) { + $r = q("select * from item where uuid = '%s' $item_normal limit 1", + dbesc($item_id) + ); + if($r) { + http_status_exit(403, 'Forbidden'); + } + http_status_exit(404, 'Not found'); + } + + xchan_query($r,true); + $items = fetch_post_tags($r,false); + + $channel = channelx_by_n($items[0]['uid']); + + $x = array_merge( ['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + z_root() . ZOT_APSCHEMA_REV + ]], ZlibActivity::encode_activity($items[0],true)); + + $headers = []; + $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; + $x['signature'] = LDSignatures::sign($x,$channel); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $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['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + + $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel)); + HTTPSig::set_headers($h); + echo $ret; + killme(); + + } + goaway(z_root() . '/item/' . argv(1)); } diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 9c8cddab3..307be048a 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -442,44 +442,12 @@ class Channel extends Controller { } - $update_unseen = ''; - - if($page_mode === 'list') { - - /** - * in "list mode", only mark the parent item and any like activities as "seen". - * We won't distinguish between comment likes and post likes. The important thing - * is that the number of unseen comments will be accurate. The SQL to separate the - * comment likes could also get somewhat hairy. - */ - - if($parents_str) { - $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; - $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; - } - } - else { - if($parents_str) { - $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; - } - } - - if($is_owner && $update_unseen) { - $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; - call_hooks('update_unseen',$x); - if($x['update'] === 'unset' || intval($x['update'])) { - $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen", - intval(local_channel()) - ); - } - } - // Add pinned content if(! x($_REQUEST,'mid') && ! $search) { - $pinned = new \Zotlabs\Widget\Pinned; - $r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]); - $o .= $r['html']; - } + $pinned = new \Zotlabs\Widget\Pinned; + $r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]); + $o .= $r['html']; + } $mode = (($search) ? 'search' : 'channel'); diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php index 20ac41fbe..12e1891d4 100644 --- a/Zotlabs/Module/Chanview.php +++ b/Zotlabs/Module/Chanview.php @@ -1,31 +1,35 @@ <?php namespace Zotlabs\Module; -require_once('include/zot.php'); +use App; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\Webfinger; +use Zotlabs\Lib\Zotfinger; + class Chanview extends \Zotlabs\Web\Controller { function get() { - $observer = \App::get_observer(); + $observer = App::get_observer(); $xchan = null; $r = null; if($_REQUEST['hash']) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", + $r = q("select * from xchan where xchan_hash = '%s'", dbesc($_REQUEST['hash']) ); } if($_REQUEST['address']) { - $r = q("select * from xchan where xchan_addr = '%s' limit 1", + $r = q("select * from xchan where xchan_addr = '%s'", dbesc(punify($_REQUEST['address'])) ); } elseif(local_channel() && intval($_REQUEST['cid'])) { $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d and abook_id = %d LIMIT 1", + WHERE abook_channel = %d and abook_id = %d", intval(local_channel()), intval($_REQUEST['cid']) ); @@ -35,12 +39,12 @@ class Chanview extends \Zotlabs\Web\Controller { // if somebody re-installed they will have more than one xchan, use the most recent name date as this is // the most useful consistently ascending table item we have. - $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc limit 1", + $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc", dbesc($_REQUEST['url']) ); } if($r) { - \App::$poi = $r[0]; + App::$poi = Libzot::zot_record_preferred($r, 'xchan_network'); } @@ -49,43 +53,45 @@ class Chanview extends \Zotlabs\Web\Controller { // address, we can and should try to import it. If it's just a hash, we can't continue, but we // probably wouldn't have a hash if we don't already have an xchan for this channel. - if(! \App::$poi) { + if(! App::$poi) { logger('mod_chanview: fallback'); - // This is hackish - construct a zot address from the url - if($_REQUEST['url']) { - if(preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) { - $_REQUEST['address'] = $matches[3] . '@' . $matches[1]; + + if($_REQUEST['address']) { + $href = Webfinger::zot_url(punify($_REQUEST['address'])); + if($href) { + $_REQUEST['url'] = $href; } - logger('mod_chanview: constructed address ' . print_r($matches,true)); } $r = null; - if($_REQUEST['address']) { - $j = \Zotlabs\Zot\Finger::run($_REQUEST['address'],null); - if($j['success']) { - import_xchan($j); - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($_REQUEST['address']) + if($_REQUEST['url']) { + + $zf = Zotfinger::exec($_REQUEST['url'], null); + + if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $_REQUEST['url'] && intval($zf['signature']['header_valid'])) { + Libzot::import_xchan($j); + $r = q("select * from xchan where xchan_url = '%s'", + dbesc($_REQUEST['url']) ); if($r) { - \App::$poi = $r[0]; + App::$poi = Libzot::zot_record_preferred($r, 'xchan_network'); } } if(! $r) { - if(discover_by_webbie($_REQUEST['address'])) { - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($_REQUEST['address']) + if(discover_by_webbie($_REQUEST['url'])) { + $r = q("select * from xchan where xchan_url = '%s'", + dbesc($_REQUEST['url']) ); if($r) { - \App::$poi = $r[0]; + App::$poi = Libzot::zot_record_preferred($r, 'xchan_network'); } } } } } - if(! \App::$poi) { + if(! App::$poi) { notice( t('Channel not found.') . EOL); return; } @@ -93,19 +99,17 @@ class Chanview extends \Zotlabs\Web\Controller { $is_zot = false; $connected = false; - if (\App::$poi) { - $url = \App::$poi['xchan_url']; - if(in_array(\App::$poi['xchan_network'], ['zot', 'zot6'])) { - $is_zot = true; - } - if(local_channel()) { - $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", - intval(local_channel()), - dbesc(\App::$poi['xchan_hash']) - ); - if($c) - $connected = true; - } + $url = App::$poi['xchan_url']; + if(in_array(App::$poi['xchan_network'], ['zot', 'zot6'])) { + $is_zot = true; + } + if(local_channel()) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval(local_channel()), + dbesc(App::$poi['xchan_hash']) + ); + if($c) + $connected = true; } // We will load the chanview template if it's a foreign network, diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index c0df57390..0fc807d42 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -7,9 +7,16 @@ namespace Zotlabs\Module; * */ +use App; use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Libsync; +use Zotlabs\Daemon\Master; +use Zotlabs\Web\Controller; +use Zotlabs\Access\Permissions; +use Zotlabs\Access\PermissionLimits; +use Zotlabs\Web\HTTPHeaders; +use Zotlabs\Lib\Permcat; require_once('include/socgraph.php'); require_once('include/selectors.php'); @@ -17,7 +24,7 @@ require_once('include/group.php'); require_once('include/photos.php'); -class Connedit extends \Zotlabs\Web\Controller { +class Connedit extends Controller { /* @brief Initialize the connection-editor * @@ -37,12 +44,12 @@ class Connedit extends \Zotlabs\Web\Controller { intval(argv(1)) ); if($r) { - \App::$poi = array_shift($r); + App::$poi = array_shift($r); } } - $channel = \App::get_channel(); + $channel = App::get_channel(); if($channel) head_set_icon($channel['xchan_photo_s']); @@ -62,7 +69,7 @@ class Connedit extends \Zotlabs\Web\Controller { if(! $contact_id) return; - $channel = \App::get_channel(); + $channel = App::get_channel(); // TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the // connection enable is toggled to a special autopost url and set permissions immediately, leaving @@ -141,7 +148,7 @@ class Connedit extends \Zotlabs\Web\Controller { $rating_text = trim(escape_tags($_REQUEST['rating_text'])); - $all_perms = \Zotlabs\Access\Permissions::Perms(); + $all_perms = Permissions::Perms(); if($all_perms) { foreach($all_perms as $perm => $desc) { @@ -213,7 +220,7 @@ class Connedit extends \Zotlabs\Web\Controller { $record = $z[0]['xlink_id']; } if($record) { - \Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record)); + Master::Summon(array('Ratenotif','rating',$record)); } } @@ -228,7 +235,7 @@ class Connedit extends \Zotlabs\Web\Controller { // request. The workaround is to approve the connection, then go back and // adjust permissions as desired. - $p = \Zotlabs\Access\Permissions::connect_perms(local_channel()); + $p = Permissions::connect_perms(local_channel()); $my_perms = $p['perms']; if($my_perms) { foreach($my_perms as $k => $v) { @@ -258,12 +265,12 @@ class Connedit extends \Zotlabs\Web\Controller { else notice( t('Failed to update connection record.') . EOL); - if(! intval(\App::$poi['abook_self'])) { + if(! intval(App::$poi['abook_self'])) { if($new_friend) { - \Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] ); + Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] ); } - \Zotlabs\Daemon\Master::Summon( [ + Master::Summon( [ 'Notifier', (($new_friend) ? 'permission_create' : 'permission_update'), $contact_id @@ -276,7 +283,7 @@ class Connedit extends \Zotlabs\Web\Controller { require_once('include/group.php'); $g = group_rec_byhash(local_channel(),$default_group); if($g) - group_add_member(local_channel(),'',\App::$poi['abook_xchan'],$g['id']); + group_add_member(local_channel(),'',App::$poi['abook_xchan'],$g['id']); } // Check if settings permit ("post new friend activity" is allowed, and @@ -300,19 +307,19 @@ class Connedit extends \Zotlabs\Web\Controller { $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); $obj = array( 'type' => ACTIVITY_OBJ_PERSON, - 'title' => \App::$poi['xchan_name'], - 'id' => \App::$poi['xchan_hash'], + 'title' => App::$poi['xchan_name'], + 'id' => App::$poi['xchan_hash'], 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => \App::$poi['xchan_url']), - array('rel' => 'photo', 'type' => \App::$poi['xchan_photo_mimetype'], 'href' => \App::$poi['xchan_photo_l']) + array('rel' => 'alternate', 'type' => 'text/html', 'href' => App::$poi['xchan_url']), + array('rel' => 'photo', 'type' => App::$poi['xchan_photo_mimetype'], 'href' => App::$poi['xchan_photo_l']) ), ); $xarr['obj'] = json_encode($obj); $xarr['obj_type'] = ACTIVITY_OBJ_PERSON; - $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . \App::$poi['xchan_url'] . ']' . \App::$poi['xchan_name'] . '[/zrl]'; + $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; - $xarr['body'] .= "\n\n\n" . '[zrl=' . \App::$poi['xchan_url'] . '][zmg=80x80]' . \App::$poi['xchan_photo_m'] . '[/zmg][/zrl]'; + $xarr['body'] .= "\n\n\n" . '[zrl=' . App::$poi['xchan_url'] . '][zmg=80x80]' . App::$poi['xchan_photo_m'] . '[/zmg][/zrl]'; post_activity_item($xarr); @@ -320,7 +327,7 @@ class Connedit extends \Zotlabs\Web\Controller { // pull in a bit of content if there is any to pull in - \Zotlabs\Daemon\Master::Summon(array('Onepoll',$contact_id)); + Master::Summon(array('Onepoll',$contact_id)); } @@ -333,11 +340,11 @@ class Connedit extends \Zotlabs\Web\Controller { intval($contact_id) ); if($r) { - \App::$poi = $r[0]; + App::$poi = $r[0]; } if($new_friend) { - $arr = array('channel_id' => local_channel(), 'abook' => \App::$poi); + $arr = array('channel_id' => local_channel(), 'abook' => App::$poi); call_hooks('accept_follow', $arr); } @@ -357,23 +364,23 @@ class Connedit extends \Zotlabs\Web\Controller { function connedit_clone(&$a) { - if(! \App::$poi) + if(! App::$poi) return; - $channel = \App::get_channel(); + $channel = App::get_channel(); $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", intval(local_channel()), - intval(\App::$poi['abook_id']) + intval(App::$poi['abook_id']) ); if($r) { - \App::$poi = array_shift($r); + App::$poi = array_shift($r); } - $clone = \App::$poi; + $clone = App::$poi; unset($clone['abook_id']); unset($clone['abook_account']); @@ -402,11 +409,11 @@ class Connedit extends \Zotlabs\Web\Controller { } $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); - $channel = \App::get_channel(); + $channel = App::get_channel(); $yes_no = array(t('No'),t('Yes')); - $connect_perms = \Zotlabs\Access\Permissions::connect_perms(local_channel()); + $connect_perms = Permissions::connect_perms(local_channel()); $o .= "<script>function connectDefaultShare() { \$('.abook-edit-me').each(function() { @@ -427,7 +434,7 @@ class Connedit extends \Zotlabs\Web\Controller { return; $cmd = argv(2); - + $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", intval($contact_id), @@ -441,7 +448,7 @@ class Connedit extends \Zotlabs\Web\Controller { if($cmd === 'update') { // pull feed and consume it, which should subscribe to the hub. - \Zotlabs\Daemon\Master::Summon(array('Poller',$contact_id)); + Master::Summon(array('Poller',$contact_id)); goaway(z_root() . '/connedit/' . $contact_id); } @@ -451,7 +458,7 @@ class Connedit extends \Zotlabs\Web\Controller { $recurse = 0; $x = z_fetch_url(zid($url),false,$recurse,['session' => true]); if($x['success']) { - $h = new \Zotlabs\Web\HTTPHeaders($x['header']); + $h = new HTTPHeaders($x['header']); $fields = $h->fetch(); if($fields) { foreach($fields as $y) { @@ -482,17 +489,17 @@ class Connedit extends \Zotlabs\Web\Controller { if($cmd === 'refresh') { if($orig_record[0]['xchan_network'] === 'zot') { - if(! zot_refresh($orig_record[0],\App::get_channel())) + if(! zot_refresh($orig_record[0],App::get_channel())) notice( t('Refresh failed - channel is currently unavailable.') ); } elseif($orig_record[0]['xchan_network'] === 'zot6') { - if(! Libzot::refresh($orig_record[0],\App::get_channel())) + if(! Libzot::refresh($orig_record[0],App::get_channel())) notice( t('Refresh failed - channel is currently unavailable.') ); } else { // if you are on a different network we'll force a refresh of the connection basic info - \Zotlabs\Daemon\Master::Summon(array('Notifier','permission_update',$contact_id)); + Master::Summon(array('Notifier','permission_update',$contact_id)); } goaway(z_root() . '/connedit/' . $contact_id); } @@ -550,15 +557,10 @@ class Connedit extends \Zotlabs\Web\Controller { if($cmd === 'drop') { - - // @FIXME - // We need to send either a purge or a refresh packet to the other side (the channel being unfriended). - // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier - // runs in the background there could be a race condition preventing this packet from being sent in all - // cases. - // PLACEHOLDER - contact_remove(local_channel(), $orig_record[0]['abook_id']); + + Master::Summon( [ 'Notifier', 'purge', local_channel(), $orig_record[0]['xchan_hash'] ] ); + Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array(array( 'abook_xchan' => $orig_record[0]['abook_xchan'], @@ -574,13 +576,13 @@ class Connedit extends \Zotlabs\Web\Controller { } } - if(\App::$poi) { + if(App::$poi) { $abook_prev = 0; $abook_next = 0; - $contact_id = \App::$poi['abook_id']; - $contact = \App::$poi; + $contact_id = App::$poi['abook_id']; + $contact = App::$poi; $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name", intval(local_channel()) @@ -788,9 +790,9 @@ class Connedit extends \Zotlabs\Web\Controller { $perms = array(); - $channel = \App::get_channel(); + $channel = App::get_channel(); - $global_perms = \Zotlabs\Access\Permissions::Perms(); + $global_perms = Permissions::Perms(); $existing = get_all_perms(local_channel(),$contact['abook_xchan'],false); @@ -822,7 +824,7 @@ class Connedit extends \Zotlabs\Web\Controller { $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); //fixme - $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k); + $checkinherited = PermissionLimits::Get(local_channel(),$k); // For auto permissions (when $self is true) we don't want to look at existing // permissions because they are enabled for the channel owner @@ -835,7 +837,7 @@ class Connedit extends \Zotlabs\Web\Controller { $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); } - $pcat = new \Zotlabs\Lib\Permcat(local_channel()); + $pcat = new Permcat(local_channel()); $pcatlist = $pcat->listing(); $permcats = []; if($pcatlist) { diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index f45f37001..3d61d7018 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -47,7 +47,6 @@ class Display extends \Zotlabs\Web\Controller { } $observer_is_owner = false; - $updateable = false; if(local_channel() && (! $update)) { @@ -274,9 +273,6 @@ class Display extends \Zotlabs\Web\Controller { intval(local_channel()), dbesc($target_item['parent_mid']) ); - if($r) { - $updateable = true; - } } if(! $r) { @@ -318,9 +314,6 @@ class Display extends \Zotlabs\Web\Controller { intval(local_channel()), dbesc($target_item['parent_mid']) ); - if($r) { - $updateable = true; - } } if($r === null) { @@ -432,13 +425,6 @@ class Display extends \Zotlabs\Web\Controller { killme(); } - - if($updateable) { - $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", - intval(local_channel()), - intval($r[0]['item_id']) - ); - } $o .= '<div id="content-complete"></div>'; diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index 5b331f4c1..e2678c07f 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -199,8 +199,6 @@ class Hq extends \Zotlabs\Web\Controller { ]); } - $updateable = false; - if($load && $target_item) { $r = null; @@ -213,10 +211,6 @@ class Hq extends \Zotlabs\Web\Controller { dbesc($target_item['parent_mid']) ); - if($r) { - $updateable = true; - } - if(!$r) { $sys_item = true; @@ -243,10 +237,6 @@ class Hq extends \Zotlabs\Web\Controller { dbesc($target_item['parent_mid']) ); - if($r) { - $updateable = true; - } - if(!$r) { $sys_item = true; @@ -283,13 +273,6 @@ class Hq extends \Zotlabs\Web\Controller { $o .= conversation($items, 'hq', $update, 'client'); - if($updateable) { - $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ", - intval(local_channel()), - intval($r[0]['item_id']) - ); - } - $o .= '<div id="content-complete"></div>'; return $o; diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index d8c837522..922a2ef06 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -157,6 +157,106 @@ class Item extends Controller { } + if(ActivityStreams::is_as_request()) { + + $item_id = argv(1); + if(! $item_id) + http_status_exit(404, 'Not found'); + + $portable_id = EMPTY_STR; + + $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 "; + + $i = null; + + // do we have the item (at all)? + // add preferential bias to item owners (item_wall = 1) + + $r = q("select * from item where mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1", + dbesc(z_root() . '/item/' . $item_id), + dbesc($item_id) + ); + + if (! $r) { + http_status_exit(404,'Not found'); + } + + // process an authenticated fetch + + $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); + + $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ", + dbesc($r[0]['parent_mid']), + dbesc($portable_id) + ); + } + elseif (Config::get('system','require_authenticated_fetch',false)) { + http_status_exit(403,'Permission denied'); + } + + // 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) + + $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']) + ); + } + + if(! $i) { + http_status_exit(403,'Forbidden'); + } + + // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it. + + xchan_query($r,true); + $items = fetch_post_tags($r,false); + + $chan = channelx_by_n($items[0]['uid']); + + if(! $chan) + http_status_exit(404, 'Not found'); + + if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) + http_status_exit(403, 'Forbidden'); + + $i = Activity::encode_item($items[0],true); + + if(! $i) + http_status_exit(404, 'Not found'); + + $x = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + z_root() . ZOT_APSCHEMA_REV + ]], $i); + + $headers = []; + $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; + $x['signature'] = LDSignatures::sign($x,$chan); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $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['(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(); + + } + + if(argc() > 1 && argv(1) !== 'drop') { $x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' ", dbesc(z_root() . '/item/' . argv(1)), diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index edd4cfac8..8ffa7f66c 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -441,15 +441,15 @@ class Like extends \Zotlabs\Web\Controller { if($extended_like) { - $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]'; - $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $ulink = '[zrl=' . $ch[0]['xchan_url'] . '][bdi]' . $ch[0]['xchan_name'] . '[/bdi][/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]'; $private = (($public) ? 0 : 1); } else { $arr['parent'] = $item['id']; $arr['thr_parent'] = $item['mid']; - $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; - $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $ulink = '[zrl=' . $item_author['xchan_url'] . '][bdi]' . $item_author['xchan_name'] . '[/bdi][/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . '][bdi]' . $observer['xchan_name'] . '[/bdi][/zrl]'; $plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]'; $allow_cid = $item['allow_cid']; $allow_gid = $item['allow_gid']; diff --git a/Zotlabs/Module/Locs.php b/Zotlabs/Module/Locs.php index 47ece8041..4c935a6a2 100644 --- a/Zotlabs/Module/Locs.php +++ b/Zotlabs/Module/Locs.php @@ -1,22 +1,24 @@ <?php namespace Zotlabs\Module; /** @file */ +use App; +use Zotlabs\Web\Controller; +use Zotlabs\Daemon\Master; - -class Locs extends \Zotlabs\Web\Controller { +class Locs extends Controller { function post() { if(! local_channel()) return; - $channel = \App::get_channel(); + $channel = App::get_channel(); if($_REQUEST['primary']) { $hubloc_id = intval($_REQUEST['primary']); if($hubloc_id) { - $r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", + $r = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", intval($hubloc_id), dbesc($channel['channel_hash']) ); @@ -26,15 +28,16 @@ class Locs extends \Zotlabs\Web\Controller { return; } - $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' ", - dbesc($channel['channel_hash']) + q("UPDATE hubloc SET hubloc_primary = 0 WHERE hubloc_primary = 1 AND (hubloc_hash = '%s' OR hubloc_hash = '%s')", + dbesc($channel['channel_hash']), + dbesc($channel['channel_portable_id']) ); - $r = q("update hubloc set hubloc_primary = 1 where hubloc_id = %d and hubloc_hash = '%s'", + q("UPDATE hubloc SET hubloc_primary = 1 WHERE hubloc_id = %d AND hubloc_hash = '%s'", intval($hubloc_id), dbesc($channel['channel_hash']) ); - - \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id'])); + + Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); return; } } @@ -68,11 +71,12 @@ class Locs extends \Zotlabs\Web\Controller { } } - $r = q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d and hubloc_hash = '%s'", - intval($hubloc_id), - dbesc($channel['channel_hash']) + q("UPDATE hubloc SET hubloc_deleted = 1 WHERE hubloc_id_url = '%s' AND (hubloc_hash = '%s' OR hubloc_hash = '%s')", + dbesc($r[0]['hubloc_id_url']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_portable_id']) ); - \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id'])); + Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); return; } } @@ -88,10 +92,10 @@ class Locs extends \Zotlabs\Web\Controller { return; } - $channel = \App::get_channel(); + $channel = App::get_channel(); if($_REQUEST['sync']) { - \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id'])); + Master::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); info( t('Syncing locations') . EOL); goaway(z_root() . '/locs'); } diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php index 6ac656a04..b4372e26d 100644 --- a/Zotlabs/Module/Magic.php +++ b/Zotlabs/Module/Magic.php @@ -1,214 +1,133 @@ <?php namespace Zotlabs\Module; +use App; +use Zotlabs\Web\Controller; use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\SConfig; -@require_once('include/zot.php'); - - -class Magic extends \Zotlabs\Web\Controller { +class Magic extends Controller { function init() { + + $ret = [ + 'success' => false, + 'url' => '', + 'message' => '' + ]; - $ret = array('success' => false, 'url' => '', 'message' => ''); logger('mod_magic: invoked', LOGGER_DEBUG); - - logger('mod_magic: args: ' . print_r($_REQUEST,true),LOGGER_DATA); - - $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : ''); - $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : ''); - $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : ''); - $test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0); - $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0); - $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0); - $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : ''); - - if($bdest) + + logger('args: ' . print_r($_REQUEST,true),LOGGER_DATA); + + $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : ''); + $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : ''); + $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : ''); + $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0); + $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0); + $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : ''); + + // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing + + if ($bdest) { $dest = hex2bin($bdest); + } $parsed = parse_url($dest); - if(! $parsed) { - if($test) { - $ret['message'] .= 'could not parse ' . $dest . EOL; - return($ret); - } + + if (! $parsed) { goaway($dest); } - + $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); - - $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", - dbesc($basepath) - ); - - if(! $x) { - - /* - * We have no records for, or prior communications with this hub. - * If an address was supplied, let's finger them to create a hub record. - * Otherwise we'll use the special address '[system]' which will return - * either a system channel or the first available normal channel. We don't - * really care about what channel is returned - we need the hub information - * from that response so that we can create signed auth packets destined - * for that hub. - * - */ - - $j = \Zotlabs\Zot\Finger::run((($addr) ? $addr : '[system]@' . $parsed['host']),null); - if($j['success']) { - import_xchan($j); - - // Now try again - - $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", - dbesc($basepath) - ); - } - } - - if(! $x) { - if($rev) - goaway($dest); - else { - logger('mod_magic: no channels found for requested hub.' . print_r($_REQUEST,true)); - if($test) { - $ret['message'] .= 'This site has no previous connections with ' . $basepath . EOL; - return $ret; - } - notice( t('Hub not found.') . EOL); - return; - } - } - + $owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa'); + // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. // By default, we'll proceed without asking. - - $arr = array( - 'channel_id' => local_channel(), - 'xchan' => $x[0], + + $arr = [ + 'channel_id' => local_channel(), 'destination' => $dest, - 'proceed' => true - ); - + 'proceed' => true + ]; + call_hooks('magic_auth',$arr); $dest = $arr['destination']; - if(! $arr['proceed']) { - if($test) { - $ret['message'] .= 'cancelled by plugin.' . EOL; - return $ret; - } + if (! $arr['proceed']) { goaway($dest); } - - if((get_observer_hash()) && ($x[0]['hubloc_url'] === z_root())) { + + if((get_observer_hash()) && (stripos($dest,z_root()) === 0)) { + // We are already authenticated on this site and a registered observer. - // Just redirect. - if($test) { - $ret['success'] = true; - $ret['message'] .= 'Local site - you are already authenticated.' . EOL; - return $ret; - } - - $delegation_success = false; - if($delegate) { + // First check if this is a delegate request on the local system and process accordingly. + // Otherwise redirect. + + if ($delegate) { + $r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1", dbesc($delegate) ); - - if($r && intval($r[0]['channel_id'])) { - $allowed = perm_is_allowed($r[0]['channel_id'],get_observer_hash(),'delegate'); - if($allowed) { + + if ($r) { + $c = array_shift($r); + if (perm_is_allowed($c['channel_id'],get_observer_hash(),'delegate')) { $tmp = $_SESSION; - $_SESSION['delegate_push'] = $tmp; - $_SESSION['delegate_channel'] = $r[0]['channel_id']; - $_SESSION['delegate'] = get_observer_hash(); - $_SESSION['account_id'] = intval($r[0]['channel_account_id']); - change_channel($r[0]['channel_id']); - - $delegation_success = true; + $_SESSION['delegate_push'] = $tmp; + $_SESSION['delegate_channel'] = $c['channel_id']; + $_SESSION['delegate'] = get_observer_hash(); + $_SESSION['account_id'] = intval($c['channel_account_id']); + + change_channel($c['channel_id']); } } } - - - - // FIXME: check and honour local delegation - - + goaway($dest); } - - if(local_channel()) { - $channel = \App::get_channel(); - + + if (local_channel()) { + $channel = App::get_channel(); + // OpenWebAuth - if($owa) { + if ($owa) { $dest = strip_zids($dest); $dest = strip_query_param($dest,'f'); + // We now post to the OWA endpoint. This improves security by providing a signed digest + $data = json_encode([ 'OpenWebAuth' => random_string() ]); $headers = []; $headers['Accept'] = 'application/x-zot+json' ; + $headers['Content-Type'] = 'application/x-zot+json' ; $headers['X-Open-Web-Auth'] = random_string(); - $headers['Host'] = $parsed['host']; $headers['Digest'] = HTTPSig::generate_digest_header($data); + $headers['Host'] = $parsed['host']; + $headers['(request-target)'] = 'post ' . '/owa'; - $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], 'acct:' . channel_reddress($channel),true,'sha512'); - $x = z_post_url($basepath . '/owa',$data,$redirects,[ 'headers' => $headers ]); - - if($x['success']) { + $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); + $x = z_post_url($owapath,$data,$redirects,[ 'headers' => $headers ]); + logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA); + if ($x['success']) { $j = json_decode($x['body'],true); - if($j['success']) { + if ($j['success'] && $j['encrypted_token']) { + // decrypt the token using our private key $token = ''; - if($j['encrypted_token']) { - openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']); - } - else { - $token = $j['token']; - } - - $strp = strpbrk($dest,'?&'); - $args = (($strp) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : ''); + openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']); + $x = strpbrk($dest,'?&'); + // redirect using the encrypted token which will be exchanged for an authenticated session + $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : ''); goaway($dest . $args); } } - goaway($dest); - } - - - $token = random_string(); - - \Zotlabs\Lib\Verify::create('auth',$channel['channel_id'],$token,$x[0]['hubloc_url']); - - $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode(channel_reddress($channel)) - . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION; - - if($delegate) - $target_url .= '&delegate=' . urlencode($delegate); - - logger('mod_magic: redirecting to: ' . $target_url, LOGGER_DEBUG); - - if($test) { - $ret['success'] = true; - $ret['url'] = $target_url; - $ret['message'] = 'token ' . $token . ' created for channel ' . $channel['channel_id'] . ' for url ' . $x[0]['hubloc_url'] . EOL; - return $ret; } - - goaway($target_url); - } - - if($test) { - $ret['message'] = 'Not authenticated or invalid arguments to mod_magic' . EOL; - return $ret; - } - + goaway($dest); - } - + } diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index fe1aa4386..bbacbb21e 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -133,8 +133,6 @@ class Network extends \Zotlabs\Web\Controller { $pf = ((x($_GET,'pf')) ? $_GET['pf'] : ''); $unseen = ((x($_GET,'unseen')) ? $_GET['unseen'] : ''); - $deftag = ''; - if (Apps::system_app_installed(local_channel(),'Affinity Tool')) { $affinity_locked = intval(get_pconfig(local_channel(),'affinity','lock',1)); if ($affinity_locked) { @@ -160,10 +158,7 @@ class Network extends \Zotlabs\Web\Controller { goaway(z_root() . '/network'); // NOTREACHED } - if($pf) - $deftag = '!{' . (($cid_r[0]['xchan_addr']) ? $cid_r[0]['xchan_addr'] : $cid_r[0]['xchan_url']) . '}'; - else - $def_acl = [ 'allow_cid' => '<' . $cid_r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + $def_acl = [ 'allow_cid' => '<' . $cid_r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; } if(! $update) { @@ -177,6 +172,17 @@ class Network extends \Zotlabs\Web\Controller { nav_set_selected('Network'); + $bang = '!'; + + if($cid_r) { + $forums = get_forum_channels($channel['channel_id']); + if($forums) { + $forum_xchans = ids_to_array($forums, 'xchan_hash'); + if(in_array($cid_r[0]['abook_xchan'], $forum_xchans)) + $bang = $cid_r[0]['abook_xchan']; + } + } + $channel_acl = array( 'allow_cid' => $channel['channel_allow_cid'], 'allow_gid' => $channel['channel_allow_gid'], @@ -184,7 +190,7 @@ class Network extends \Zotlabs\Web\Controller { 'deny_gid' => $channel['channel_deny_gid'] ); - $private_editing = ((($group || $cid) && (! intval($_GET['pf']))) ? true : false); + $private_editing = (($group || $cid) ? true : false); $x = array( 'is_owner' => true, @@ -194,7 +200,7 @@ class Network extends \Zotlabs\Web\Controller { 'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), 'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'permissions' => (($private_editing) ? $def_acl : $channel_acl), - 'bang' => (($private_editing) ? '!' : ''), + 'bang' => (($private_editing) ? $bang : ''), 'visitor' => true, 'profile_uid' => local_channel(), 'editor_autocomplete' => true, @@ -203,9 +209,6 @@ class Network extends \Zotlabs\Web\Controller { 'jotnets' => true, 'reset' => t('Reset form') ); - if($deftag) - $x['pretext'] = $deftag; - $status_editor = status_editor($a,$x,false,'Network'); $o .= $status_editor; @@ -490,7 +493,6 @@ class Network extends \Zotlabs\Web\Controller { $page_mode = 'client'; $parents_str = ''; - $update_unseen = ''; $simple_update = (($update) ? " and item_unseen = 1 " : ''); @@ -529,9 +531,6 @@ class Network extends \Zotlabs\Web\Controller { ); $parents_str = ids_to_querystr($items,'item_id'); - if($parents_str) { - $update_unseen = " AND id IN ( " . dbesc($parents_str) . " )"; - } require_once('include/items.php'); @@ -595,35 +594,6 @@ class Network extends \Zotlabs\Web\Controller { $items = array(); } - if($page_mode === 'list') { - - /** - * in "list mode", only mark the parent item and any like activities as "seen". - * We won't distinguish between comment likes and post likes. The important thing - * is that the number of unseen comments will be accurate. The SQL to separate the - * comment likes could also get somewhat hairy. - */ - - if($parents_str) { - $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; - $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; - } - } - else { - if($parents_str) { - $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; - } - } - } - - if($update_unseen) { - $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; - call_hooks('update_unseen',$x); - if($x['update'] === 'unset' || intval($x['update'])) { - $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ", - intval(local_channel()) - ); - } } $mode = (($nouveau) ? 'network-new' : 'network'); diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index 3977ac8dd..75304161b 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -125,7 +125,7 @@ class Oep extends \Zotlabs\Web\Controller { "' profile='".$p[0]['author']['xchan_url'] . "' avatar='".$p[0]['author']['xchan_photo_s']. "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') . + "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') . "' posted='".$p[0]['created']. "' message_id='".$p[0]['mid']."']"; if($p[0]['title']) @@ -213,7 +213,7 @@ class Oep extends \Zotlabs\Web\Controller { "' profile='".$p[0]['author']['xchan_url'] . "' avatar='".$p[0]['author']['xchan_photo_s']. "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') . + "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') . "' posted='".$p[0]['created']. "' message_id='".$p[0]['mid']."']"; if($p[0]['title']) @@ -299,7 +299,7 @@ class Oep extends \Zotlabs\Web\Controller { "' profile='".$p[0]['author']['xchan_url'] . "' avatar='".$p[0]['author']['xchan_photo_s']. "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') . + "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') . "' posted='".$p[0]['created']. "' message_id='".$p[0]['mid']."']"; if($p[0]['title']) @@ -374,7 +374,7 @@ class Oep extends \Zotlabs\Web\Controller { "' profile='".$p[0]['author']['xchan_url'] . "' avatar='".$p[0]['author']['xchan_photo_s']. "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot') ? 'true' : 'false') . + "' auth='".((in_array($p[0]['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') . "' posted='".$p[0]['created']. "' message_id='".$p[0]['mid']."']"; if($p[0]['title']) diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php index 4c6fd6216..561e35754 100644 --- a/Zotlabs/Module/Owa.php +++ b/Zotlabs/Module/Owa.php @@ -3,10 +3,12 @@ namespace Zotlabs\Module; use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Verify; +use Zotlabs\Web\Controller; /** * OpenWebAuth verifier and token generator - * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home + * See spec/OpenWebAuth/Home.md * Requests to this endpoint should be signed using HTTP Signatures * using the 'Authorization: Signature' authentication method * If the signature verifies a token is returned. @@ -14,74 +16,51 @@ use Zotlabs\Web\HTTPSig; * This token may be exchanged for an authenticated cookie. */ -class Owa extends \Zotlabs\Web\Controller { +class Owa extends Controller { function init() { $ret = [ 'success' => false ]; - foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { - if($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } - - $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); - if($sigblock) { - $keyId = $sigblock['keyId']; - - if($keyId) { - - // Hubzilla connections can have both zot6 and zot hublocs - // The connections will usually be zot6 so match those first - - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and hubloc_network = 'zot6' ", - dbesc(str_replace('acct:','',$keyId)), - dbesc($keyId) - ); + if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER']; + } - // If nothing was found, try searching on any network - - if (! $r) { + if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') { + $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); + if ($sigblock) { + $keyId = $sigblock['keyId']; + if ($keyId) { + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash + where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ", + dbesc(str_replace('acct:','',$keyId)), + dbesc($keyId) + ); + if (! $r) { + $found = discover_by_webbie(str_replace('acct:','',$keyId)); + if ($found) { $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where ( hubloc_addr = '%s' or hubloc_id_url = '%s' )", + where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ", dbesc(str_replace('acct:','',$keyId)), dbesc($keyId) ); } - - // If nothing was found on any network, use network discovery and create a new record - - if (! $r) { - $found = discover_by_webbie(str_replace('acct:','',$keyId)); - if($found) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ", - dbesc(str_replace('acct:','',$keyId)), - dbesc($keyId) - ); - } - } - - if ($r) { - foreach($r as $hubloc) { - $verified = HTTPSig::verify(file_get_contents('php://input'),$hubloc['xchan_pubkey']); - if($verified && $verified['header_signed'] && $verified['header_valid']) { - logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); - logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); - $ret['success'] = true; - $token = random_string(32); - \Zotlabs\Lib\Verify::create('owt',0,$token,$hubloc['hubloc_network'] . ',' . $hubloc['hubloc_addr']); - $result = ''; - openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); - $ret['encrypted_token'] = base64url_encode($result); - break; - } - else { - logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); - } + } + if ($r) { + foreach ($r as $hubloc) { + $verified = HTTPSig::verify(file_get_contents('php://input')); + if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) { + logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); + logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); + $ret['success'] = true; + $token = random_string(32); + Verify::create('owt',0,$token,$hubloc['hubloc_addr']); + $result = ''; + openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); + $ret['encrypted_token'] = base64url_encode($result); + break; + } else { + logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); } } } diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 7deceabab..9ac0e725e 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -607,10 +607,10 @@ class Profiles extends \Zotlabs\Web\Controller { $channel = \App::get_channel(); if($namechanged && $is_default) { - $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'", + $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_url = '%s'", dbesc($name), dbesc(datetime_convert()), - dbesc($channel['xchan_hash']) + dbesc(z_root() . '/channel/' . $channel['channel_address']) ); $r = q("UPDATE channel SET channel_name = '%s' WHERE channel_hash = '%s'", dbesc($name), diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 76a3e0d9e..55c96b23d 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -264,7 +264,6 @@ class Pubstream extends \Zotlabs\Web\Controller { // Then fetch all the children of the parents that are on this page $parents_str = ''; - $update_unseen = ''; if($r) { diff --git a/Zotlabs/Module/Regdir.php b/Zotlabs/Module/Regdir.php index f4d16c562..e49f89231 100644 --- a/Zotlabs/Module/Regdir.php +++ b/Zotlabs/Module/Regdir.php @@ -1,6 +1,9 @@ <?php namespace Zotlabs\Module; +use Zotlabs\Lib\Zotfinger; +use Zotlabs\Web\Controller; + /** * With args, register a directory server for this realm. * With no args, return a JSON array of directory servers for this realm. @@ -14,7 +17,7 @@ namespace Zotlabs\Module; * @param App &$a */ -class Regdir extends \Zotlabs\Web\Controller { +class Regdir extends Controller { function init() { @@ -25,7 +28,7 @@ class Regdir extends \Zotlabs\Web\Controller { $valid = 0; // we probably don't need the realm as we will find out in the probe. - // What we may want to die is throw an error if you're trying to register in a different realm + // What we may want to do is throw an error if you're trying to register in a different realm // so this configuration issue can be discovered. $realm = $_REQUEST['realm']; @@ -59,34 +62,28 @@ class Regdir extends \Zotlabs\Web\Controller { json_return_and_die($result); } - $j = \Zotlabs\Zot\Finger::run('[system]@' . $m['host']); - if($j['success'] && $j['guid']) { - $x = import_xchan($j); - if($x['success']) { - $result['success'] = true; - } + $j = Zotfinger::exec($url); + if($j) { + $result['success'] = true; } - - if(! $result['success']) + else { $valid = 0; - + } + q("update site set site_valid = %d where site_url = '%s'", intval($valid), strtolower($url) ); - + json_return_and_die($result); - } else { - - // We can put this in the sql without the condition after 31 august 2015 assuming - // most directory servers will have updated by then - // This just makes sure it happens if I forget + + } + else { - $sql_extra = ((datetime_convert() > datetime_convert('UTC','UTC','2015-08-31')) ? ' and site_valid = 1 ' : '' ); if ($dirmode == DIRECTORY_MODE_STANDALONE) { $r = array(array('site_url' => z_root())); } else { - $r = q("select site_url from site where site_flags in ( 1, 2 ) and site_realm = '%s' and site_type = %d $sql_extra ", + $r = q("select site_url from site where site_flags in ( 1, 2 ) and site_realm = '%s' and site_type = %d and site_valid = 1 ", dbesc(get_directory_realm()), intval(SITE_TYPE_ZOT) ); diff --git a/Zotlabs/Module/Removeaccount.php b/Zotlabs/Module/Removeaccount.php index 9d2bbd0de..cd18b79c0 100644 --- a/Zotlabs/Module/Removeaccount.php +++ b/Zotlabs/Module/Removeaccount.php @@ -37,7 +37,7 @@ class Removeaccount extends \Zotlabs\Web\Controller { } } - $global_remove = intval($_POST['global']); + $global_remove = 0; //intval($_POST['global']); account_remove($account_id, 1 - $global_remove); } @@ -57,7 +57,7 @@ class Removeaccount extends \Zotlabs\Web\Controller { '$title' => t('Remove This Account'), '$desc' => array(t('WARNING: '), t('This account and all its channels will be completely removed from the network. '), t('This action is permanent and can not be undone!')), '$passwd' => t('Please enter your password for verification:'), - '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')), + // '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')), '$submit' => t('Remove Account') )); diff --git a/Zotlabs/Module/Removeme.php b/Zotlabs/Module/Removeme.php index 451e280c3..876d61ca6 100644 --- a/Zotlabs/Module/Removeme.php +++ b/Zotlabs/Module/Removeme.php @@ -37,7 +37,7 @@ class Removeme extends \Zotlabs\Web\Controller { } } - $global_remove = intval($_POST['global']); + $global_remove = 0; //intval($_POST['global']); channel_remove(local_channel(),1 - $global_remove,true); @@ -60,7 +60,7 @@ class Removeme extends \Zotlabs\Web\Controller { '$title' => t('Remove This Channel'), '$desc' => [ t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!') ], '$passwd' => t('Please enter your password for verification:'), - '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ], + // '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ], '$submit' => t('Remove Channel') )); diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php index 8c1e5cdab..ab9ad059e 100644 --- a/Zotlabs/Module/Rmagic.php +++ b/Zotlabs/Module/Rmagic.php @@ -1,6 +1,7 @@ <?php namespace Zotlabs\Module; +use Zotlabs\Lib\Libzot; class Rmagic extends \Zotlabs\Web\Controller { @@ -11,23 +12,24 @@ class Rmagic extends \Zotlabs\Web\Controller { $me = get_my_address(); if($me) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'", dbesc($me) ); if(! $r) { $w = discover_by_webbie($me); if($w) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'", dbesc($me) ); } } - if($r) { - if($r[0]['hubloc_url'] === z_root()) + if($r) { + $r = Libzot::zot_record_preferred($r); + if($r['hubloc_url'] === z_root()) goaway(z_root() . '/login'); $dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string)); - goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest); + goaway($r['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest); } } } @@ -55,13 +57,13 @@ class Rmagic extends \Zotlabs\Web\Controller { $r = null; if($address) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'", dbesc($address) ); if(! $r) { $w = discover_by_webbie($address); if($w) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s'", dbesc($address) ); } @@ -69,7 +71,8 @@ class Rmagic extends \Zotlabs\Web\Controller { } if($r) { - $url = $r[0]['hubloc_url']; + $r = Libzot::zot_record_preferred($r); + $url = $r['hubloc_url']; } else { $url = 'https://' . substr($address,strpos($address,'@')+1); diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index ab9b72490..2eed1efc9 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -274,10 +274,11 @@ class Channel { } if($name_change) { - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", + // change name on all associated xchans by matching the url + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'", dbesc($username), dbesc(datetime_convert()), - dbesc($channel['channel_hash']) + dbesc(z_root() . '/channel/' . $channel['channel_address']) ); $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", dbesc($username), diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php index 6d5acf276..e3439e7dd 100644 --- a/Zotlabs/Module/Sse_bs.php +++ b/Zotlabs/Module/Sse_bs.php @@ -36,12 +36,15 @@ class Sse_bs extends Controller { self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify', -1); self::$evdays = intval(get_pconfig(self::$uid, 'system', 'evdays')); - self::$limit = 100; + self::$limit = 50; self::$offset = 0; self::$xchans = ''; - if(!empty($_GET['nquery']) && $_GET['nquery'] !== '%') { - $nquery = $_GET['nquery']; + if($_REQUEST['sse_rmids']) + self::mark_read($_REQUEST['sse_rmids']); + + if(!empty($_REQUEST['nquery']) && $_REQUEST['nquery'] !== '%') { + $nquery = $_REQUEST['nquery']; $x = q("SELECT xchan_hash FROM xchan WHERE xchan_name LIKE '%s' OR xchan_addr LIKE '%s'", dbesc($nquery . '%'), @@ -108,6 +111,31 @@ class Sse_bs extends Controller { json_return_and_die($result); } + function mark_read($arr) { + + if(! self::$uid) + return; + + $mids = []; + $str = ''; + + foreach($arr as $a) { + $mids[] = '\'' . dbesc(@base64url_decode(substr($a,4))) . '\''; + } + + $str = implode($mids, ','); + + $x = [ 'channel_id' => self::$uid, 'update' => 'unset' ]; + call_hooks('update_unseen',$x); + + if($x['update'] === 'unset' || intval($x['update'])) { + q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND mid in (". $str . ") AND item_unseen = 1", + intval(self::$uid) + ); + } + + } + function bs_network($notifications) { $result['network']['notifications'] = []; @@ -163,9 +191,10 @@ class Sse_bs extends Controller { $r = q("SELECT count(id) as total FROM item WHERE uid = %d and item_unseen = 1 AND item_wall = 0 AND item_private IN (0, 1) + AND obj_type NOT IN ('Document', 'Video', 'Audio', 'Image') + AND author_xchan != '%s' $item_normal - $sql_extra - AND author_xchan != '%s'", + $sql_extra", intval(self::$uid), dbesc(self::$ob_hash) ); diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php index 909823ec4..ac792dd69 100644 --- a/Zotlabs/Web/WebServer.php +++ b/Zotlabs/Web/WebServer.php @@ -62,7 +62,8 @@ class WebServer { $_SESSION['my_address'] = $_GET['zid']; $_SESSION['authenticated'] = 0; } - zid_init(); + if(! $_SESSION['authenticated']) + zid_init(); } } |