From 0350b76d851977ccd6eed4278738346f0febbf96 Mon Sep 17 00:00:00 2001 From: friendica Date: Sat, 13 Sep 2014 16:00:09 -0700 Subject: some backend work for the remaining missing bits of mod_hubman - this is still a fair ways from being complete and is not ready for prime time. Basically we'll let a channel send out a public message saying "these are my currently approved locations" and anything that isn't in the list will be marked deleted. We'll send out this message when locations change somehow - either through direct personal involvement (hub revoke, change primary, channel import) or during a system rename or "find bad/obsolete hublocs" activity. This way we won't have clones sending back location info we just got rid of and re-importing the bad entries. --- include/hubloc.php | 56 ++++++++++++++- include/zot.php | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++- mod/post.php | 4 +- version.inc | 2 +- 4 files changed, 258 insertions(+), 6 deletions(-) diff --git a/include/hubloc.php b/include/hubloc.php index 566875ce9..d51e38eae 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -42,4 +42,58 @@ function prune_hub_reinstalls() { } } } -} \ No newline at end of file +} + +function remove_obsolete_hublocs() { + + // Get rid of any hublocs which are ours but aren't valid anymore - + // e.g. they point to a different and perhaps transient URL that we aren't using. + + // I need to stress that this shouldn't happen. fix_system_urls() fixes hublocs + // when it discovers the URL has changed. So it's unclear how we could end up + // with URLs pointing to the old site name. But it happens. This may be an artifact + // of an old bug or maybe a regression in some newer code. In any event, they + // mess up communications and we have to take action if we find any. + + // First make sure we have any hublocs (at all) with this URL and sitekey. + // We don't want to perform this operation while somebody is in the process + // of renaming their hub or installing certs. + + $r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'", + dbesc(z_root()), + dbesc(get_config('system','pubkey')) + ); + if((! $r) || (! count($r))) + return; + + // Good. We have at least one valid hubloc. + + // Do we have any invalid ones? + + $r = q("select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'", + dbesc(get_config('system','pubkey')), + dbesc(z_root()) + ); + if(! $r) + return; + + logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.'); + + // We've got invalid hublocs. Get rid of them. + + $r = q("delete from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'", + dbesc(get_config('system','pubkey')), + dbesc(z_root()) + ); + + // We should probably tell everybody... But we don't have an easy way to do this + // for the entire site. We'd have to do a channel at a time. + // They will find out anyway - it just might take a little while. + + // FIXME we probably also need to check that the sys channel has a valid hubloc + // and re-create it if it doesn't. + +} + + + \ No newline at end of file diff --git a/include/zot.php b/include/zot.php index 644d20ec2..d2b657edb 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1189,7 +1189,8 @@ function zot_fetch($arr) { * we will verify the sender and url in each returned message structure and also verify * that all the messages returned match the site url that we are currently processing. * - * The message types handled here are 'activity' (e.g. posts), 'mail' , 'profile', and 'channel_sync' + * The message types handled here are 'activity' (e.g. posts), 'mail' , 'profile', 'location', + * and 'channel_sync' * * @returns array => array ( [0] => string $channel_hash, [1] => string $delivery_status, [2] => string $address ) * suitable for logging remotely, enumerating the processing results of each message/recipient combination. @@ -1348,7 +1349,7 @@ function zot_import($arr, $sender_url) { } elseif($i['message']['type'] === 'channel_sync') { -// $arr = get_channelsync_elements($i['message']); + // $arr = get_channelsync_elements($i['message']); $arr = $i['message']; @@ -1357,6 +1358,15 @@ function zot_import($arr, $sender_url) { $result = process_channel_sync_delivery($i['notify']['sender'],$arr,$deliveries); } + elseif($i['message']['type'] === 'location') { + $arr = $i['message']; + + logger('Location message received: ' . print_r($arr,true), LOGGER_DATA); + logger('Location messaeg recipients: ' . print_r($deliveries,true), LOGGER_DATA); + + $result = process_location_delivery($i['notify']['sender'],$arr,$deliveries); + } + } if($result){ $return = array_merge($return,$result); @@ -1800,6 +1810,194 @@ function process_profile_delivery($sender,$arr,$deliveries) { import_directory_profile($sender['hash'],$arr,$r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); } +function process_location_delivery($sender,$arr,$deliveries) { + + // deliveries is irrelevant + logger('process_location_delivery', LOGGER_DEBUG); +// sync_locations($sender,$arr,true); +} + +// We need to merge this code with that in the import_xchan function so as to make it +// easier to maintain changes. + +function sync_locations($sender,$arr,$absolute = false) { + +// fix sender stuff + + if($arr['locations']) { + + $xisting = q("select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s'", + dbesc($sender['hash']) + ); + + // See if a primary is specified + + $has_primary = false; + foreach($arr['locations'] as $location) { + if($location['primary']) { + $has_primary = true; + break; + } + } + + foreach($arr['locations'] as $location) { + if(! rsa_verify($location['url'],base64url_decode($location['url_sig']),$sender['key'])) { + logger('import_xchan: Unable to verify site signature for ' . $location['url']); + $ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL; + continue; + } + + // Ensure that they have one primary hub + + if(! $has_primary) + $location['primary'] = true; + + + for($x = 0; $x < count($xisting); $x ++) { + if(($xisting[$x]['hubloc_url'] === $location['url']) && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { + $xisting[$x]['updated'] = true; + } + } + + if(! $location['sitekey']) { + logger('import_xchan: empty hubloc sitekey. ' . print_r($location,true)); + continue; + } + + // Catch some malformed entries from the past which still exist + + if(strpos($location['address'],'/') !== false) + $location['address'] = substr($location['address'],0,strpos($location['address'],'/')); + + // match as many fields as possible in case anything at all changed. + + $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ", + dbesc($sender['hash']), + dbesc($sender['guid']), + dbesc($sender['guid_sig']), + dbesc($location['url']), + dbesc($location['url_sig']), + dbesc($location['host']), + dbesc($location['address']), + dbesc($location['callback']), + dbesc($location['sitekey']) + ); + if($r) { + logger('import_xchan: hub exists: ' . $location['url']); + // update connection timestamp if this is the site we're talking to + if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) { + q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d limit 1", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + } + if($r[0]['hubloc_status'] & HUBLOC_OFFLINE) { + q("update hubloc set hubloc_status = (hubloc_status ^ %d) where hubloc_id = %d limit 1", + intval(HUBLOC_OFFLINE), + intval($r[0]['hubloc_id']) + ); + if($r[0]['hubloc_flags'] & HUBLOC_FLAGS_ORPHANCHECK) { + q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_ORPHANCHECK), + intval($r[0]['hubloc_id']) + ); + } + q("update xchan set xchan_flags = (xchan_flags ^ %d) where (xchan_flags & %d) and xchan_hash = '%s' limit 1", + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_ORPHAN), + dbesc($sender['hash']) + ); + + } + + // Remove pure duplicates + if(count($r) > 1) { + for($h = 1; $h < count($r); $h ++) { + q("delete from hubloc where hubloc_id = %d limit 1", + intval($r[$h]['hubloc_id']) + ); + } + } + + if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY) && (! $location['primary'])) + || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_PRIMARY)) && ($location['primary']))) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_PRIMARY), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what = 'primary_hub '; + $changed = true; + } + if((($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED) && (! $location['deleted'])) + || ((! ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_DELETED)) && ($location['deleted']))) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1", + intval(HUBLOC_FLAGS_DELETED), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what = 'delete_hub '; + $changed = true; + } + continue; + } + + // new hub claiming to be primary. Make it so. + + if(intval($location['primary'])) { + $r = q("update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d )", + intval(HUBLOC_FLAGS_PRIMARY), + dbesc(datetime_convert()), + dbesc($sender['hash']), + intval(HUBLOC_FLAGS_PRIMARY) + ); + } + logger('location_delivery: new hub: ' . $location['url']); + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_flags, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected) + values ( '%s','%s','%s','%s', '%s', %d ,'%s','%s','%s','%s','%s','%s','%s')", + dbesc($sender['guid']), + dbesc($sender['guid_sig']), + dbesc($sender['hash']), + dbesc($location['address']), + dbesc('zot'), + intval((intval($location['primary'])) ? HUBLOC_FLAGS_PRIMARY : 0), + dbesc($location['url']), + dbesc($location['url_sig']), + dbesc($location['host']), + dbesc($location['callback']), + dbesc($location['sitekey']), + dbesc(datetime_convert()), + dbesc(datetime_convert()) + ); + $what .= 'newhub '; + $changed = true; + + } + + // get rid of any hubs we have for this channel which weren't reported. + + if($absolute && $xisting) { + foreach($xisting as $x) { + if(! array_key_exists('updated',$x)) { + logger('import_xchan: removing unreferenced hub location ' . $x['hubloc_url']); + $r = q("delete from hubloc where hubloc_id = %d limit 1", + intval($x['hubloc_id']) + ); + $what .= 'removed_hub'; + $changed = true; + } + } + } + } + + $ret['change_message'] = $what; + $ret['changed'] = $changed; + + return $ret; + +} + /* * @function import_directory_profile diff --git a/mod/post.php b/mod/post.php index 3b4f66baf..d62233ca1 100644 --- a/mod/post.php +++ b/mod/post.php @@ -415,8 +415,8 @@ function post_init(&$a) { * } *} * - * Currently defined message types are 'activity', 'mail', 'profile' and 'channel_sync', which each have - * different content schemas. + * Currently defined message types are 'activity', 'mail', 'profile', 'location' and 'channel_sync', + * which each have different content schemas. * * Ping packet: * A ping packet does not require any parameters except the type. It may or may not be encrypted. diff --git a/version.inc b/version.inc index aa1814513..92c44d434 100644 --- a/version.inc +++ b/version.inc @@ -1 +1 @@ -2014-09-12.796 +2014-09-13.797 -- cgit v1.2.3