From 255b6a14a8d993a086dc790e8c4dbe64ce6e3e48 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 8 Nov 2020 12:55:32 +0000 Subject: less hubloc confusion --- Zotlabs/Lib/JSalmon.php | 2 +- Zotlabs/Lib/Zotfinger.php | 7 +++-- Zotlabs/Module/Channel.php | 2 +- Zotlabs/Module/Connedit.php | 15 ++-------- Zotlabs/Module/Zot_probe.php | 2 +- Zotlabs/Web/HTTPSig.php | 66 ++++++++++++++++++++++++++++++-------------- Zotlabs/Zot6/Receiver.php | 2 +- 7 files changed, 56 insertions(+), 40 deletions(-) diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php index 67512046f..48a4e649b 100644 --- a/Zotlabs/Lib/JSalmon.php +++ b/Zotlabs/Lib/JSalmon.php @@ -51,7 +51,7 @@ class JSalmon { . base64url_encode($x['encoding'],true) . '.' . base64url_encode($x['alg'],true); - $key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id'])); + $key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id'])); logger('key: ' . print_r($key,true)); if($key['portable_id'] && $key['public_key']) { if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) { diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php index 722e34dfc..e853d6ebc 100644 --- a/Zotlabs/Lib/Zotfinger.php +++ b/Zotlabs/Lib/Zotfinger.php @@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig; class Zotfinger { - static function exec($resource,$channel = null) { + static function exec($resource,$channel = null, $verify = true) { if(! $resource) { return false; @@ -41,8 +41,9 @@ class Zotfinger { logger('fetch: ' . print_r($x,true)); if($x['success']) { - - $result['signature'] = HTTPSig::verify($x); + if ($verify) { + $result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6'); + } $result['data'] = json_decode($x['body'],true); diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 307be048a..dc8e9e1c5 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -60,7 +60,7 @@ class Channel extends Controller { if(Libzot::is_zot_request()) { - $sigdata = HTTPSig::verify(file_get_contents('php://input')); + $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ])); diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 0fc807d42..becf8460d 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -294,8 +294,8 @@ class Connedit extends Controller { intval($channel['channel_id']) ); if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) { - $xarr = array(); - $xarr['verb'] = ACTIVITY_FRIEND; + $xarr = []; + $xarr['item_wall'] = 1; $xarr['item_origin'] = 1; $xarr['item_thread_top'] = 1; @@ -305,17 +305,6 @@ class Connedit extends Controller { $xarr['deny_cid'] = $channel['channel_deny_cid']; $xarr['deny_gid'] = $channel['channel_deny_gid']; $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); - $obj = array( - 'type' => ACTIVITY_OBJ_PERSON, - 'title' => App::$poi['xchan_name'], - 'id' => App::$poi['xchan_hash'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => App::$poi['xchan_url']), - array('rel' => 'photo', 'type' => App::$poi['xchan_photo_mimetype'], 'href' => App::$poi['xchan_photo_l']) - ), - ); - $xarr['obj'] = json_encode($obj); - $xarr['obj_type'] = ACTIVITY_OBJ_PERSON; $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; diff --git a/Zotlabs/Module/Zot_probe.php b/Zotlabs/Module/Zot_probe.php index 648ed2175..7585affdf 100644 --- a/Zotlabs/Module/Zot_probe.php +++ b/Zotlabs/Module/Zot_probe.php @@ -34,7 +34,7 @@ class Zot_probe extends \Zotlabs\Web\Controller { $o .= '
' . htmlspecialchars($x['header']) . '
' . EOL; - $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x),true)) . EOL; + $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x, EMPTY_STR, 'zot6'),true)) . EOL; $o .= '
' . htmlspecialchars(json_encode(json_decode($x['body']),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '
' . EOL; diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index 827e0d779..42426afb1 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -76,7 +76,7 @@ class HTTPSig { // See draft-cavage-http-signatures-10 - static function verify($data,$key = '') { + static function verify($data,$key = '', $keytype = '') { $body = $data; $headers = null; @@ -151,7 +151,7 @@ class HTTPSig { $result['signer'] = $sig_block['keyId']; - $key = self::get_key($key,$result['signer']); + $key = self::get_key($key,$keytype,$result['signer']); if(! ($key && $key['public_key'])) { return $result; @@ -162,13 +162,26 @@ class HTTPSig { logger('verified: ' . $x, LOGGER_DEBUG); if(! $x) { - logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key')); - $sig_block['signature'] = base64_encode($sig_block['signature']); - logger('affected sigblock: ' . print_r($sig_block,true)); - logger('signed_data: ' . print_r($signed_data,true)); - logger('headers: ' . print_r($headers,true)); - logger('server: ' . print_r($_SERVER,true)); - return $result; + + // try again, ignoring the local actor (xchan) cache and refetching the key + // from its source + + $fkey = self::get_key($key,$keytype,$result['signer'],true); + + if ($fkey && $fkey['public_key']) { + $y = rsa_verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm); + logger('verified: (cache reload) ' . $x, LOGGER_DEBUG); + } + + if (! $y) { + logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key')); + $sig_block['signature'] = base64_encode($sig_block['signature']); + logger('affected sigblock: ' . print_r($sig_block,true)); + logger('headers: ' . print_r($headers,true)); + logger('server: ' . print_r($_SERVER,true)); + return $result; + } + } $result['portable_id'] = $key['portable_id']; @@ -187,12 +200,17 @@ class HTTPSig { } logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false')); + if (! $result['content_valid']) { + logger('invalid content signature: data ' . print_r($data,true)); + logger('invalid content signature: headers ' . print_r($headers,true)); + logger('invalid content signature: body ' . print_r($body,true)); + } } return $result; } - static function get_key($key,$id) { + static function get_key($key,$keytype,$id) { if($key) { if(function_exists($key)) { @@ -201,6 +219,13 @@ class HTTPSig { return [ 'public_key' => $key ]; } + if($keytype === 'zot6') { + $key = self::get_zotfinger_key($id,$force); + if($key) { + return $key; + } + } + if(strpos($id,'#') === false) { $key = self::get_webfinger_key($id); } @@ -243,7 +268,7 @@ class HTTPSig { $url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id); - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network in ('zot6', 'activitypub')", dbesc(str_replace('acct:','',$url)), dbesc($url) ); @@ -303,18 +328,15 @@ class HTTPSig { return (($key['public_key']) ? $key : false); } - function get_zotfinger_key($id) { - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s'", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' and hubloc_network = 'zot6'", dbesc(str_replace('acct:','',$id)), dbesc($id) ); - $x = Libzot::zot_record_preferred($x); - - if($x && $x['xchan_pubkey']) { - return [ 'portable_id' => $x['xchan_hash'], 'public_key' => $x['xchan_pubkey'] , 'hubloc' => $x ]; + if($x && $x[0]['xchan_pubkey']) { + return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ]; } $wf = Webfinger::exec($id); @@ -330,13 +352,18 @@ class HTTPSig { continue; } if($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) { - $z = \Zotlabs\Lib\Zotfinger::exec($l['href']); + + // The third argument to Zotfinger::exec() tells it not to verify signatures + // Since we're inside a function that is fetching keys with which to verify signatures, + // this is necessary to prevent infinite loops. + + $z = \Zotlabs\Lib\Zotfinger::exec($l['href'],null,false); if($z) { $i = Libzot::import_xchan($z['data']); if($i['success']) { $key['portable_id'] = $i['hash']; - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' and hubloc_network = 'zot6'", dbesc($l['href']) ); if($x) { @@ -485,7 +512,6 @@ class HTTPSig { if(preg_match('/iv="(.*?)"/ism',$header,$matches)) $header = self::decrypt_sigheader($header); - if(preg_match('/keyId="(.*?)"/ism',$header,$matches)) $ret['keyId'] = $matches[1]; if(preg_match('/algorithm="(.*?)"/ism',$header,$matches)) diff --git a/Zotlabs/Zot6/Receiver.php b/Zotlabs/Zot6/Receiver.php index 9e70ab318..a9a7ab0df 100644 --- a/Zotlabs/Zot6/Receiver.php +++ b/Zotlabs/Zot6/Receiver.php @@ -155,7 +155,7 @@ class Receiver { $result = false; - $this->sigdata = HTTPSig::verify($this->rawdata); + $this->sigdata = HTTPSig::verify($this->rawdata, EMPTY_STR, 'zot6'); if ($this->sigdata && $this->sigdata['header_signed'] && $this->sigdata['header_valid']) { $result = true; -- cgit v1.2.3 From b3e6a3c1e2cb086788f41252e872d6a131fcca90 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 8 Nov 2020 19:07:44 +0000 Subject: =?UTF-8?q?make=20share=20titles=20h3=20to=20reflect=20the=20origi?= =?UTF-8?q?nal=20titl=C3=83e=20size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zotlabs/Lib/Share.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php index 419e6ed5f..d34c0eaba 100644 --- a/Zotlabs/Lib/Share.php +++ b/Zotlabs/Lib/Share.php @@ -133,7 +133,7 @@ class Share { "' message_id='" . $this->item['mid'] . "']"; if($this->item['title']) - $bb .= '[b]'.$this->item['title'].'[/b]'."\r\n"; + $bb .= '[h3][b]'.$this->item['title'].'[/b][/h3]'."\r\n"; $bb .= (($is_photo) ? $photo_bb . "\r\n" . $this->item['body'] : $this->item['body']); $bb .= "[/share]"; } -- cgit v1.2.3 From cddae143529f3acb9586ce3517d356925e819055 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 9 Nov 2020 11:31:20 +0000 Subject: do not log exception - it could exhaust memory --- Zotlabs/Lib/LDSignatures.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index 16c8cfc18..2eba66ccf 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -93,7 +93,8 @@ class LDSignatures { $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); } catch (\Exception $e) { - logger('normalise error:' . print_r($e,true)); + // Don't log the exception - this can exhaust memory + // logger('normalise error:' . print_r($e,true)); logger('normalise error: ' . print_r($data,true)); } -- cgit v1.2.3 From 890290fff019f691221a530b0cff01f291b38044 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 11 Nov 2020 12:10:35 +0000 Subject: log the body if fetch failed --- Zotlabs/Lib/Activity.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index e7fa6352a..48714a48d 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -104,6 +104,7 @@ class Activity { } else { logger('fetch failed: ' . $url); + logger($x['body']); } return null; } -- cgit v1.2.3 From c879e5de44d8a29fb3d3aa0902f44a85add8ef99 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 12 Nov 2020 08:57:51 +0000 Subject: changelog and version bump --- CHANGELOG | 10 ++++++++++ boot.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 0c8498488..6a6292da3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +Hubzilla 5.0.1 (2020-11-12) + - Fix share title size + - Fix issue where hublocs could get mixed up between different protocols + + Addons + - Pubcrawl: implement authenticated profile fetches which are now partly required in mastodon + - Sse: call xchan_query() just once per item + - Pubcrawl: reject messages where sender is not the author if ld-signature is not ok + + Hubzilla 5.0 (2020-11-05) - Remove unmaintained and deprecated schemas - Deprecate HTML5_Parser library diff --git a/boot.php b/boot.php index 9045fe9f4..385a34891 100755 --- a/boot.php +++ b/boot.php @@ -50,7 +50,7 @@ require_once('include/attach.php'); require_once('include/bbcode.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '5.1.2' ); +define ( 'STD_VERSION', '5.1.3' ); define ( 'ZOT_REVISION', '6.0' ); define ( 'DB_UPDATE_VERSION', 1238 ); -- cgit v1.2.3