aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/feedutils.php139
-rwxr-xr-xinclude/items.php32
-rw-r--r--include/network.php13
3 files changed, 120 insertions, 64 deletions
diff --git a/include/feedutils.php b/include/feedutils.php
index d1985649d..477685f9a 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -254,81 +254,124 @@ function get_atom_elements($feed, $item, &$author) {
else
$base_url = '';
- // look for a photo. We should check media size and find the best one,
- // but for now let's just find any author photo
- $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+ $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
- if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
- $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- foreach($base as $link) {
- if(!x($author, 'author_photo') || ! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
+ // select between supported verbs
+
+ if($rawverb) {
+ $res['verb'] = unxmlify($rawverb[0]['data']);
}
- $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
+ // translate OStatus unfollow to activity streams if it happened to get selected
+
+ if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
+ $res['verb'] = ACTIVITY_UNFOLLOW;
- if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
- $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- if($base && count($base)) {
- foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
- $author['author_link'] = unxmlify($link['attribs']['']['href']);
- if(!x($author, 'author_photo') || ! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
- }
- // check for a yahoo media element (github etc.)
- if(! $author['author_photo']) {
- $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail');
- if($rawmedia && $rawmedia[0]['attribs']['']['url']) {
- $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
+ if(array_key_exists('verb',$res) && $res['verb'] === ACTIVITY_SHARE) {
+ // For Mastodon shares ("boosts"), we need to parse the original author information
+ // from the activity:object -> author structure
+ $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
+
+ if($rawobj) {
+ $rawauthor = $rawobj->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name']) {
+ $author['author_name'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name']);
+ }
+
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri']) {
+ $author['author_link'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri']);
+ }
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ foreach($base as $link) {
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
}
}
+ else {
+ // look for a photo. We should check media size and find the best one,
+ // but for now let's just find any author photo
+ $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
- // No photo/profile-link on the item - look at the feed level
-
- if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
- $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
$base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) {
- $author['author_link'] = unxmlify($link['attribs']['']['href']);
- $author['author_is_feed'] = true;
- }
- if(! $author['author_photo']) {
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
- $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
+ $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
$base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
-
if($base && count($base)) {
foreach($base as $link) {
if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
$author['author_link'] = unxmlify($link['attribs']['']['href']);
- if(! (x($author,'author_photo'))) {
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
}
+
+ // check for a yahoo media element (github etc.)
+
+ if(! $author['author_photo']) {
+ $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail');
+ if($rawmedia && $rawmedia[0]['attribs']['']['url']) {
+ $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
+ }
+ }
+
+
+ // No photo/profile-link on the item - look at the feed level
+
+ if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
+ $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ foreach($base as $link) {
+ if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) {
+ $author['author_link'] = unxmlify($link['attribs']['']['href']);
+ $author['author_is_feed'] = true;
+ }
+ if(! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+
+ $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
+
+ if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
+ $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+
+ if($base && count($base)) {
+ foreach($base as $link) {
+ if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
+ $author['author_link'] = unxmlify($link['attribs']['']['href']);
+ if(! (x($author,'author_photo'))) {
+ if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+ }
+ }
}
$ostatus_protocol = (($item->get_item_tags(NAMESPACE_OSTATUS,'conversation')) ? true : false);
@@ -492,18 +535,6 @@ function get_atom_elements($feed, $item, &$author) {
$res['coord'] = unxmlify($rawgeo[0]['data']);
- $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
-
- // select between supported verbs
-
- if($rawverb) {
- $res['verb'] = unxmlify($rawverb[0]['data']);
- }
-
- // translate OStatus unfollow to activity streams if it happened to get selected
-
- if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
- $res['verb'] = ACTIVITY_UNFOLLOW;
$cats = $item->get_categories();
if($cats) {
diff --git a/include/items.php b/include/items.php
index 933b9ef81..2e46ee3bd 100755
--- a/include/items.php
+++ b/include/items.php
@@ -632,14 +632,17 @@ function get_item_elements($x,$allow_code = false) {
return array();
// save a potentially expensive lookup if author == owner
+
if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']))
$arr['owner_xchan'] = $arr['author_xchan'];
else {
$xchan_hash = import_author_xchan($x['owner']);
- if($xchan_hash)
+ if($xchan_hash) {
$arr['owner_xchan'] = $xchan_hash;
- else
+ }
+ else {
return array();
+ }
}
// Check signature on the body text received.
@@ -656,10 +659,25 @@ function get_item_elements($x,$allow_code = false) {
$r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
- if($r && rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey']))
- $arr['item_verified'] = 1;
- else
- logger('get_item_elements: message verification failed.');
+ if($r) {
+ if($r[0]['xchan_pubkey']) {
+ if(rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) {
+ $arr['item_verified'] = 1;
+ }
+ else {
+ logger('get_item_elements: message verification failed.');
+ }
+ }
+ else {
+
+ // If we don't have a public key, strip the signature so it won't show as invalid.
+ // This won't happen in normal use, but could happen if import_author_xchan()
+ // failed to load the zot-info packet due to a server failure and had
+ // to create an alternate xchan with network 'unknown'
+
+ unset($arr['sig']);
+ }
+ }
}
// if the input is markdown, remove one level of html escaping.
@@ -1123,7 +1141,7 @@ function encode_item_xchan($xchan) {
$ret['address'] = $xchan['xchan_addr'];
$ret['url'] = $xchan['xchan_url'];
$ret['network'] = $xchan['xchan_network'];
- $ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']);
+ $ret['photo'] = [ 'mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m'] ];
$ret['guid'] = $xchan['xchan_guid'];
$ret['guid_sig'] = $xchan['xchan_guid_sig'];
diff --git a/include/network.php b/include/network.php
index 6d1a05e9f..d72f3f4fd 100644
--- a/include/network.php
+++ b/include/network.php
@@ -22,7 +22,6 @@ function get_capath() {
* @param int $redirects default 0
* internal use, recursion counter
* @param array $opts (optional parameters) associative array with:
- * * \b accept_content => supply Accept: header with 'accept_content' as the value
* * \b timeout => int seconds, default system config value or 60 seconds
* * \b headers => array of additional header fields
* * \b http_auth => username:password
@@ -202,7 +201,6 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
* @param int $redirects = 0
* internal use, recursion counter
* @param array $opts (optional parameters)
- * 'accept_content' => supply Accept: header with 'accept_content' as the value
* 'timeout' => int seconds, default system config value or 60 seconds
* 'http_auth' => username:password
* 'novalidate' => do not validate SSL certs, default is to validate using our CA list
@@ -1543,7 +1541,16 @@ function webfinger_rfc7033($webbie,$zot = false) {
}
logger('fetching url from resource: ' . $rhs . ':' . $webbie);
- $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''));
+ // The default curl Accept: header is */*, which is incorrectly handled by Mastodon servers
+ // and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML
+ // document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json,
+ // but some test webfinger servers may not explicitly set the content type and they would be
+ // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is
+ // accomplished by setting it to nothing.
+
+ $counter = 0;
+ $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''),
+ false, $counter, [ 'headers' => [ 'Accept:' ] ]);
if($s['success']) {
$j = json_decode($s['body'],true);