diff --git a/Zotlabs/Daemon/Content_importer.php b/Zotlabs/Daemon/Content_importer.php index 592a538ed..adc180a2c 100644 --- a/Zotlabs/Daemon/Content_importer.php +++ b/Zotlabs/Daemon/Content_importer.php @@ -29,14 +29,14 @@ class Content_importer { $headers = [ 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , + 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , + '(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , ]; $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]); if(! $x['success']) { logger('no API response',LOGGER_DEBUG); diff --git a/Zotlabs/Daemon/File_importer.php b/Zotlabs/Daemon/File_importer.php index 8153dd3cc..f3fe785bb 100644 --- a/Zotlabs/Daemon/File_importer.php +++ b/Zotlabs/Daemon/File_importer.php @@ -28,13 +28,13 @@ class File_importer { $headers = [ 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/file/export?f=&file_id=' . $attach_id, + 'X-API-Request' => $hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id, 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/file/export?f=&file_id=' . $attach_id, + '(request-target)' => 'get /api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id, ]; $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/file/export?f=&file_id=' . $attach_id,false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id,false,$redirects,[ 'headers' => $headers ]); if(! $x['success']) { logger('no API response',LOGGER_DEBUG); diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 6963b9911..0151d8d5c 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -93,7 +93,7 @@ class Activity { } $headers = [ - 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Accept' => 'application/activity+json, application/x-zot-activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'Host' => $m['host'], 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), '(request-target)' => 'get ' . get_request_string($url) @@ -1281,6 +1281,9 @@ class Activity { 'width' => 300, ]; $ret['url'] = $p['xchan_url']; + if ($p['channel_location']) { + $ret['location'] = [ 'type' => 'Place', 'name' => $p['channel_location'] ]; + } if ($activitypub && get_config('system','activitypub', ACTIVITYPUB_ENABLED)) { @@ -2428,6 +2431,20 @@ class Activity { $s['app'] = escape_tags($generator['name']); } + $location = $act->get_property_obj('location'); + if (is_array($location) && array_key_exists('type',$location) && $location['type'] === 'Place') { + if (array_key_exists('name',$location)) { + $s['location'] = escape_tags($location['name']); + } + if (array_key_exists('content',$location)) { + $s['location'] = html2plain(html2plain(purify_html($location['content']),256)); + } + + if (array_key_exists('latitude',$location) && array_key_exists('longitude',$location)) { + $s['coord'] = escape_tags($location['latitude']) . ' ' . escape_tags($location['longitude']); + } + } + if (! $response_activity) { $a = self::decode_taxonomy($act->obj); if ($a) { diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 6931aa46a..b92b49ce7 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -463,7 +463,8 @@ class ActivityStreams { $x = getBestSupportedMimeType([ 'application/ld+json;profile="https://www.w3.org/ns/activitystreams"', 'application/activity+json', - 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"' + 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"', + 'application/x-zot-activity+json' ]); return(($x) ? true : false); diff --git a/Zotlabs/Lib/MastAPI.php b/Zotlabs/Lib/MastAPI.php index 105925c27..b87955e68 100644 --- a/Zotlabs/Lib/MastAPI.php +++ b/Zotlabs/Lib/MastAPI.php @@ -79,7 +79,7 @@ class MastAPI { $ret = []; - $ret['uri'] = App::get_hostname(); + $ret['uri'] = z_root(); $ret['title'] = System::get_site_name(); $ret['description'] = bbcode(get_config('system','siteinfo'), [ 'export' => true ] ); $ret['email'] = get_config('system','admin_email'); diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php index fcbb87a89..7f7f268c7 100644 --- a/Zotlabs/Module/Activity.php +++ b/Zotlabs/Module/Activity.php @@ -14,6 +14,93 @@ class Activity extends Controller { function init() { + + 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); + + if ($portable_id && (! intval($items[0]['item_private']))) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($items[0]['uid']), + dbesc($portable_id) + ); + if (! $c) { + ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id); + } + } + + $channel = channelx_by_n($items[0]['uid']); + + as_return_and_die(ZlibActivity::encode_activity($items[0],true),$channel); + + } + if (Libzot::is_zot_request()) { $item_id = argv(1); @@ -171,92 +258,8 @@ class Activity extends Controller { killme(); } - - 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); - - if ($portable_id && (! intval($items[0]['item_private']))) { - $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", - intval($items[0]['uid']), - dbesc($portable_id) - ); - if (! $c) { - ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id); - } - } - - $channel = channelx_by_n($items[0]['uid']); - - as_return_and_die(ZlibActivity::encode_activity($items[0],true),$channel); - - } goaway(z_root() . '/item/' . argv(1)); } diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 7715d3c98..b0852365a 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -75,36 +75,6 @@ class Channel extends Controller { ]); - // handle zot6 channel discovery - - if(Libzot::is_zot_request()) { - - $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); - - if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer'] ])); - $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($sigdata['signer']) - ); - - if($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { - $data = json_encode(Crypto::encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto']))); - } - } - else { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'] ])); - } - - $headers = [ - 'Content-Type' => 'application/x-zot+json', - 'Digest' => HTTPSig::generate_digest_header($data), - '(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 $data; - killme(); - } // An ActivityStreams actor record is more or less required for ActivityStreams compliance // unless the actor object is inlined into every activity/object. This implies that it @@ -151,6 +121,38 @@ class Channel extends Controller { as_return_and_die(Activity::encode_person($channel,true,true),$channel); } + // handle zot6 channel discovery + + if(Libzot::is_zot_request()) { + + $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); + + if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { + $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer'] ])); + $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($sigdata['signer']) + ); + + if($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { + $data = json_encode(Crypto::encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto']))); + } + } + else { + $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'] ])); + } + + $headers = [ + 'Content-Type' => 'application/x-zot+json', + 'Digest' => HTTPSig::generate_digest_header($data), + '(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 $data; + killme(); + } + + // Run Libprofile::load() here to make sure the theme is set before // we start loading content diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index 35bf66aa7..a78616493 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -89,7 +89,7 @@ class Import extends Controller { return; } - $api_path .= 'channel/export/basic?f=&channel=' . $channelname; + $api_path .= 'channel/export/basic?f=&zap_compat=1&channel=' . $channelname; if ($import_posts) { $api_path .= '&posts=1'; } @@ -498,27 +498,27 @@ class Import extends Controller { if (is_array($data['chatroom'])) { import_chatrooms($channel,$data['chatroom']); } - if (is_array($data['conv'])) { - import_conv($channel,$data['conv']); - } - if (is_array($data['mail'])) { - import_mail($channel,$data['mail']); - } +// if (is_array($data['conv'])) { +// import_conv($channel,$data['conv']); +// } +// if (is_array($data['mail'])) { +// import_mail($channel,$data['mail']); +// } if (is_array($data['event'])) { import_events($channel,$data['event']); } if (is_array($data['event_item'])) { import_items($channel,$data['event_item'],false,$relocate); } - if (is_array($data['menu'])) { - import_menus($channel,$data['menu']); - } - if (is_array($data['wiki'])) { - import_items($channel,$data['wiki'],false,$relocate); - } - if (is_array($data['webpages'])) { - import_items($channel,$data['webpages'],false,$relocate); - } +// if (is_array($data['menu'])) { +// import_menus($channel,$data['menu']); +// } +// if (is_array($data['wiki'])) { +// import_items($channel,$data['wiki'],false,$relocate); +// } +// if (is_array($data['webpages'])) { +// import_items($channel,$data['webpages'],false,$relocate); +// } $addon = array('channel' => $channel,'data' => $data); call_hooks('import_channel',$addon); @@ -542,14 +542,14 @@ class Import extends Controller { while (1) { $headers = [ 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , + 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , + '(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , ]; $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]); // logger('z_fetch: ' . print_r($x,true)); @@ -577,14 +577,14 @@ class Import extends Controller { $headers = [ 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/files?f=&since=' . urlencode($since) . '&until=' . urlencode($until), + 'X-API-Request' => $hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/files?f=&since=' . urlencode($since) . '&until=' . urlencode($until), + '(request-target)' => 'get /api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), ]; $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/files?f=&since=' . urlencode($since) . '&until=' . urlencode($until),false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until),false,$redirects,[ 'headers' => $headers ]); if (! $x['success']) { logger('no API response'); diff --git a/Zotlabs/Module/Import_items.php b/Zotlabs/Module/Import_items.php index cf12bc3d7..225e3d6c6 100644 --- a/Zotlabs/Module/Import_items.php +++ b/Zotlabs/Module/Import_items.php @@ -58,7 +58,7 @@ class Import_items extends \Zotlabs\Web\Controller { $servername = substr($old_address,strpos($old_address,'@')+1); $scheme = 'https://'; - $api_path = '/api/red/channel/export/items?f=&channel=' . $channelname . '&year=' . intval($year); + $api_path = '/api/red/channel/export/items?f=&zap_compat=1&channel=' . $channelname . '&year=' . intval($year); $binary = false; $redirects = 0; $opts = array('http_auth' => $email . ':' . $password); @@ -86,13 +86,20 @@ class Import_items extends \Zotlabs\Web\Controller { if(! is_array($data)) return; - if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { - $v1 = substr($data['compatibility']['database'],-4); - $v2 = substr(DB_UPDATE_VERSION,-4); - if($v2 > $v1) { - $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); - notice($t . EOL); - } +// if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { +// $v1 = substr($data['compatibility']['database'],-4); +// $v2 = substr(DB_UPDATE_VERSION,-4); +// if($v2 > $v1) { +// $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); +// notice($t . EOL); +// } +// } + + $codebase = 'zap'; + + if ((! array_path_exists('compatibility/codebase',$data)) || $data['compatibility']['codebase'] !== $codebase) { + notice(t('Data export format is not compatible with this software')); + return; } $channel = \App::get_channel(); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 9bdda13f7..29417ac3d 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -50,6 +50,101 @@ class Item extends Controller { function init() { + 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'); + } + + if ($portable_id && (! intval($items[0]['item_private']))) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($items[0]['uid']), + dbesc($portable_id) + ); + if (! $c) { + ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id); + } + } + + as_return_and_die($i,$chan); + } + if(Libzot::is_zot_request()) { $conversation = false; @@ -166,102 +261,6 @@ 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'); - } - - if ($portable_id && (! intval($items[0]['item_private']))) { - $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", - intval($items[0]['uid']), - dbesc($portable_id) - ); - if (! $c) { - ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id); - } - } - - as_return_and_die($i,$chan); - } - - // if it isn't a drop command and isn't a post method and wasn't handled already, // the default action is a browser request for a persistent uri and this should return // the text/html page of the item. diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php index 31e648d60..70e0898f4 100644 --- a/Zotlabs/Module/Settings/Display.php +++ b/Zotlabs/Module/Settings/Display.php @@ -154,7 +154,7 @@ class Display { } - $preload_images = get_pconfig(local_channel(),'system','preload_images', '1'); + $preload_images = get_pconfig(local_channel(),'system','preload_images'); $user_scalable = get_pconfig(local_channel(),'system','user_scalable', '0'); diff --git a/boot.php b/boot.php index 335329642..f16402528 100755 --- a/boot.php +++ b/boot.php @@ -16,7 +16,7 @@ use Zotlabs\Daemon\Run; * @brief This file defines some global constants and includes the central App class. */ -define ( 'STD_VERSION', '21.02.15' ); +define ( 'STD_VERSION', '21.02.22' ); define ( 'ZOT_REVISION', '6.0' ); define ( 'DB_UPDATE_VERSION', 1247 ); @@ -692,8 +692,8 @@ function startup() { @set_time_limit(0); if (function_exists ('ini_set')) { - // This has to be quite large to deal with embedded private photos - @ini_set('pcre.backtrack_limit', 500000); + // This has to be quite large + @ini_set('pcre.backtrack_limit', 5000000); // Use cookies to store the session ID on the client side @ini_set('session.use_only_cookies', 1); diff --git a/include/bbcode.php b/include/bbcode.php index c05fc4924..5205191d4 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -269,6 +269,9 @@ function bb_parse_crypt($match) { if ($matches[1] != "") $hint = $matches[1]; preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches); + if ($matches[1] != "") + $hint = $matches[1]; + preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches); if ($matches[1] != "") $hint = $matches[1]; @@ -284,6 +287,25 @@ function bb_parse_crypt($match) { return $Text; } +/** + * @brief Returns raw base64 encoded crypt content. + * + * @param array $match + * @return string + */ +function bb_parse_b64_crypt($match) { + + if(empty($match[2])) + return; + + $r .= '----- ENCRYPTED CONTENT -----' . PHP_EOL; + $r .= $match[2] . PHP_EOL; + $r .= '----- END ENCRYPTED CONTENT -----'; + + return $r; + +} + function bb_parse_app($match) { $app = Apps::app_decode($match[1]); @@ -1534,8 +1556,10 @@ function bbcode($Text, $options = []) { $Text = preg_replace("/([^\]\='".'"'."\;\/])(https?\:\/\/$urlchars+)/ismu", '$1$2', $Text); } - if (strpos($Text,'[/share]') !== false) { + $count = 0; + while (strpos($Text,'[/share]') !== false && $count < 10) { $Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", 'bb_ShareAttributes', $Text); + $count ++; } if (strpos($Text,'[/url]') !== false) { @@ -1848,7 +1872,10 @@ function bbcode($Text, $options = []) { // crypt if (strpos($Text,'[/crypt]') !== false) { - if (! $activitypub) { + if ($activitypub) { + $Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_b64_crypt', $Text); + } + else { $Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text); } } diff --git a/include/channel.php b/include/channel.php index 1b70e8925..c1f67cae5 100644 --- a/include/channel.php +++ b/include/channel.php @@ -1124,6 +1124,8 @@ function channel_export_items_date($channel_id, $start, $finish) { $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()]; } + $ret['compatibility']['codebase'] = 'zap'; + $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and created >= '%s' and created <= '%s' and resource_type = '' order by created", intval(ITEM_TYPE_POST), intval($channel_id), @@ -1190,6 +1192,9 @@ function channel_export_items_page($channel_id, $start, $finish, $page = 0, $lim $ret['relocate'] = [ 'channel_address' => $ch['channel_address'], 'url' => z_root()]; } + $ret['compatibility']['codebase'] = 'zap'; + + $r = q("select * from item where ( item_wall = 1 or item_type != %d ) and item_deleted = 0 and uid = %d and resource_type = '' and created >= '%s' and created <= '%s' order by created limit %d offset %d", intval(ITEM_TYPE_POST), intval($channel_id), diff --git a/include/connections.php b/include/connections.php index dc5182a17..ca5f3d0f4 100644 --- a/include/connections.php +++ b/include/connections.php @@ -233,6 +233,8 @@ function abook_toggle_flag($abook,$flag) { function mark_orphan_hubsxchans() { + return; + $dirmode = intval(get_config('system','directory_mode')); if ($dirmode == DIRECTORY_MODE_NORMAL) { return; diff --git a/include/import.php b/include/import.php index 60bac841a..f4d5a01f0 100644 --- a/include/import.php +++ b/include/import.php @@ -169,6 +169,23 @@ function import_config($channel, $configs) { } load_pconfig($channel['channel_id']); + $permissions_role = get_pconfig($channel['channel_id'],'system','permissions_role'); + if ($permissions_role === 'social_federation') { + // Convert Hubzilla's social_federation role to 'social' with relaxed comment permissions + set_pconfig($channel['channel_id'],'systems','permissions_role','social'); + PermissionLimits::Set($channel['channel_id'],'post_comments', PERMS_AUTHED); + } + else { + // If the requested permissions_role doesn't exist on this system, + // convert it to 'social' + + $role_permissions = PermissionRoles::role_perms($permissions_role); + + if (! $role_permissions) { + set_pconfig($channel['channel_id'],'system','permissions_role','social'); + } + } + } } @@ -1440,8 +1457,14 @@ function sync_files($channel, $files) { continue; } + $columns = db_columns('attach'); + $str = ''; foreach ($att as $k => $v) { + if (! in_array($k,$columns)) { + continue; + } + if ($str) { $str .= ","; } diff --git a/include/items.php b/include/items.php index d0286844e..c1d619399 100644 --- a/include/items.php +++ b/include/items.php @@ -2985,27 +2985,22 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $arr['item_wall'] = 1; $arr['item_thread_top'] = 1; - if (strpos($item['body'], "[/share]") !== false) { - $pos = strpos($item['body'], "[share"); - $bb = substr($item['body'], $pos); - } - else { - $bb = "[share author='" . urlencode($item['author']['xchan_name']). - "' profile='" . $item['author']['xchan_url'] . - "' portable_id='" . $item['author']['xchan_hash'] . - "' avatar='" . $item['author']['xchan_photo_s'] . - "' link='" . $item['plink'] . - "' auth='" . (($item['author']['network'] === 'zot6') ? 'true' : 'false') . - "' posted='" . $item['created'] . - "' message_id='" . $item['mid'] . - "']"; - if($item['title']) - $bb .= '[b]'.$item['title'].'[/b]'."\r\n"; - $bb .= $item['body']; - $bb .= "[/share]"; + $bb = "[share author='" . urlencode($item['author']['xchan_name']). + "' profile='" . $item['author']['xchan_url'] . + "' portable_id='" . $item['author']['xchan_hash'] . + "' avatar='" . $item['author']['xchan_photo_s'] . + "' link='" . $item['plink'] . + "' auth='" . (($item['author']['network'] === 'zot6') ? 'true' : 'false') . + "' posted='" . $item['created'] . + "' message_id='" . $item['mid'] . + "']"; + if($item['title']) { + $bb .= '[b]' . $item['title'] . '[/b]' . "\r\n"; + $arr['title'] = $item['title']; } + $bb .= $item['body']; + $bb .= "[/share]"; -// $mention = '@[zrl=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/zrl]'; $arr['body'] = $bb; $arr['term'] = $item['term'];