diff options
Diffstat (limited to 'Zotlabs/Lib/Libzotdir.php')
-rw-r--r-- | Zotlabs/Lib/Libzotdir.php | 358 |
1 files changed, 227 insertions, 131 deletions
diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index dfedd0bc8..58138850c 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -172,13 +172,12 @@ class Libzotdir { } /** - * @brief Checks the directory mode of this hub. + * @brief fetches updates from known directories * * Checks the directory mode of this hub to see if it is some form of directory server. If it is, * get the directory realm of this hub. Fetch a list of all other directory servers in this realm and request - * a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB. - * In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored - * directly if the rater's signature matches. + * a directory sync packet. Store these all in the DB. + * In the case of updates, we will query each of them asynchronously from a poller task. * * @param int $dirmode; */ @@ -233,6 +232,8 @@ class Libzotdir { if (! $r) return; + $dir_trusted_hosts = array_merge(get_directory_fallback_servers(), get_config('system', 'trusted_directory_servers', [])); + foreach ($r as $rr) { if (! $rr['site_directory']) continue; @@ -264,31 +265,65 @@ class Libzotdir { if (is_array($j['transactions']) && count($j['transactions'])) { foreach ($j['transactions'] as $t) { - - if (empty($t['hash']) || empty($t['transaction_id']) || empty($t['address'])) { + if (empty($t['hash']) || empty($t['host']) || empty($t['address'])) { continue; } - $r = q("select * from updates where ud_guid = '%s' limit 1", - dbesc($t['transaction_id']) + $r = q("select * from updates where ud_hash = '%s' limit 1", + dbesc($t['hash']) ); - if($r) - continue; - $ud_flags = 0; - if (is_array($t['flags']) && in_array('deleted',$t['flags'])) - $ud_flags |= UPDATE_FLAGS_DELETED; - if (is_array($t['flags']) && in_array('forced',$t['flags'])) - $ud_flags |= UPDATE_FLAGS_FORCED; - - $z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) - values ( '%s', '%s', '%s', %d, '%s' ) ", - dbesc($t['hash']), - dbesc($t['transaction_id']), - dbesc($t['timestamp']), - intval($ud_flags), - dbesc($t['address']) - ); + if ($r) { + $update = 0; + + // no need to look at updates that originated from our own site + if ($t['host'] === z_root()) { + continue; + } + + // there is more recent xchan information + if ($r[0]['ud_date'] <= $t['timestamp']) { + $update = 1; + } + + // the host is trusted and flags have changed - update flags immediately + if (in_array($t['host'], $dir_trusted_hosts) && + $rr['site_url'] === $t['host'] && + intval($r[0]['ud_flags']) !== intval($t['flags'])) { + + q("UPDATE updates SET ud_update = %d, ud_flags = %d WHERE ud_id = %d", + intval($update), + intval($t['flags']), + dbesc($r[0]['ud_id']) + ); + + q("UPDATE xchan SET xchan_censored = %d WHERE xchan_hash = '%s'", + intval($t['flags']), + dbesc($r[0]['ud_hash']) + ); + + continue; + } + + if (!$update) { + continue; + } + + q("UPDATE updates SET ud_update = %d WHERE ud_id = %d", + intval($update), + dbesc($r[0]['ud_id']) + ); + } + else { + q("insert into updates ( ud_hash, ud_host, ud_date, ud_addr, ud_update, ud_flags ) + values ( '%s', '%s', '%s', '%s', 1, %d) ", + dbesc($t['hash']), + dbesc($t['host']), + dbesc($t['timestamp']), + dbesc($t['address']), + dbesc(in_array($t['host'], $dir_trusted_hosts) ? $t['flags'] : 0) + ); + } } } } @@ -303,8 +338,9 @@ class Libzotdir { * * Ignore updating records marked as deleted. * - * If successful, sets ud_last in the DB to the current datetime for this + * If successful, sets ud_updated in the DB to the current datetime for this * reddress/webbie. + * Else update ud_last so we can stop trying after 7 days (Daemon/Poller.php) * * @param array $ud Entry from update table */ @@ -313,31 +349,47 @@ class Libzotdir { logger('update_directory_entry: ' . print_r($ud,true), LOGGER_DATA); - if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { - $success = false; - $zf = []; + // TODO: remove this check after all directory servers have version > 8.4 + // ud_addr will always be the channel url at that time + $href = ((strpos($ud['ud_addr'], '://') === false) ? Webfinger::zot_url(punify($ud['ud_addr'])) : punify($ud['ud_addr'])); + if($href) { + $zf = Zotfinger::exec($href); + if($zf && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { + $xc = Libzot::import_xchan($zf['data']); + + // xchan_hash mismatch - this can happen after a site re-install at the same url + if ($xc['success'] && $xc['hash'] !== $ud['ud_hash']) { + self::delete_by_hash($ud['ud_hash']); + } + + // backwards compatibility: Libzot::import_xchan(), where self::update() is called, + // will fail with versions < 8.4 if the channel has been locally deleted. + // In this case we will update the updates record here without bumping the date + // since we could not verify if anything changed. + if (!$xc['success'] && !empty($zf['data']['deleted_locally'])) { + self::update($ud['ud_hash'], $ud['ud_addr'], false); + } - $href = Webfinger::zot_url(punify($ud['ud_addr'])); - if($href) { - $zf = Zotfinger::exec($href); - } - if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { - $xc = Libzot::import_xchan($zf['data'], 0, $ud); // This is a workaround for a missing xchan_updated column // TODO: implement xchan_updated in the xchan table and update this column instead - if($zf['data']['primary_location']['address'] && $zf['data']['primary_location']['url']) { + if(!empty($zf['data']['primary_location']['url'])) { q("UPDATE hubloc SET hubloc_updated = '%s' WHERE hubloc_id_url = '%s' AND hubloc_primary = 1", dbesc(datetime_convert()), dbesc($zf['data']['primary_location']['url']) ); } - q("update updates set ud_last = '%s' where ud_addr = '%s'", - dbesc(datetime_convert()), - dbesc($ud['ud_addr']) - ); + return true; } } + + q("UPDATE updates SET ud_addr = '%s', ud_last = '%s' WHERE ud_hash = '%s'", + dbesc($href ? $href : $ud['ud_addr']), + dbesc(datetime_convert()), + dbesc($ud['ud_hash']) + ); + + return false; } @@ -352,85 +404,78 @@ class Libzotdir { */ static function local_dir_update($uid, $force) { + logger('local_dir_update uid: ' . $uid, LOGGER_DEBUG); - - logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); - - $p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", + $p = q("select channel.channel_hash, channel_address, channel_timezone, profile.*, xchan.xchan_hidden, xchan.xchan_url from profile left join channel on channel_id = uid left join xchan on channel_hash = xchan_hash where profile.uid = %d and profile.is_default = 1", intval($uid) ); - $profile = array(); + if (!$p) { + logger('profile not found'); + return; + } + + $profile = []; $profile['encoding'] = 'zot'; - if ($p) { - $hash = $p[0]['channel_hash']; - - $profile['description'] = $p[0]['pdesc']; - $profile['birthday'] = $p[0]['dob']; - if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) - $profile['age'] = $age; - - $profile['gender'] = $p[0]['gender']; - $profile['marital'] = $p[0]['marital']; - $profile['sexual'] = $p[0]['sexual']; - $profile['locale'] = $p[0]['locality']; - $profile['region'] = $p[0]['region']; - $profile['postcode'] = $p[0]['postal_code']; - $profile['country'] = $p[0]['country_name']; - $profile['about'] = $p[0]['about']; - $profile['homepage'] = $p[0]['homepage']; - $profile['hometown'] = $p[0]['hometown']; - - if ($p[0]['keywords']) { - $tags = array(); - $k = explode(' ', $p[0]['keywords']); - if ($k) - foreach ($k as $kk) - if (trim($kk)) - $tags[] = trim($kk); - - if ($tags) - $profile['keywords'] = $tags; - } + $hash = $p[0]['channel_hash']; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) + $profile['age'] = $age; + + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if ($p[0]['keywords']) { + $tags = array(); + $k = explode(' ', $p[0]['keywords']); + if ($k) + foreach ($k as $kk) + if (trim($kk)) + $tags[] = trim($kk); + + if ($tags) + $profile['keywords'] = $tags; + } - $hidden = (1 - intval($p[0]['publish'])); + $hidden = (1 - intval($p[0]['publish'])); - logger('hidden: ' . $hidden); + logger('hidden: ' . $hidden); - $r = q("select xchan_hidden from xchan where xchan_hash = '%s'", - dbesc($p[0]['channel_hash']) + if(intval($p[0]['xchan_hidden']) !== $hidden) { + q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", + intval($hidden), + dbesc($hash) ); + } - if(intval($r[0]['xchan_hidden']) != $hidden) { - $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", - intval($hidden), - dbesc($hash) - ); - } - - $arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ]; - call_hooks('local_dir_update', $arr); - - $address = channel_reddress($p[0]); - - if (perm_is_allowed($uid, '', 'view_profile')) { - self::import_directory_profile($hash, $arr['profile'], $address, 0); - } - else { - // they may have made it private - q("delete from xprof where xprof_hash = '%s'", - dbesc($hash) - ); - q("delete from xtag where xtag_hash = '%s'", - dbesc($hash) - ); - } + $arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ]; + call_hooks('local_dir_update', $arr); + if (perm_is_allowed($uid, '', 'view_profile')) { + self::import_directory_profile($hash, $arr['profile']); + } + else { + // they may have made it private + q("delete from xprof where xprof_hash = '%s'", + dbesc($hash) + ); + q("delete from xtag where xtag_hash = '%s'", + dbesc($hash) + ); } - $ud_hash = random_string() . '@' . \App::get_hostname(); - self::update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); + self::update($hash, $p[0]['xchan_url']); } @@ -440,13 +485,10 @@ class Libzotdir { * * @param string $hash * @param array $profile - * @param string $addr - * @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED - * @param number $suppress_update (optional) default 0 * @return boolean $updated if something changed */ - static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) { + static function import_directory_profile($hash, $profile) { logger('import_directory_profile', LOGGER_DEBUG); if (! $hash) @@ -479,7 +521,12 @@ class Libzotdir { $clean = array(); if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) { self::import_directory_keywords($hash,$profile['keywords']); + foreach ($profile['keywords'] as $kw) { + if (in_array($kw, $clean)) { + continue; + } + $kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false)); $kw = trim($kw, ','); $clean[] = $kw; @@ -586,9 +633,6 @@ class Libzotdir { */ call_hooks('import_directory_profile', $d); - if (($d['update']) && (! $suppress_update)) - self::update_modtime($arr['xprof_hash'],random_string() . '@' . \App::get_hostname(), $addr, $ud_flags); - return $d['update']; } @@ -606,6 +650,10 @@ class Libzotdir { dbesc($hash) ); + $xchan = q("select xchan_censored from xchan where xchan_hash = '%s'", + dbesc($hash) + ); + if($r) { foreach($r as $rr) $existing[] = $rr['xtag_term']; @@ -613,6 +661,10 @@ class Libzotdir { $clean = array(); foreach($keywords as $kw) { + if (in_array($kw, $clean)) { + continue; + } + $kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false)); $kw = trim($kw, ','); $clean[] = $kw; @@ -627,9 +679,10 @@ class Libzotdir { } foreach($clean as $x) { if(! in_array($x, $existing)) { - $r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )", + $r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', %d )", dbesc($hash), - dbesc($x) + dbesc($x), + intval($xchan[0]['xchan_censored']) ); } } @@ -639,13 +692,12 @@ class Libzotdir { /** * @brief * - * @param string $hash - * @param string $guid - * @param string $addr - * @param int $flags (optional) default 0 + * @param string $hash the channel hash + * @param string $addr the channel url + * @param bool $bump_date (optional) default true */ - static function update_modtime($hash, $guid, $addr, $flags = 0) { + static function update($hash, $addr, $bump_date = true, $flag = null) { $dirmode = intval(get_config('system', 'directory_mode')); @@ -653,26 +705,70 @@ class Libzotdir { return; } - if (empty($hash) || empty($guid) || empty($addr)) { + if (empty($hash) || empty($addr)) { return; } - if($flags) { - q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )", - dbesc($hash), - dbesc($guid), - dbesc(datetime_convert()), - intval($flags), - dbesc($addr) - ); + $u = q("SELECT * FROM updates WHERE ud_hash = '%s' LIMIT 1", + dbesc($hash) + ); + + $date_sql = ''; + if ($bump_date) { + $date_sql = "ud_date = '" . dbesc(datetime_convert()) . "',"; } - else { - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ", - intval(UPDATE_FLAGS_UPDATED), + + $flag_sql = ''; + if ($flag !== null) { + $flag_sql = "ud_flags = '" . intval($flag) . "',"; + } + + + if ($u) { + $x = q("UPDATE updates SET $date_sql $flag_sql ud_last = '%s', ud_host = '%s', ud_addr = '%s', ud_update = 0 WHERE ud_id = %d", + dbesc(NULL_DATE), + dbesc(z_root()), dbesc($addr), - intval(UPDATE_FLAGS_UPDATED) + intval($u[0]['ud_id']) ); + + return; + } + + q("INSERT INTO updates (ud_hash, ud_host, ud_date, ud_addr, ud_flags) VALUES ( '%s', '%s', '%s', '%s', %d )", + dbesc($hash), + dbesc(z_root()), + dbesc(datetime_convert()), + dbesc($addr), + intval($flag) + ); + + return; + + } + + + /** + * @brief deletes a entry in updates by hash + * + * @param string $hash the channel hash + * @return boolean + */ + + static function delete_by_hash($hash) { + if (!$hash) { + return false; + } + + $x = q("DELETE FROM updates WHERE ud_hash = '%s'", + dbesc($hash) + ); + + if ($x) { + return true; } + + return false; } } |