diff --git a/CHANGELOG b/CHANGELOG index 0a57efa9d..eeba6c6d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,33 @@ +Hubzilla 4.0.1 (2019-03-21) + - Fix permissions not getting decrypted on follow + - Add option to add a poster to the video bbcode + - Fix SQL performance issue with queries including thr_parent + - Fix share encoding issue between hz and zap + - Fix edge case in unsupported advisory privacy + - Messagefilter enhancements + - Fix XSS issues + - Clone systems apps to the extent possible + - Auto-configure imagick thumbnail binary during setup if possible + - Fix array not unserialized in util/service_class + - Add phpmd and phpcs to composer require-dev for code linting + - Fix issue with email encoding + - Fix signature issue for zot6 content imported from zotfeeds to hubzilla + - Find unregistered z6 clones on hubzilla sites + - Add zot6 to clonable networks + - Add owner permission checks to AS item fetch + - Perform zot6 discovery in import_author_xchan + - Fix authenticated fetches + - Port zot_record_preferred() from zap + + Addons: + - Pubcrawl: deliver comments to abook contacts and thread participants + - Pubcrawl: fix can_comment_on_post() + - Deliverynotice: do not save empty postopts + - Gravatar: fix URL and use z_fetch_url() + - Pubcrawl: improve SQL queries in pubcrawl_item_mod_init() + - Pubcrawl: fix authenticated item fetch + + Hubzilla 4.0 (2019-03-08) - Add CURLOPT_CONNECTTIMEOUT option - Allow parameters as final path argument in API router diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index f0351fcdd..dbfcff439 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -85,6 +85,7 @@ class Cron_daily { Master::Summon(array('Cli_suggest')); remove_obsolete_hublocs(); + z6_discover(); call_hooks('cron_daily',datetime_convert()); diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php index a8cf34ce2..84bf7e923 100644 --- a/Zotlabs/Daemon/Poller.php +++ b/Zotlabs/Daemon/Poller.php @@ -199,6 +199,7 @@ class Poller { set_config('system','lastpoll',datetime_convert()); //All done - clear the lockfile + @unlink($lockfile); return; diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 9aaf6d866..5b9d356bb 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2,6 +2,7 @@ namespace Zotlabs\Lib; +use Zotlabs\Daemon\Master; use Zotlabs\Zot6\HTTPSig; class Activity { @@ -526,6 +527,10 @@ class Activity { else return []; + if(strpos($i['body'],'[/share]') !== false) { + $i['obj'] = null; + } + if($i['obj']) { if(! is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'],true); @@ -868,7 +873,7 @@ class Activity { // Send an Accept back to them set_abconfig($channel['channel_id'],$person_obj['id'],'pubcrawl','their_follow_id', $their_follow_id); - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); return; case 'Accept': @@ -969,9 +974,9 @@ class Activity { if($my_perms && $automatic) { // send an Accept for this Follow activity - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); // Send back a Follow notification to them - \Zotlabs\Daemon\Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); + Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); } $clone = array(); @@ -1162,7 +1167,7 @@ class Activity { $photos = import_xchan_photo($icon,$url); $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('UTC','UTC',$arr['photo_updated'])), + dbescdate(datetime_convert('UTC','UTC',$photos[5])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -1406,7 +1411,7 @@ class Activity { if($parent) { if($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(array('Notifier','comment-import',$x['item_id'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) @@ -1790,7 +1795,7 @@ class Activity { $s['item_private'] = 1; set_iconfig($s,'activitypub','recips',$act->raw_recips); - + // @FIXME: $parent is not defined if($parent) { set_iconfig($s,'activitypub','rawmsg',$act->raw,1); } @@ -1921,10 +1926,11 @@ class Activity { if(is_array($x) && $x['item_id']) { + // @FIXME: $parent is not defined if($parent) { if($s['owner_xchan'] === $channel['channel_hash']) { // We are the owner of this conversation, so send all received comments back downstream - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$x['item_id'])); + Master::Summon(array('Notifier','comment-import',$x['item_id'])); } $r = q("select * from item where id = %d limit 1", intval($x['item_id']) @@ -2060,7 +2066,7 @@ class Activity { if($result['success']) { // if the message isn't already being relayed, notify others if(intval($parent_item['item_origin'])) - Zotlabs\Daemon\Master::Summon(array('Notifier','comment-import',$result['item_id'])); + Master::Summon(array('Notifier','comment-import',$result['item_id'])); sync_an_item($channel['channel_id'],$result['item_id']); } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index a357b6d69..006744aff 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -319,7 +319,10 @@ class ActivityStreams { function get_compound_property($property, $base = '', $namespace = '', $first = false) { $x = $this->get_property_obj($property, $base, $namespace); if($this->is_url($x)) { - $x = $this->fetch_property($x); + $y = $this->fetch_property($x); + if (is_array($y)) { + $x = $y; + } } // verify and unpack JSalmon signature if present diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index 7541c68a4..fefc6639d 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -328,6 +328,7 @@ class Apps { 'Bookmarks' => t('Bookmarks'), 'Chatrooms' => t('Chatrooms'), 'Content Filter' => t('Content Filter'), + 'Content Import' => t('Content Import'), 'Connections' => t('Connections'), 'Remote Diagnostics' => t('Remote Diagnostics'), 'Suggest Channels' => t('Suggest Channels'), diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 5e5798cac..a7082f45a 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -754,9 +754,9 @@ class Enotify { // generate a multipart/alternative message header $messageHeader = $params['additionalMailHeader'] . - "From: $fromName <{$params['fromEmail']}>\n" . - "Reply-To: $fromName <{$params['replyTo']}>\n" . - "MIME-Version: 1.0\n" . + "From: $fromName <{$params['fromEmail']}>" . PHP_EOL . + "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL . + "MIME-Version: 1.0" . PHP_EOL . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\""; // assemble the final multipart message body with the text and html types included @@ -764,15 +764,15 @@ class Enotify { $htmlBody = chunk_split(base64_encode($params['htmlVersion'])); $multipartMessageBody = - "--" . $mimeBoundary . "\n" . // plain text section - "Content-Type: text/plain; charset=UTF-8\n" . - "Content-Transfer-Encoding: base64\n\n" . - $textBody . "\n" . - "--" . $mimeBoundary . "\n" . // text/html section - "Content-Type: text/html; charset=UTF-8\n" . - "Content-Transfer-Encoding: base64\n\n" . - $htmlBody . "\n" . - "--" . $mimeBoundary . "--\n"; // message ending + "--" . $mimeBoundary . PHP_EOL . // plain text section + "Content-Type: text/plain; charset=UTF-8" . PHP_EOL . + "Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL . + $textBody . PHP_EOL . + "--" . $mimeBoundary . PHP_EOL . // text/html section + "Content-Type: text/html; charset=UTF-8" . PHP_EOL . + "Content-Transfer-Encoding: base64" . PHP_EOL . PHP_EOL . + $htmlBody . PHP_EOL . + "--" . $mimeBoundary . "--" . PHP_EOL; // message ending // send the message $res = mail( diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index fd1538f0b..70602bbbc 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1197,12 +1197,14 @@ class Libzot { //logger($AS->debug()); - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + $r = q("select hubloc_hash, hubloc_network from hubloc where hubloc_id_url = '%s' ", dbesc($AS->actor['id']) ); if($r) { - $arr['author_xchan'] = $r[0]['hubloc_hash']; + // selects a zot6 hash if available, otherwise use whatever we have + $r = self::zot_record_preferred($r); + $arr['author_xchan'] = $r['hubloc_hash']; } @@ -3096,4 +3098,22 @@ class Libzot { return(($x) ? true : false); } + + static public function zot_record_preferred($arr, $check = 'hubloc_network') { + + if(! $arr) { + return $arr; + } + + foreach($arr as $v) { + if($v[$check] === 'zot6') { + + return $v; + } + } + + return $arr[0]; + + } + } diff --git a/Zotlabs/Lib/MessageFilter.php b/Zotlabs/Lib/MessageFilter.php index eb0fc3d2c..750d6d424 100644 --- a/Zotlabs/Lib/MessageFilter.php +++ b/Zotlabs/Lib/MessageFilter.php @@ -19,7 +19,7 @@ class MessageFilter { $lang = null; - if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false)) { + if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) { $lang = detect_language($text); } @@ -39,10 +39,17 @@ class MessageFilter { 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; } @@ -60,10 +67,17 @@ class MessageFilter { 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; } diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 5fdefd805..d4ef94e06 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -414,12 +414,12 @@ class Channel extends Controller { '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), '$search' => $search, '$xchan' => '', - '$order' => $order, + '$order' => (($order) ? urlencode($order) : ''), '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$file' => '', '$cats' => (($category) ? urlencode($category) : ''), '$tags' => (($hashtags) ? urlencode($hashtags) : ''), - '$mid' => $mid, + '$mid' => (($mid) ? urlencode($mid) : ''), '$verb' => '', '$net' => '', '$dend' => $datequery, diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index 967e9521d..6a93b3462 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -329,7 +329,7 @@ class Connections extends \Zotlabs\Web\Controller { killme(); } else { - $o .= ""; + $o .= ""; $o .= replace_macros(get_markup_template('connections.tpl'),array( '$header' => t('Connections') . (($head) ? ': ' . $head : ''), '$tabs' => $tabs, diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index a587324df..acd7cb769 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -848,7 +848,7 @@ class Connedit extends \Zotlabs\Web\Controller { $locstr = unpunify($contact['xchan_url']); $clone_warn = ''; - $clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false); + $clonable = (in_array($contact['xchan_network'],['zot', 'zot6', 'rss']) ? true : false); if(! $clonable) { $clone_warn = ''; $clone_warn .= ((intval($contact['abook_not_here'])) diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index c29fa8326..5448a4816 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -399,7 +399,7 @@ class Directory extends \Zotlabs\Web\Controller { $dirtitle = (($globaldir) ? t('Global Directory') : t('Local Directory')); - $o .= ""; + $o .= ""; $o .= replace_macros($tpl, array( '$search' => $search, '$desc' => t('Find'), diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 04e5f9fce..258aac556 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -233,7 +233,7 @@ class Display extends \Zotlabs\Web\Controller { '$dbegin' => '', '$verb' => '', '$net' => '', - '$mid' => $mid + '$mid' => (($mid) ? urlencode($mid) : '') )); head_add_link([ diff --git a/Zotlabs/Module/Dreport.php b/Zotlabs/Module/Dreport.php index 2c125b7a9..0fc36dc29 100644 --- a/Zotlabs/Module/Dreport.php +++ b/Zotlabs/Module/Dreport.php @@ -16,17 +16,20 @@ class Dreport extends \Zotlabs\Web\Controller { $channel = \App::get_channel(); $mid = ((argc() > 1) ? argv(1) : ''); + $encoded_mid = ''; - if(strpos($mid,'b64.') === 0) + if(strpos($mid,'b64.') === 0) { + $encoded_mid = $mid; $mid = @base64url_decode(substr($mid,4)); - - + } if($mid === 'push') { $table = 'push'; $mid = ((argc() > 2) ? argv(2) : ''); - if(strpos($mid,'b64.') === 0) + if(strpos($mid,'b64.') === 0) { + $encoded_mid = $mid; $mid = @base64url_decode(substr($mid,4)); + } if($mid) { $i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ", @@ -40,7 +43,7 @@ class Dreport extends \Zotlabs\Web\Controller { } } sleep(3); - goaway(z_root() . '/dreport/' . urlencode($mid)); + goaway(z_root() . '/dreport/' . (($encoded_mid) ? $encoded_mid : $mid)); } if($mid === 'mail') { @@ -159,6 +162,7 @@ class Dreport extends \Zotlabs\Web\Controller { '$title' => sprintf( t('Delivery report for %1$s'),basename($mid)) . '...', '$table' => $table, '$mid' => urlencode($mid), + '$safe_mid' => urlencode(gen_link_id($mid)), '$options' => t('Options'), '$push' => t('Redeliver'), '$entries' => $entries diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index 3535ac71a..848fe3e25 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -194,7 +194,7 @@ class Hq extends \Zotlabs\Web\Controller { '$dbegin' => '', '$verb' => '', '$net' => '', - '$mid' => $mid + '$mid' => (($mid) ? urlencode($mid) : '') ]); } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index 0daf28aa9..9d047ed7b 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -472,6 +472,9 @@ class Import extends \Zotlabs\Web\Controller { if(is_array($data['app'])) import_apps($channel,$data['app']); + if(is_array($data['sysapp'])) + import_sysapps($channel,$data['sysapp']); + if(is_array($data['chatroom'])) import_chatrooms($channel,$data['chatroom']); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index ebcf632ef..c466e7c82 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -40,56 +40,78 @@ class Item extends Controller { function init() { - if(Libzot::is_zot_request()) { + if (Libzot::is_zot_request()) { $conversation = false; $item_id = argv(1); - if(! $item_id) + 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)? + + $r = q("select * from item where mid = '%s' $item_normal limit 1", + dbesc(z_root() . '/item/' . $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']; + observer_auth($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 + + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($sigdata['portable_id']) + ); + + 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 ($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']) + ); + } + } } - $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 "; + // 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 $sql_extra = item_permissions_sql(0); - $r = q("select * from item where mid = '%s' $item_normal $sql_extra limit 1", - dbesc(z_root() . '/item/' . $item_id) - ); - if(! $r) { - - - $r = q("select * from item where mid = '%s' $item_normal limit 1", - dbesc(z_root() . '/item/' . $item_id) + if (! $i) { + $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1", + dbesc($r[0]['parent_mid']) ); - if($r) { - http_status_exit(403, 'Forbidden'); - } - http_status_exit(404, 'Not found'); } - - $items = q("select parent as item_id from item where mid = '%s' and uid = %d $item_normal $sql_extra ", - dbesc($r[0]['parent_mid']), - intval($r[0]['uid']) - ); - if(! $items) { - http_status_exit(404, 'Not found'); + if(! $i) { + http_status_exit(403,'Forbidden'); } - $r = $items; - - $parents_str = ids_to_querystr($r,'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 $sql_extra ", + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ", dbesc($parents_str) ); @@ -97,9 +119,8 @@ class Item extends Controller { http_status_exit(404, 'Not found'); } - $r = $items; - xchan_query($r,true); - $items = fetch_post_tags($r,true); + xchan_query($items,true); + $items = fetch_post_tags($items,true); $observer = App::get_observer(); $parent = $items[0]; diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 2019082ed..1c16e34ef 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -368,19 +368,19 @@ class Network extends \Zotlabs\Web\Controller { '$static' => $static, '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => (($search) ? $search : ''), - '$xchan' => $xchan, + '$search' => (($search) ? urlencode($search) : ''), + '$xchan' => (($xchan) ? urlencode($xchan) : ''), '$order' => $order, - '$file' => $file, - '$cats' => urlencode($category), - '$tags' => urlencode($hashtags), + '$file' => (($file) ? urlencode($file) : ''), + '$cats' => (($category) ? urlencode($category) : ''), + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), '$dend' => $datequery, '$mid' => '', - '$verb' => $verb, - '$net' => $net, + '$verb' => (($verb) ? urlencode($verb) : ''), + '$net' => (($net) ? urlencode($net) : ''), '$dbegin' => $datequery2, - '$pf' => (($pf) ? $pf : '0'), - '$unseen' => $unseen + '$pf' => (($pf) ? intval($pf) : 0), + '$unseen' => (($unseen) ? urlencode($unseen) : '') )); } diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index a761dbd14..3a6d77f00 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -848,7 +848,7 @@ class Photos extends \Zotlabs\Web\Controller { killme(); } else { - $o .= ""; + $o .= ""; $tpl = get_markup_template('photo_album.tpl'); $o .= replace_macros($tpl, array( '$photos' => $photos, @@ -1396,7 +1396,7 @@ class Photos extends \Zotlabs\Web\Controller { killme(); } else { - $o .= ""; + $o .= ""; $tpl = get_markup_template('photos_recent.tpl'); $o .= replace_macros($tpl, array( '$title' => t('Recent Photos'), diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 94df29984..84ac42f72 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -149,11 +149,11 @@ class Pubstream extends \Zotlabs\Web\Controller { '$order' => 'comment', '$file' => '', '$cats' => '', - '$tags' => $hashtags, + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), '$dend' => '', - '$mid' => $mid, + '$mid' => (($mid) ? urlencode($mid) : ''), '$verb' => '', - '$net' => $net, + '$net' => (($net) ? urlencode($net) : ''), '$dbegin' => '' )); } diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index ce0538099..c809ff5ec 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -732,6 +732,12 @@ class Setup extends \Zotlabs\Web\Controller { // install the standard theme set_config('system', 'allowed_themes', 'redbasic'); + // if imagick converter is installed, use it + if(@is_executable('/usr/bin/convert')) { + set_config('system','imagick_convert_path','/usr/bin/convert'); + } + + // Set a lenient list of ciphers if using openssl. Other ssl engines // (e.g. NSS used in RedHat) require different syntax, so hopefully // the default curl cipher list will work for most sites. If not, diff --git a/Zotlabs/Module/Viewconnections.php b/Zotlabs/Module/Viewconnections.php index 0a5e86907..30df0b9e4 100644 --- a/Zotlabs/Module/Viewconnections.php +++ b/Zotlabs/Module/Viewconnections.php @@ -107,7 +107,7 @@ class Viewconnections extends \Zotlabs\Web\Controller { killme(); } else { - $o .= ""; + $o .= ""; $tpl = get_markup_template("viewcontact_template.tpl"); $o .= replace_macros($tpl, array( '$title' => t('View Connections'), diff --git a/Zotlabs/Update/_1231.php b/Zotlabs/Update/_1231.php new file mode 100644 index 000000000..a685c5b28 --- /dev/null +++ b/Zotlabs/Update/_1231.php @@ -0,0 +1,73 @@ + $data['message_id'], 'encoding' => 'activitystreams' ]); + $messages = zot_feed($c[0]['channel_id'], $sender, [ 'message_id' => $data['message_id'], 'encoding' => 'activitystreams' ]); return (($messages) ? : [] ); } diff --git a/boot.php b/boot.php index 2c352dfae..338a3e3ae 100755 --- a/boot.php +++ b/boot.php @@ -50,10 +50,10 @@ require_once('include/attach.php'); require_once('include/bbcode.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '4.0' ); +define ( 'STD_VERSION', '4.0.1' ); define ( 'ZOT_REVISION', '6.0a' ); -define ( 'DB_UPDATE_VERSION', 1230 ); +define ( 'DB_UPDATE_VERSION', 1231 ); define ( 'PROJECT_BASE', __DIR__ ); diff --git a/composer.json b/composer.json index e6cefa241..cb14083f0 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,9 @@ "behat/mink-extension": "@stable", "behat/mink-goutte-driver": "@stable", "php-mock/php-mock-phpunit": "@stable", - "phpunit/dbunit": "@stable" + "phpunit/dbunit": "@stable", + "phpmd/phpmd": "^2.6", + "squizlabs/php_codesniffer": "*" }, "autoload" : { "psr-4" : { diff --git a/composer.lock b/composer.lock index c4fba0975..2631b8dac 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fe5e71d7076eeddf1c174be4a5c052dd", + "content-hash": "8da1fe9aabe6c20d116a21f63fff8ac2", "packages": [ { "name": "blueimp/jquery-file-upload", @@ -2038,6 +2038,46 @@ ], "time": "2018-06-11T23:09:50+00:00" }, + { + "name": "pdepend/pdepend", + "version": "2.5.2", + "source": { + "type": "git", + "url": "https://github.com/pdepend/pdepend.git", + "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", + "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", + "shasum": "" + }, + "require": { + "php": ">=5.3.7", + "symfony/config": "^2.3.0|^3|^4", + "symfony/dependency-injection": "^2.3.0|^3|^4", + "symfony/filesystem": "^2.3.0|^3|^4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "squizlabs/php_codesniffer": "^2.0.0" + }, + "bin": [ + "src/bin/pdepend" + ], + "type": "library", + "autoload": { + "psr-4": { + "PDepend\\": "src/main/php/PDepend" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of pdepend to be handled with Composer", + "time": "2017-12-13T13:21:38+00:00" + }, { "name": "phar-io/manifest", "version": "1.0.3", @@ -2460,6 +2500,72 @@ ], "time": "2017-07-14T14:27:02+00:00" }, + { + "name": "phpmd/phpmd", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpmd/phpmd.git", + "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374", + "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "pdepend/pdepend": "^2.5", + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.0" + }, + "bin": [ + "src/bin/phpmd" + ], + "type": "project", + "autoload": { + "psr-0": { + "PHPMD\\": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Manuel Pichler", + "email": "github@manuel-pichler.de", + "homepage": "https://github.com/manuelpichler", + "role": "Project Founder" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "homepage": "https://github.com/ravage84", + "role": "Project Maintainer" + } + ], + "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", + "homepage": "http://phpmd.org/", + "keywords": [ + "mess detection", + "mess detector", + "pdepend", + "phpmd", + "pmd" + ], + "time": "2017-01-20T14:41:10+00:00" + }, { "name": "phpspec/prophecy", "version": "1.8.0", @@ -3614,6 +3720,57 @@ "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03T07:35:21+00:00" }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "379deb987e26c7cd103a7b387aea178baec96e48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/379deb987e26c7cd103a7b387aea178baec96e48", + "reference": "379deb987e26c7cd103a7b387aea178baec96e48", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2018-12-19T23:57:18+00:00" + }, { "name": "symfony/browser-kit", "version": "v4.2.1", diff --git a/include/account.php b/include/account.php index 2ab99ce19..5f0c8737f 100644 --- a/include/account.php +++ b/include/account.php @@ -142,12 +142,10 @@ function create_account($arr) { $invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : ''); $email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : ''); $password = ((x($arr,'password')) ? trim($arr['password']) : ''); - $password2 = ((x($arr,'password2')) ? trim($arr['password2']) : ''); $parent = ((x($arr,'parent')) ? intval($arr['parent']) : 0 ); $flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK); $roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 ); $expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE); - $techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel'))); $default_service_class = get_config('system','default_service_class'); @@ -264,9 +262,8 @@ function create_account($arr) { function verify_email_address($arr) { if(array_key_exists('resend',$arr)) { - $email = $arr['email']; $a = q("select * from account where account_email = '%s' limit 1", - dbesc($arr['email']) + dbesc($arr['email']) ); if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) { return false; @@ -285,7 +282,7 @@ function verify_email_address($arr) { else { $hash = random_string(24); - $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", + q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", dbesc($hash), dbesc(datetime_convert()), intval($arr['account']['account_id']), @@ -304,7 +301,7 @@ function verify_email_address($arr) { '$email' => $arr['email'], '$uid' => $account['account_id'], '$hash' => $hash, - '$details' => $details + '$details' => '' ] ); @@ -318,9 +315,7 @@ function verify_email_address($arr) { pop_lang(); - if($res) - $delivered ++; - else + if(! $res) logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']); return $res; @@ -442,16 +437,17 @@ function account_allow($hash) { if(! $account) return $ret; - $r = q("DELETE FROM register WHERE hash = '%s'", + q("DELETE FROM register WHERE hash = '%s'", dbesc($register[0]['hash']) ); - $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", + q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", intval(ACCOUNT_BLOCKED), intval(ACCOUNT_BLOCKED), intval($register[0]['uid']) ); - $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", + + q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", intval(ACCOUNT_PENDING), intval(ACCOUNT_PENDING), intval($register[0]['uid']) @@ -516,11 +512,11 @@ function account_deny($hash) { if(! $account) return false; - $r = q("DELETE FROM account WHERE account_id = %d", + q("DELETE FROM account WHERE account_id = %d", intval($register[0]['uid']) ); - $r = q("DELETE FROM register WHERE id = %d", + q("DELETE FROM register WHERE id = %d", dbesc($register[0]['id']) ); notice( sprintf(t('Registration revoked for %s'), $account[0]['account_email']) . EOL); @@ -551,21 +547,23 @@ function account_approve($hash) { if(! $account) return $ret; - $r = q("DELETE FROM register WHERE hash = '%s' and password = 'verify'", + q("DELETE FROM register WHERE hash = '%s' and password = 'verify'", dbesc($register[0]['hash']) ); - $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", + q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", intval(ACCOUNT_BLOCKED), intval(ACCOUNT_BLOCKED), intval($register[0]['uid']) ); - $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", + + q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", intval(ACCOUNT_PENDING), intval(ACCOUNT_PENDING), intval($register[0]['uid']) ); - $r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", + + q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d", intval(ACCOUNT_UNVERIFIED), intval(ACCOUNT_UNVERIFIED), intval($register[0]['uid']) @@ -620,7 +618,7 @@ function downgrade_accounts() { foreach($r as $rr) { if(($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) { - $x = q("UPDATE account set account_service_class = '%s', account_expires = '%s' + q("UPDATE account set account_service_class = '%s', account_expires = '%s' where account_id = %d", dbesc($basic), dbesc(NULL_DATE), @@ -631,7 +629,7 @@ function downgrade_accounts() { logger('downgrade_accounts: Account id ' . $rr['account_id'] . ' downgraded.'); } else { - $x = q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d", + q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d", intval(ACCOUNT_EXPIRED), intval($rr['account_id']) ); diff --git a/include/acl_selectors.php b/include/acl_selectors.php index c7a87afee..35e385058 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -84,7 +84,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti ); if($r) { foreach($r as $rv) { - $selected = (($single_group && 'vp.' . $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : ''); + $selected = (($single_group && 'vp.' . $rv['profile_guid'] === $allow_gid[0]) ? ' selected = "selected" ' : ''); $groups .= '' . "\r\n"; } } diff --git a/include/attach.php b/include/attach.php index 17a47d9ac..f6594b154 100644 --- a/include/attach.php +++ b/include/attach.php @@ -321,7 +321,6 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) { $sql_extra = permissions_sql($uid,$ob_hash); $hash = $folder_hash; - $result = false; if(! $folder_hash) { return perm_is_allowed($uid,$ob_hash,'view_storage'); @@ -352,7 +351,7 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) { * @param string $hash * @param string $observer_hash * @param int $rev (optional) revision default 0 - * @return associative array with everything except data + * @return array (associative) with everything except data * * \e boolean \b success boolean true or false * * \e string \b message (optional) only when success is false * * \e array \b data array of attach DB entry without data component @@ -1224,7 +1223,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { $ret['success'] = true; // update the parent folder's lastmodified timestamp - $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", + q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($created), dbesc($arr['folder']), intval($channel_id) @@ -1270,8 +1269,6 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) { $ret = array('success' => false); $channel_id = $channel['channel_id']; - $sql_options = ''; - $basepath = 'store/' . $channel['channel_address']; logger('basepath: ' . $basepath); @@ -1374,7 +1371,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi } } - $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d", + q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d", dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), @@ -1383,7 +1380,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi intval($channel_id) ); if($r[0]['is_photo']) { - $x = q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d", + q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d", dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), @@ -1482,7 +1479,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { } // delete from database - $z = q("DELETE FROM attach WHERE hash = '%s' AND uid = %d", + q("DELETE FROM attach WHERE hash = '%s' AND uid = %d", dbesc($resource), intval($channel_id) ); @@ -1493,7 +1490,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { // update the parent folder's lastmodified timestamp - $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", + q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc(datetime_convert()), dbesc($r[0]['folder']), intval($channel_id) @@ -1815,7 +1812,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $u_jsonobject = json_encode($object); //we have got the relevant info - delete the old item before we create the new one - $z = q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'", + q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'", dbesc(ACTIVITY_OBJ_FILE), dbesc(ACTIVITY_POST), dbesc($y[0]['mid']) @@ -1946,7 +1943,6 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $ $ret = array(); $parent_arr = array(); $count_values = array(); - $poster = App::get_observer(); //lookup all channels in sharee group and add them to sharee $arr_allow_cid if($arr_allow_gid) { @@ -2351,7 +2347,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { if(! $n) return false; - $newdirname = $n[0]['filename']; $newalbumname = $n[0]['display_path']; $newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id; } @@ -2359,7 +2354,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { // root directory - $newdirname = EMPTY_STR; $newalbumname = EMPTY_STR; $newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id; } @@ -2428,7 +2422,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { } } - $t = q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d", + q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d", dbescbin($newstorepath), dbesc($new_folder_hash), dbesc($filename), @@ -2438,7 +2432,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { $x = attach_syspaths($channel_id,$resource_id); - $t1 = q("update attach set os_path = '%s', display_path = '%s' where id = %d", + q("update attach set os_path = '%s', display_path = '%s' where id = %d", dbesc($x['os_path']), dbesc($x['path']), intval($r[0]['id']) @@ -2446,7 +2440,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { if($r[0]['is_photo']) { - $t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s' + q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s' where resource_id = '%s' and uid = %d", dbesc($newalbumname), dbesc($filename), @@ -2456,7 +2450,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { intval($channel_id) ); - $t = q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0", + q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0", dbescbin($newstorepath), dbesc($resource_id), intval($channel_id) @@ -2587,12 +2581,12 @@ function attach_upgrade() { foreach($r as $rv) { $x = attach_syspaths($rv['uid'],$rv['hash']); if($x) { - $w = q("update attach set os_path = '%s', display_path = '%s' where id = %d", + q("update attach set os_path = '%s', display_path = '%s' where id = %d", dbesc($x['os_path']), dbesc($x['path']), intval($rv['id']) ); - $y = q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'", + q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'", dbesc($x['os_path']), dbesc($x['path']), intval($rv['uid']), diff --git a/include/bbcode.php b/include/bbcode.php index 7531bd774..36f943e46 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -117,6 +117,26 @@ function tryzrlvideo($match) { return ''; } +function videowithopts($match) { + $link = $match[2]; + $zrl = is_matrix_url($link); + if($zrl) + $link = zid($link); + + $attributes = $match[1]; + + $poster = ""; + + preg_match("/poster='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"'; + + return ''; +} + + + + // [noparse][i]italic[/i][/noparse] turns into // [noparse][ i ]italic[ /i ][/noparse], // to hide them from parser. @@ -1251,12 +1271,14 @@ function bbcode($Text, $options = []) { // html5 video and audio if (strpos($Text,'[/video]') !== false) { + $Text = preg_replace_callback("/\[video (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'videowithopts', $Text); $Text = preg_replace_callback("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'tryzrlvideo', $Text); } if (strpos($Text,'[/audio]') !== false) { $Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/audio\]/ism", 'tryzrlaudio', $Text); } if (strpos($Text,'[/zvideo]') !== false) { + $Text = preg_replace_callback("/\[zvideo (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'videowithopts', $Text); $Text = preg_replace_callback("/\[zvideo\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'tryzrlvideo', $Text); } if (strpos($Text,'[/zaudio]') !== false) { @@ -1360,4 +1382,3 @@ function bbcode($Text, $options = []) { return $Text; } - diff --git a/include/channel.php b/include/channel.php index f705ba4d2..654bbdb05 100644 --- a/include/channel.php +++ b/include/channel.php @@ -948,6 +948,18 @@ function identity_basic_export($channel_id, $sections = null) { } $ret['app'] = $r; } + $r = q("select * from app where app_channel = %d and app_system = 1", + intval($channel_id) + ); + if($r) { + for($x = 0; $x < count($r); $x ++) { + $r[$x]['term'] = q("select * from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($r[$x]['id']) + ); + } + $ret['sysapp'] = $r; + } } if(in_array('chatrooms',$sections)) { @@ -1439,7 +1451,7 @@ function profile_edit_menu($uid) { * @param boolean $show_connect (optional) default true * @param mixed $zcard (optional) default false * - * @return HTML string suitable for sidebar inclusion + * @return string (HTML) suitable for sidebar inclusion * Exceptions: Returns empty string if passed $profile is wrong type or not populated */ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = false) { diff --git a/include/follow.php b/include/follow.php index db77a0160..1b35f1b32 100644 --- a/include/follow.php +++ b/include/follow.php @@ -119,6 +119,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if( array_key_exists('permissions',$j) && array_key_exists('data',$j['permissions'])) { $permissions = crypto_unencapsulate(array( 'data' => $j['permissions']['data'], + 'alg' => $j['permissions']['alg'], 'key' => $j['permissions']['key'], 'iv' => $j['permissions']['iv']), $channel['channel_prvkey']); diff --git a/include/hubloc.php b/include/hubloc.php index b2903b0ee..7cb00f788 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -305,3 +305,39 @@ function ping_site($url) { return $ret; } + + +function z6_discover() { + + // find unregistered zot6 clone hublocs + + $c = q("select channel_hash, portable_id from channel where channel_deleted = 0"); + if ($c) { + foreach ($c as $entry) { + $q1 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url != '%s'", + dbesc($entry['channel_hash']), + dbesc(z_root()) + ); + if (! $q1) { + // channel has no zot clones + continue; + } + // does this particular server have a zot6 clone registered on our site for this channel? + foreach ($q1 as $q) { + $q2 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url = '%s'", + dbesc($entry['portable_id']), + dbesc($q['hubloc_url']) + ); + if ($q2) { + continue; + } + // zot6 hubloc not found. + if(strpos($entry['site_project'],'hubzilla') !== false && version_compare($entry['site_version'],'4.0') >= 0) { + // probe and store results - only for zot6 (over-ride the zot default) + discover_by_webbie($entry['hubloc_addr'],'zot6'); + } + } + } + } + +} \ No newline at end of file diff --git a/include/import.php b/include/import.php index f391400bd..8d1a19202 100644 --- a/include/import.php +++ b/include/import.php @@ -147,7 +147,9 @@ function import_config($channel, $configs) { foreach($configs as $config) { unset($config['id']); $config['uid'] = $channel['channel_id']; - + if($config['cat'] === 'system' && $config['k'] === 'import_system_apps') { + continue; + } create_table_from_array('pconfig', $config); } @@ -364,6 +366,9 @@ function import_apps($channel, $apps) { if($channel && $apps) { foreach($apps as $app) { + if(array_key_exists('app_system',$app) && intval($app['app_system'])) + continue; + $term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null); unset($app['id']); @@ -413,6 +418,9 @@ function sync_apps($channel, $apps) { $exists = false; $term = ((array_key_exists('term',$app)) ? $app['term'] : null); + if(array_key_exists('app_system',$app) && intval($app['app_system'])) + continue; + $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", dbesc($app['app_id']), intval($channel['channel_id']) @@ -504,6 +512,84 @@ function sync_apps($channel, $apps) { } } + + +/** + * @brief Import system apps. + * System apps from the original server may not exist on this system + * (e.g. apps associated with addons that are not installed here). + * Check the system apps that were provided in the import file to see if they + * exist here and if so, install them locally. Preserve categories that + * might have been added by this channel on the other server. + * Do not use any paths from the original as they will point to a different server. + * @param array $channel + * @param array $apps + */ +function import_sysapps($channel, $apps) { + + if($channel && $apps) { + + $sysapps = \Zotlabs\Lib\Apps::get_system_apps(false); + + foreach($apps as $app) { + + if(array_key_exists('app_system',$app) && (! intval($app['app_system']))) + continue; + + $term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null); + + foreach($sysapps as $sysapp) { + if($app['app_id'] === hash('whirlpool',$sysapp['app_name'])) { + // install this app on this server + $newapp = $sysapp; + $newapp['uid'] = $channel['channel_id']; + $newapp['guid'] = hash('whirlpool',$newapp['name']); + + $installed = q("select id from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($newapp['guid']), + intval($channel['channel_id']) + ); + if($installed) { + break; + } + + $newapp['system'] = 1; + if($term) { + $s = EMPTY_STR; + foreach($term as $t) { + if($s) { + $s .= ','; + } + $s .= $t['term']; + } + $newapp['categories'] = $s; + } + \Zotlabs\Lib\Apps::app_install($channel['channel_id'],$newapp); + } + } + } + } +} + +/** + * @brief Sync system apps. + * + * @param array $channel + * @param array $apps + */ +function sync_sysapps($channel, $apps) { + + if($channel && $apps) { + + // we do not currently sync system apps + + } +} + + + + + /** * @brief Import chatrooms. * diff --git a/include/items.php b/include/items.php index 51aa81017..c9c2e2d48 100755 --- a/include/items.php +++ b/include/items.php @@ -763,11 +763,11 @@ function get_item_elements($x,$allow_code = false) { // check the supplied signature against the supplied content. // Note that we will purify the content which could change it. - $r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", + $r = q("select xchan_pubkey, xchan_network from xchan where xchan_hash = '%s' limit 1", dbesc($arr['author_xchan']) ); if($r) { - if($r[0]['xchan_pubkey']) { + if($r[0]['xchan_pubkey'] && $r[0]['xchan_network'] === 'zot') { if(rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) { $arr['item_verified'] = 1; } @@ -914,6 +914,16 @@ function import_author_xchan($x) { if(array_key_exists('network',$x) && $x['network'] === 'zot') return $y; + // perform zot6 discovery + + if($x['url']) { + $y = discover_by_webbie($x['url'],'zot6'); + + if($y) { + return $y; + } + } + if($x['network'] === 'rss') { $y = import_author_rss($x); } diff --git a/include/nav.php b/include/nav.php index 58e13dd93..3e1acd306 100644 --- a/include/nav.php +++ b/include/nav.php @@ -42,6 +42,10 @@ function nav($template = 'default') { require_once('include/conversation.php'); + $nav_apps = []; + $navbar_apps = []; + $channel_apps = []; + $channel_apps[] = channel_apps($is_owner, App::$profile['channel_address']); @@ -179,7 +183,6 @@ function nav($template = 'default') { $search_form_action = 'search'; } - $nav['search'] = ['search', t('Search'), "", t('Search site @name, !forum, #tag, ?docs, content'), $search_form_action]; /** @@ -378,16 +381,15 @@ function channel_apps($is_owner = false, $nickname = null) { if(App::$is_sys) return ''; - if(! get_pconfig($uid, 'system', 'channelapps','1')) - return ''; - $channel = App::get_channel(); if($channel && is_null($nickname)) $nickname = $channel['channel_address']; $uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel()); - $account_id = ((App::$profile['profile_uid']) ? App::$profile['channel_account_id'] : App::$channel['channel_account_id']); + + if(! get_pconfig($uid, 'system', 'channelapps','1')) + return; if($uid == local_channel()) { return; diff --git a/include/network.php b/include/network.php index 12f2ad4e9..c754625cd 100644 --- a/include/network.php +++ b/include/network.php @@ -874,13 +874,16 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority = } -function email_header_encode($in_str, $charset = 'UTF-8') { +function email_header_encode($in_str, $charset = 'UTF-8', $header = 'Subject') { + + $out_str = $in_str; $need_to_convert = false; for($x = 0; $x < strlen($in_str); $x ++) { if((ord($in_str[$x]) == 0) || ((ord($in_str[$x]) > 128))) { $need_to_convert = true; + break; } } @@ -892,11 +895,11 @@ function email_header_encode($in_str, $charset = 'UTF-8') { // define start delimimter, end delimiter and spacer $end = "?="; $start = "=?" . $charset . "?B?"; - $spacer = $end . "\r\n " . $start; + $spacer = $end . PHP_EOL . " " . $start; // determine length of encoded text within chunks // and ensure length is even - $length = 75 - strlen($start) - strlen($end); + $length = 75 - strlen($start) - strlen($end) - (strlen($header) + 2); /* [EDIT BY danbrown AT php DOT net: The following @@ -1796,8 +1799,8 @@ function z_mail($params) { $messageHeader = $params['additionalMailHeader'] . - "From: $fromName <{$params['fromEmail']}>\n" . - "Reply-To: $fromName <{$params['replyTo']}>\n" . + "From: $fromName <{$params['fromEmail']}>" . PHP_EOL . + "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL . "Content-Type: text/plain; charset=UTF-8"; // send the message diff --git a/include/security.php b/include/security.php index 493d34699..38cb72263 100644 --- a/include/security.php +++ b/include/security.php @@ -306,6 +306,7 @@ function change_channel($change_channel) { * * @return string additional SQL where statement */ + function permissions_sql($owner_id, $remote_observer = null, $table = '') { $local_channel = local_channel(); @@ -316,7 +317,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') { * default permissions - anonymous user */ - if($table) + if ($table) $table .= '.'; $sql = " AND {$table}allow_cid = '' @@ -329,38 +330,63 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') { * Profile owner - everything is visible */ - if(($local_channel) && ($local_channel == $owner_id)) { - $sql = ''; + if (($local_channel) && ($local_channel == $owner_id)) { + return EMPTY_STR; } /** - * Authenticated visitor. Unless pre-verified, - * check that the contact belongs to this $owner_id - * and load the groups the visitor belongs to. - * If pre-verified, the caller is expected to have already - * done this and passed the groups into this function. + * Authenticated visitor. */ else { + $observer = ((! is_null($remote_observer)) ? $remote_observer : get_observer_hash()); - if($observer) { - $groups = init_groups_visitor($observer); - $gs = '<<>>'; // should be impossible to match + if ($observer) { - if(is_array($groups) && count($groups)) { - foreach($groups as $g) - $gs .= '|<' . $g . '>'; + $sec = get_security_ids($owner_id,$observer); + + // always allow the channel owner, even if authenticated as a visitor + + if ($sec['channel_id']) { + foreach ($sec['channel_id'] as $ch) { + if ($observer === $ch) { + return EMPTY_STR; + } + } + } + + if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) { + $ca = []; + foreach ($sec['allow_cid'] as $c) { + $ca[] = '<' . $c . '>'; + } + $cs = implode('|',$ca); } + else { + $cs = '<<>>'; // should be impossible to match + } + + if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) { + $ga = []; + foreach ($sec['allow_gid'] as $g) { + $ga[] = '<' . $g . '>'; + } + $gs = implode('|',$ga); + } + else { + $gs = '<<>>'; // should be impossible to match + } + $regexop = db_getfunc('REGEXP'); $sql = sprintf( - " AND ( NOT ({$table}deny_cid like '%s' OR {$table}deny_gid $regexop '%s') - AND ( {$table}allow_cid like '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') ) + " AND ( NOT ({$table}deny_cid $regexop '%s' OR {$table}deny_gid $regexop '%s') + AND ( {$table}allow_cid $regexop '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') ) ) ", - dbesc(protect_sprintf( '%<' . $observer . '>%')), + dbesc($cs), dbesc($gs), - dbesc(protect_sprintf( '%<' . $observer . '>%')), + dbesc($cs), dbesc($gs) ); } @@ -377,6 +403,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') { * * @return string additional SQL where statement */ + function item_permissions_sql($owner_id, $remote_observer = null) { $local_channel = local_channel(); @@ -398,37 +425,59 @@ function item_permissions_sql($owner_id, $remote_observer = null) { } /** - * Authenticated visitor. Unless pre-verified, - * check that the contact belongs to this $owner_id - * and load the groups the visitor belongs to. - * If pre-verified, the caller is expected to have already - * done this and passed the groups into this function. + * Authenticated visitor. */ else { - $observer = (($remote_observer) ? $remote_observer : get_observer_hash()); - if($observer) { + $observer = (($remote_observer) ? $remote_observer : get_observer_hash()); - $s = scopes_sql($owner_id,$observer); + if($observer) { - $groups = init_groups_visitor($observer); + $scope = scopes_sql($owner_id,$observer); + $sec = get_security_ids($owner_id,$observer); - $gs = '<<>>'; // should be impossible to match + // always allow the channel owner, even if authenticated as a visitor - if(is_array($groups) && count($groups)) { - foreach($groups as $g) - $gs .= '|<' . $g . '>'; + if($sec['channel_id']) { + foreach($sec['channel_id'] as $ch) { + if($observer === $ch) { + return EMPTY_STR; + } + } + } + + if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) { + $ca = []; + foreach ($sec['allow_cid'] as $c) { + $ca[] = '<' . $c . '>'; + } + $cs = implode('|',$ca); } + else { + $cs = '<<>>'; // should be impossible to match + } + + if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) { + $ga = []; + foreach ($sec['allow_gid'] as $g) { + $ga[] = '<' . $g . '>'; + } + $gs = implode('|',$ga); + } + else { + $gs = '<<>>'; // should be impossible to match + } + $regexop = db_getfunc('REGEXP'); $sql = sprintf( - " AND (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s') - AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 )) - ) OR ( item_private = 1 $s )) + " AND (( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s') + AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 )) + ) OR ( item_private = 1 $scope )) ", - dbesc(protect_sprintf( '%<' . $observer . '>%')), + dbesc($cs), dbesc($gs), - dbesc(protect_sprintf( '%<' . $observer . '>%')), + dbesc($cs), dbesc($gs) ); } @@ -465,40 +514,57 @@ function scopes_sql($uid,$observer) { } - - - - - /** * @param string $observer_hash * * @return string additional SQL where statement */ + function public_permissions_sql($observer_hash) { - $groups = init_groups_visitor($observer_hash); + $owner_id = 0; - $gs = '<<>>'; // should be impossible to match + if ($observer_hash) { + + $sec = get_security_ids($owner_id,$observer_hash); + + if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) { + $ca = []; + foreach ($sec['allow_cid'] as $c) { + $ca[] = '<' . $c . '>'; + } + $cs = implode('|',$ca); + } + else { + $cs = '<<>>'; // should be impossible to match + } + + if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) { + $ga = []; + foreach ($sec['allow_gid'] as $g) { + $ga[] = '<' . $g . '>'; + } + $gs = implode('|',$ga); + } + else { + $gs = '<<>>'; // should be impossible to match + } - if(is_array($groups) && count($groups)) { - foreach($groups as $g) - $gs .= '|<' . $g . '>'; - } - $sql = ''; - if($observer_hash) { $regexop = db_getfunc('REGEXP'); $sql = sprintf( - " OR (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s') - AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ) ) - )) + " AND ( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s') + AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0) ) + ) ", - dbesc(protect_sprintf( '%<' . $observer_hash . '>%')), + dbesc($cs), dbesc($gs), - dbesc(protect_sprintf( '%<' . $observer_hash . '>%')), + dbesc($cs), dbesc($gs) ); } + else { + $sql = EMPTY_STR; + } return $sql; } @@ -510,7 +576,7 @@ function public_permissions_sql($observer_hash) { * In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes; * or if the security token is used for ajax-calls that happen several times), but only valid for a certain amout of time (3hours). * The "typename" seperates the security tokens of different types of forms. This could be relevant in the following case: - * A security token is used to protekt a link from CSRF (e.g. the "delete this profile"-link). + * A security token is used to protect a link from CSRF (e.g. the "delete this profile"-link). * If the new page contains by any chance external elements, then the used security token is exposed by the referrer. * Actually, important actions should not be triggered by Links / GET-Requests at all, but somethimes they still are, * so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types). @@ -564,24 +630,40 @@ function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'f function init_groups_visitor($contact_id) { $groups = []; - // private profiles are treated as a virtual group - - $r = q("SELECT abook_profile from abook where abook_xchan = '%s' and abook_profile != '' ", + $x = q("select * from xchan where xchan_hash = '%s'", dbesc($contact_id) ); - if($r) { - foreach($r as $rv) { + + if (! $x) { + return $groups; + } + + // include xchans for all zot-like networks + + $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", + dbesc($contact_id), + dbesc($x[0]['xchan_guid']), + dbesc($x[0]['xchan_pubkey']) + ); + + if($xchans) { + $hashes = ids_to_querystr($xchans,'xchan_hash',true); + } + + // private profiles are treated as a virtual group + + $r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' "); + if ($r) { + foreach ($r as $rv) { $groups[] = 'vp.' . $rv['abook_profile']; } } - // physical groups this channel is a member of + // physical groups this identity is a member of - $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan = '%s' ", - dbesc($contact_id) - ); - if($r) { - foreach($r as $rr) + $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) "); + if ($r) { + foreach ($r as $rr) $groups[] = $rr['hash']; } return $groups; @@ -589,6 +671,70 @@ function init_groups_visitor($contact_id) { + +function get_security_ids($channel_id, $ob_hash) { + + $ret = [ + 'channel_id' => [], + 'allow_cid' => [], + 'allow_gid' => [] + ]; + + if($channel_id) { + $ch = q("select channel_hash, channel_portable_id from channel where channel_id = %d", + intval($channel_id) + ); + if($ch) { + $ret['channel_id'][] = $ch[0]['channel_hash']; + $ret['channel_id'][] = $ch[0]['channel_portable_id']; + } + } + + $groups = []; + + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($ob_hash) + ); + + if ($x) { + + // include xchans for all zot-like networks + + $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", + dbesc($ob_hash), + dbesc($x[0]['xchan_guid']), + dbesc($x[0]['xchan_pubkey']) + ); + + if ($xchans) { + $ret['allow_cid'] = ids_to_array($xchans,'xchan_hash'); + $hashes = ids_to_querystr($xchans,'xchan_hash',true); + + // private profiles are treated as a virtual group + + $r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' "); + if($r) { + foreach ($r as $rv) { + $groups[] = 'vp.' . $rv['abook_profile']; + } + } + + // physical groups this identity is a member of + + $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) "); + if($r) { + foreach ($r as $rv) { + $groups[] = $rv['hash']; + } + } + $ret['allow_gid'] = $groups; + } + } + + return $ret; +} + + // This is used to determine which uid have posts which are visible to the logged in user (from the API) for the // public_timeline, and we can use this in a community page by making // $perms = (PERMS_NETWORK|PERMS_PUBLIC) unless logged in. diff --git a/include/taxonomy.php b/include/taxonomy.php index 46d95458c..b0304de5b 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -543,8 +543,6 @@ function article_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0, function dir_tagblock($link,$r) { $o = ''; - $observer = get_observer_hash(); - if(! $r) $r = App::$data['directory_keywords']; diff --git a/include/text.php b/include/text.php index c466059b5..e5a5ee98d 100644 --- a/include/text.php +++ b/include/text.php @@ -20,7 +20,7 @@ define('RANDOM_STRING_TEXT', 0x01 ); /** * @brief This is our template processor. * - * @param string|SmartyEngine $s the string requiring macro substitution, + * @param string SmartyEngine $s the string requiring macro substitution, * or an instance of SmartyEngine * @param array $r key value pairs (search => replace) * @@ -2558,15 +2558,6 @@ function design_tools() { */ function website_portation_tools() { - $channel = App::get_channel(); - $sys = false; - - if(App::$is_sys && is_site_admin()) { - require_once('include/channel.php'); - $channel = get_sys_channel(); - $sys = true; - } - return replace_macros(get_markup_template('website_portation_tools.tpl'), [ '$title' => t('Import'), '$import_label' => t('Import website...'), @@ -2734,7 +2725,6 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) $name = substr($tag,(($exclusive) ? 2 : 1)); $newname = $name; // make a copy that we can mess with - $tagcid = 0; $r = null; @@ -2793,14 +2783,9 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) } - - - - $fn_results = []; $access_tag = EMPTY_STR; - // $r is set if we found something if($r) { diff --git a/include/xchan.php b/include/xchan.php index 4cbfb42c5..4fcdf9fce 100644 --- a/include/xchan.php +++ b/include/xchan.php @@ -1,6 +1,7 @@ $rr['hash']); + } } return $results; } diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql index 49a2c476a..cb4a3fa74 100644 --- a/install/schema_mysql.sql +++ b/install/schema_mysql.sql @@ -691,19 +691,16 @@ CREATE TABLE IF NOT EXISTS `item` ( KEY `changed` (`changed`), KEY `item_origin` (`item_origin`), KEY `item_wall` (`item_wall`), - KEY `item_unseen` (`item_unseen`), KEY `item_uplink` (`item_uplink`), - KEY `item_notshown` (`item_notshown`), KEY `item_nsfw` (`item_nsfw`), - KEY `item_relay` (`item_relay`), KEY `item_mentionsme` (`item_mentionsme`), KEY `item_nocomment` (`item_nocomment`), KEY `item_obscured` (`item_obscured`), - KEY `item_verified` (`item_verified`), KEY `item_rss` (`item_rss`), KEY `item_consensus` (`item_consensus`), KEY `item_deleted_pending_remove_changed` (`item_deleted`, `item_pending_remove`, `changed`), - KEY `item_pending_remove_changed` (`item_pending_remove`, `changed`) + KEY `item_pending_remove_changed` (`item_pending_remove`, `changed`), + KEY `thr_parent` (`thr_parent`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `item_id` ( diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql index 1b6cab51b..e56e054b0 100644 --- a/install/schema_postgres.sql +++ b/install/schema_postgres.sql @@ -627,7 +627,6 @@ CREATE TABLE "item" ( "item_search_vector" tsvector, PRIMARY KEY ("id") ); -create index "item_uid" on item ("uid"); create index "item_uuid" on item ("uuid"); create index "item_parent" on item ("parent"); create index "item_created" on item ("created"); @@ -638,17 +637,13 @@ create index "item_uid_created" on item ("uid","created"); create index "item_uid_unseen" on item ("uid","item_unseen"); create index "item_changed" on item ("changed"); create index "item_comments_closed" on item ("comments_closed"); -create index "item_aid" on item ("aid"); create index "item_owner_xchan" on item ("owner_xchan"); create index "item_author_xchan" on item ("author_xchan"); create index "item_resource_id" on item ("resource_id"); create index "item_resource_type" on item ("resource_type"); -create index "item_restrict" on item ("item_restrict"); -create index "item_flags" on item ("item_flags"); create index "item_commented" on item ("commented"); create index "item_verb" on item ("verb"); create index "item_obj_type" on item ("obj_type"); -create index "item_private" on item ("item_private"); create index "item_llink" on item ("llink"); create index "item_expires" on item ("expires"); create index "item_revision" on item ("revision"); @@ -659,30 +654,29 @@ create index "item_uid_mid" on item ("mid","uid"); create index "item_public_policy" on item ("public_policy"); create index "item_comment_policy" on item ("comment_policy"); create index "item_layout_mid" on item ("layout_mid"); -create index "item_unseen" on item ("item_unseen"); create index "item_wall" on item ("item_wall"); create index "item_origin" on item ("item_origin"); -create index "item_starred" on item ("item_starred"); create index "item_uplink" on item ("item_uplink"); create index "item_consensus" on item ("item_consensus"); -create index "item_thread_top" on item ("item_thread_top"); -create index "item_notshown" on item ("item_notshown"); create index "item_nsfw" on item ("item_nsfw"); -create index "item_relay" on item ("item_relay"); create index "item_mentionsme" on item ("item_mentionsme"); create index "item_nocomment" on item ("item_nocomment"); create index "item_obscured" on item ("item_obscured"); -create index "item_verified" on item ("item_verified"); -create index "item_retained" on item ("item_retained"); create index "item_rss" on item ("item_rss"); -create index "item_deleted" on item ("item_deleted"); -create index "item_type" on item ("item_type"); -create index "item_hidden" on item ("item_hidden"); -create index "item_unpublished" on item ("item_unpublished"); -create index "item_delayed" on item ("item_delayed"); -create index "item_pending_remove" on item ("item_pending_remove"); -create index "item_blocked" on item ("item_blocked"); +create index "item_thr_parent" on item ("thr_parent"); + +create index "item_uid_item_type" on item ("uid", "item_type"); +create index "item_uid_item_thread_top" on item ("uid", "item_thread_top"); +create index "item_uid_item_blocked" on item ("uid", "item_blocked"); +create index "item_uid_item_wall" on item ("uid", "item_wall"); +create index "item_uid_item_starred" on item ("uid", "item_starred"); +create index "item_uid_item_retained" on item ("uid", "item_retained"); +create index "item_uid_item_private" on item ("uid", "item_private"); +create index "item_uid_resource_type" on item ("uid", "resource_type"); +create index "item_item_deleted_item_pending_remove_changed" on item ("item_deleted", "item_pending_remove", "changed"); +create index "item_item_pending_remove_changed" on item ("item_pending_remove", "changed"); + -- fulltext indexes create index "item_search_idx" on item USING gist("item_search_vector"); create index "item_allow_cid" on item ("allow_cid"); diff --git a/util/service_class b/util/service_class index 50f01afff..b8a1f2386 100755 --- a/util/service_class +++ b/util/service_class @@ -93,7 +93,12 @@ if($argc == 1) { if(is_array(App::$config['service_class']) && App::$config['service_class']) { foreach(App::$config['service_class'] as $class=>$props) { echo "$class:\n"; - $d = unserialize($props); + + $d = ((! is_array($props)) && (preg_match('|^a:[0-9]+:{.*}$|s', $props)) + ? unserialize($props) + : $props + ); + if(is_array($d) && $d) { foreach($d as $k => $v) { echo "\t$k = $v\n"; diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index de9c63bdc..ba7b1d85c 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -882,6 +882,7 @@ return array( 'Zotlabs\\Lib\\Verify' => $baseDir . '/Zotlabs/Lib/Verify.php', 'Zotlabs\\Lib\\Webfinger' => $baseDir . '/Zotlabs/Lib/Webfinger.php', 'Zotlabs\\Lib\\XConfig' => $baseDir . '/Zotlabs/Lib/XConfig.php', + 'Zotlabs\\Lib\\ZotURL' => $baseDir . '/Zotlabs/Lib/ZotURL.php', 'Zotlabs\\Lib\\Zotfinger' => $baseDir . '/Zotlabs/Lib/Zotfinger.php', 'Zotlabs\\Module\\Achievements' => $baseDir . '/Zotlabs/Module/Achievements.php', 'Zotlabs\\Module\\Acl' => $baseDir . '/Zotlabs/Module/Acl.php', @@ -961,6 +962,7 @@ return array( 'Zotlabs\\Module\\Home' => $baseDir . '/Zotlabs/Module/Home.php', 'Zotlabs\\Module\\Hostxrd' => $baseDir . '/Zotlabs/Module/Hostxrd.php', 'Zotlabs\\Module\\Hq' => $baseDir . '/Zotlabs/Module/Hq.php', + 'Zotlabs\\Module\\Id' => $baseDir . '/Zotlabs/Module/Id.php', 'Zotlabs\\Module\\Impel' => $baseDir . '/Zotlabs/Module/Impel.php', 'Zotlabs\\Module\\Import' => $baseDir . '/Zotlabs/Module/Import.php', 'Zotlabs\\Module\\Import_items' => $baseDir . '/Zotlabs/Module/Import_items.php', @@ -1349,6 +1351,7 @@ return array( 'Zotlabs\\Update\\_1228' => $baseDir . '/Zotlabs/Update/_1228.php', 'Zotlabs\\Update\\_1229' => $baseDir . '/Zotlabs/Update/_1229.php', 'Zotlabs\\Update\\_1230' => $baseDir . '/Zotlabs/Update/_1230.php', + 'Zotlabs\\Update\\_1231' => $baseDir . '/Zotlabs/Update/_1231.php', 'Zotlabs\\Web\\Controller' => $baseDir . '/Zotlabs/Web/Controller.php', 'Zotlabs\\Web\\HTTPHeaders' => $baseDir . '/Zotlabs/Web/HTTPHeaders.php', 'Zotlabs\\Web\\HTTPSig' => $baseDir . '/Zotlabs/Web/HTTPSig.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index d4daa13e6..37a73de45 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -1050,6 +1050,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d 'Zotlabs\\Lib\\Verify' => __DIR__ . '/../..' . '/Zotlabs/Lib/Verify.php', 'Zotlabs\\Lib\\Webfinger' => __DIR__ . '/../..' . '/Zotlabs/Lib/Webfinger.php', 'Zotlabs\\Lib\\XConfig' => __DIR__ . '/../..' . '/Zotlabs/Lib/XConfig.php', + 'Zotlabs\\Lib\\ZotURL' => __DIR__ . '/../..' . '/Zotlabs/Lib/ZotURL.php', 'Zotlabs\\Lib\\Zotfinger' => __DIR__ . '/../..' . '/Zotlabs/Lib/Zotfinger.php', 'Zotlabs\\Module\\Achievements' => __DIR__ . '/../..' . '/Zotlabs/Module/Achievements.php', 'Zotlabs\\Module\\Acl' => __DIR__ . '/../..' . '/Zotlabs/Module/Acl.php', @@ -1129,6 +1130,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d 'Zotlabs\\Module\\Home' => __DIR__ . '/../..' . '/Zotlabs/Module/Home.php', 'Zotlabs\\Module\\Hostxrd' => __DIR__ . '/../..' . '/Zotlabs/Module/Hostxrd.php', 'Zotlabs\\Module\\Hq' => __DIR__ . '/../..' . '/Zotlabs/Module/Hq.php', + 'Zotlabs\\Module\\Id' => __DIR__ . '/../..' . '/Zotlabs/Module/Id.php', 'Zotlabs\\Module\\Impel' => __DIR__ . '/../..' . '/Zotlabs/Module/Impel.php', 'Zotlabs\\Module\\Import' => __DIR__ . '/../..' . '/Zotlabs/Module/Import.php', 'Zotlabs\\Module\\Import_items' => __DIR__ . '/../..' . '/Zotlabs/Module/Import_items.php', @@ -1517,6 +1519,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d 'Zotlabs\\Update\\_1228' => __DIR__ . '/../..' . '/Zotlabs/Update/_1228.php', 'Zotlabs\\Update\\_1229' => __DIR__ . '/../..' . '/Zotlabs/Update/_1229.php', 'Zotlabs\\Update\\_1230' => __DIR__ . '/../..' . '/Zotlabs/Update/_1230.php', + 'Zotlabs\\Update\\_1231' => __DIR__ . '/../..' . '/Zotlabs/Update/_1231.php', 'Zotlabs\\Web\\Controller' => __DIR__ . '/../..' . '/Zotlabs/Web/Controller.php', 'Zotlabs\\Web\\HTTPHeaders' => __DIR__ . '/../..' . '/Zotlabs/Web/HTTPHeaders.php', 'Zotlabs\\Web\\HTTPSig' => __DIR__ . '/../..' . '/Zotlabs/Web/HTTPSig.php', diff --git a/view/tpl/dreport.tpl b/view/tpl/dreport.tpl index 1f5915609..89188891d 100644 --- a/view/tpl/dreport.tpl +++ b/view/tpl/dreport.tpl @@ -3,11 +3,11 @@ {{if $table == 'item'}} {{/if}}

{{$title}}