streams/include/hubloc.php

428 lines
16 KiB
PHP
Raw Normal View History

<?php
2021-12-03 03:01:39 +00:00
/**
* @file include/hubloc.php
* @brief Hubloc related functions.
*/
use Code\Lib\Channel;
use Code\Lib\Config;
use Code\Lib\Libzot;
2024-03-10 02:40:50 +00:00
use Code\Lib\Time;
2022-09-11 07:41:37 +00:00
use Code\Lib\Url;
2022-02-16 04:08:28 +00:00
use Code\Daemon\Run;
2021-04-13 03:49:58 +00:00
/**
* @brief Create an array for hubloc table and insert record.
*
2024-04-19 00:46:42 +00:00
* Creates an associative array which will be inserted into the hubloc table.
*
2024-05-21 06:40:56 +00:00
* @param array $arr An associative array with hubloc values
2024-04-19 00:46:42 +00:00
* @return bool
*/
2021-12-03 03:01:39 +00:00
function hubloc_store_lowlevel($arr)
{
$update = array_key_exists('hubloc_id',$arr) && $arr['hubloc_id'] ? 'hubloc_id = ' . intval($arr['hubloc_id']) : false;
2022-09-11 07:41:37 +00:00
2021-12-03 03:01:39 +00:00
$store = [
2024-04-19 00:46:42 +00:00
'hubloc_guid' => ((array_key_exists('hubloc_guid', $arr)) ? $arr['hubloc_guid'] : ''),
'hubloc_guid_sig' => ((array_key_exists('hubloc_guid_sig', $arr)) ? $arr['hubloc_guid_sig'] : ''),
'hubloc_id_url' => ((array_key_exists('hubloc_id_url', $arr)) ? $arr['hubloc_id_url'] : ''),
'hubloc_resolver' => ((array_key_exists('hubloc_resolver', $arr)) ? $arr['hubloc_resolver'] : ''),
'hubloc_hash' => ((array_key_exists('hubloc_hash', $arr)) ? $arr['hubloc_hash'] : ''),
'hubloc_addr' => ((array_key_exists('hubloc_addr', $arr)) ? $arr['hubloc_addr'] : ''),
'hubloc_network' => ((array_key_exists('hubloc_network', $arr)) ? $arr['hubloc_network'] : ''),
'hubloc_flags' => ((array_key_exists('hubloc_flags', $arr)) ? $arr['hubloc_flags'] : 0),
'hubloc_status' => ((array_key_exists('hubloc_status', $arr)) ? $arr['hubloc_status'] : 0),
'hubloc_url' => ((array_key_exists('hubloc_url', $arr)) ? $arr['hubloc_url'] : ''),
'hubloc_url_sig' => ((array_key_exists('hubloc_url_sig', $arr)) ? $arr['hubloc_url_sig'] : ''),
'hubloc_site_id' => ((array_key_exists('hubloc_site_id', $arr)) ? $arr['hubloc_site_id'] : ''),
'hubloc_host' => ((array_key_exists('hubloc_host', $arr)) ? $arr['hubloc_host'] : ''),
'hubloc_callback' => ((array_key_exists('hubloc_callback', $arr)) ? $arr['hubloc_callback'] : ''),
'hubloc_connect' => ((array_key_exists('hubloc_connect', $arr)) ? $arr['hubloc_connect'] : ''),
'hubloc_openwebauth' => ((array_key_exists('hubloc_openwebauth', $arr)) ? $arr['hubloc_openwebauth'] : ''),
'hubloc_authredirect' => ((array_key_exists('hubloc_authredirect', $arr)) ? $arr['hubloc_authredirect'] : ''),
'hubloc_sitekey' => ((array_key_exists('hubloc_sitekey', $arr)) ? $arr['hubloc_sitekey'] : ''),
'hubloc_updated' => ((array_key_exists('hubloc_updated', $arr)) ? $arr['hubloc_updated'] : NULL_DATE),
'hubloc_connected' => ((array_key_exists('hubloc_connected', $arr)) ? $arr['hubloc_connected'] : NULL_DATE),
'hubloc_primary' => ((array_key_exists('hubloc_primary', $arr)) ? $arr['hubloc_primary'] : 0),
'hubloc_orphancheck' => ((array_key_exists('hubloc_orphancheck', $arr)) ? $arr['hubloc_orphancheck'] : 0),
'hubloc_error' => ((array_key_exists('hubloc_error', $arr)) ? $arr['hubloc_error'] : 0),
'hubloc_deleted' => ((array_key_exists('hubloc_deleted', $arr)) ? $arr['hubloc_deleted'] : 0)
2021-12-03 03:01:39 +00:00
];
2022-09-11 07:41:37 +00:00
return $update ? update_table_from_array('hubloc', $store, $update) : create_table_from_array('hubloc', $store);
2017-01-30 23:01:22 +00:00
}
2021-12-03 03:01:39 +00:00
function site_store_lowlevel($arr)
{
$store = [
'site_url' => ((array_key_exists('site_url', $arr)) ? $arr['site_url'] : ''),
'site_access' => ((array_key_exists('site_access', $arr)) ? $arr['site_access'] : 0),
'site_flags' => ((array_key_exists('site_flags', $arr)) ? $arr['site_flags'] : 0),
'site_update' => ((array_key_exists('site_update', $arr)) ? $arr['site_update'] : NULL_DATE),
'site_pull' => ((array_key_exists('site_pull', $arr)) ? $arr['site_pull'] : NULL_DATE),
'site_sync' => ((array_key_exists('site_sync', $arr)) ? $arr['site_sync'] : NULL_DATE),
'site_directory' => ((array_key_exists('site_directory', $arr)) ? $arr['site_directory'] : ''),
'site_register' => ((array_key_exists('site_register', $arr)) ? $arr['site_register'] : 0),
'site_sellpage' => ((array_key_exists('site_sellpage', $arr)) ? $arr['site_sellpage'] : ''),
'site_location' => ((array_key_exists('site_location', $arr)) ? $arr['site_location'] : ''),
'site_realm' => ((array_key_exists('site_realm', $arr)) ? $arr['site_realm'] : ''),
'site_valid' => ((array_key_exists('site_valid', $arr)) ? $arr['site_valid'] : 0),
'site_dead' => ((array_key_exists('site_dead', $arr)) ? $arr['site_dead'] : 0),
'site_type' => ((array_key_exists('site_type', $arr)) ? $arr['site_type'] : 0),
'site_project' => ((array_key_exists('site_project', $arr)) ? $arr['site_project'] : ''),
'site_version' => ((array_key_exists('site_version', $arr)) ? $arr['site_version'] : ''),
'site_crypto' => ((array_key_exists('site_crypto', $arr)) ? $arr['site_crypto'] : '')
];
return create_table_from_array('site', $store);
}
/**
* @brief Removes foreign location records which are no longer valid
* @return void
*/
2021-12-03 03:01:39 +00:00
function prune_hub_reinstalls()
{
2021-12-03 03:01:39 +00:00
$r = q(
2024-09-08 02:06:29 +00:00
"select site_url from site where site_type = %d and site_url != '%s'",
intval(SITE_TYPE_ZOT),
dbesc(z_root())
2021-12-03 03:01:39 +00:00
);
if ($r) {
foreach ($r as $rr) {
$x = q(
"select count(*) as t, hubloc_sitekey, max(hubloc_connected) as c from hubloc where hubloc_url = '%s' group by hubloc_sitekey order by c",
dbesc($rr['site_url'])
);
2021-12-03 03:01:39 +00:00
// see if this url has more than one sitekey, indicating it has been re-installed.
2021-12-03 03:01:39 +00:00
if (count($x) > 1) {
2024-03-10 02:40:50 +00:00
$d1 = Time::convert('UTC', 'UTC', $x[0]['c']);
$d2 = Time::convert('UTC', 'UTC', 'now - 3 days');
2021-12-03 03:01:39 +00:00
// allow some slop period, say 3 days - just in case this is a glitch or transient occurrence
// Then remove any hublocs pointing to the oldest entry.
2021-12-03 03:01:39 +00:00
if (($d1 < $d2) && ($x[0]['hubloc_sitekey'])) {
logger('prune_hub_reinstalls: removing dead hublocs at ' . $rr['site_url']);
hubloc_delete($x[0]);
2021-12-03 03:01:39 +00:00
}
}
}
}
}
/**
* @brief checks and repairs local hubloc records
*
* This shouldn't happen. But it does.
*/
function check_hublocs()
2021-12-03 03:01:39 +00:00
{
$sitekey = Config::Get('system', 'pubkey');
$interval = Config::Get('system', 'delivery_interval', 2);
2021-12-03 03:01:39 +00:00
$wrong_urls = q(
"select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s' and hubloc_network in ('zot6', 'nomad')",
dbesc($sitekey),
2021-12-03 03:01:39 +00:00
dbesc(z_root())
);
$wrong_keys = q(
"select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s' and hubloc_network in ('zot6', 'nomad')",
dbesc($sitekey),
2021-12-03 03:01:39 +00:00
dbesc(z_root())
);
if (is_array($wrong_urls) && is_array($wrong_keys)) {
$invalids = array_merge($wrong_urls, $wrong_keys);
2021-12-03 03:01:39 +00:00
}
if ($invalids) {
foreach ($invalids as $hubloc) {
logger('Removing invalid hubloc for ' . $hubloc['hubloc_addr'], LOGGER_DEBUG);
hubloc_delete($hubloc);
$channel = Channel::from_hash($hubloc['hubloc_hash']);
if ($channel) {
Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]);
if ($interval) {
@time_sleep_until(microtime(true) + (float)$interval);
}
}
}
2021-12-03 03:01:39 +00:00
}
$channels = q("select * from channel where channel_removed = 0");
2021-12-03 03:01:39 +00:00
if ($channels) {
foreach ($channels as $channel) {
$hubs = q("select * from hubloc where hubloc_hash = '%s' and
hubloc_url = '%s' and hubloc_sitekey = '%s'",
dbesc($channel['channel_hash']),
dbesc(z_root()),
dbesc($sitekey)
);
if (!$hubs) {
logger('Repairing hubloc for ' . $channel['channel_address'], LOGGER_DEBUG);
// This channel does not have a valid location (hubloc)
// set for this site.
$hubloc_addr = Channel::get_webfinger($channel);
$primary = 1; // if xchan is missing, make this location the primary
$xchans = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($channel['channel_hash'])
);
if ($xchans) {
$primary = (int)$xchans[0]['xchan_addr'] === $hubloc_addr;
}
$result = hubloc_store_lowlevel(
[
'hubloc_guid' => $channel['channel_guid'],
'hubloc_guid_sig' => $channel['channel_guid_sig'],
'hubloc_hash' => $channel['channel_hash'],
'hubloc_id_url' => Channel::url($channel),
'hubloc_addr' => Channel::get_webfinger($channel),
'hubloc_primary' => $primary,
'hubloc_url' => z_root(),
'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']),
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), $sitekey),
'hubloc_host' => App::get_hostname(),
'hubloc_callback' => z_root() . '/nomad',
'hubloc_sitekey' => $sitekey,
'hubloc_network' => 'nomad',
'hubloc_updated' => Time::convert(),
'hubloc_connected' => Time::convert()
]
);
if ($result) {
q("delete from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' and hubloc_sitekey != '%s'",
dbesc($channel['channel_hash']),
dbesc(z_root()),
dbesc($sitekey)
);
Run::Summon([ 'Notifier', 'refresh_all', $channel['channel_id'] ]);
if ($interval) {
@time_sleep_until(microtime(true) + (float) $interval);
}
}
2021-12-03 03:01:39 +00:00
}
}
}
}
/**
* @brief Change primary hubloc.
*
* This actually changes other structures to match the given (presumably current)
* hubloc primary selection.
*
* @param array $hubloc
2021-12-02 23:02:31 +00:00
* @return bool
*/
2021-12-03 03:01:39 +00:00
function hubloc_change_primary($hubloc)
{
if (! is_array($hubloc)) {
logger('no hubloc');
return false;
}
logger('setting primary: ' . $hubloc['hubloc_url'] . ((intval($hubloc['hubloc_primary'])) ? ' true' : ' false'));
// See if this is a local hubloc and if so update the primary for the corresponding channel record.
if ($hubloc['hubloc_url'] === z_root()) {
$r = Channel::from_hash($hubloc['hubloc_hash']);
2021-12-03 03:01:39 +00:00
if ($r) {
q(
"update channel set channel_primary = %d where channel_id = %d",
intval($hubloc['hubloc_primary']),
intval($r['channel_id'])
2021-12-03 03:01:39 +00:00
);
}
}
// we only need to proceed further if this particular hubloc is now primary
if (! (intval($hubloc['hubloc_primary']))) {
logger('not primary: ' . $hubloc['hubloc_url']);
return false;
}
// do we even have an xchan for this hubloc and if so is it already set as primary?
$r = q(
"select * from xchan where xchan_hash = '%s' limit 1",
dbesc($hubloc['hubloc_hash'])
);
if (! $r) {
logger('xchan not found');
return false;
}
if ($r[0]['xchan_addr'] === $hubloc['hubloc_addr']) {
logger('xchan already changed');
return false;
}
$url = $hubloc['hubloc_url'];
$lwebbie = substr($hubloc['hubloc_addr'], 0, strpos($hubloc['hubloc_addr'], '@'));
$r = q(
"update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_follow = '%s', xchan_connurl = '%s' where xchan_hash = '%s'",
dbesc($hubloc['hubloc_addr']),
dbesc($url . '/channel/' . $lwebbie),
dbesc($url . '/follow?f=&url=%s'),
dbesc($url . '/poco/' . $lwebbie),
dbesc($hubloc['hubloc_hash'])
);
if (! $r) {
logger('xchan_update failed.');
}
logger('primary hubloc changed.' . print_r($hubloc, true), LOGGER_DEBUG);
return true;
2014-10-13 22:27:03 +00:00
}
/**
* @brief Mark a hubloc as down.
*
* We use the post url to distinguish between http and https hublocs.
* The https might be alive, and the http dead.
* Also set site_dead for the corresponding entry in the site table
*
* @param string $posturl Hubloc callback url which to disable
*/
2021-12-03 03:01:39 +00:00
function hubloc_mark_as_down($posturl)
{
$r = q(
"update hubloc set hubloc_status = ( hubloc_status | %d ) where hubloc_callback = '%s'",
intval(HUBLOC_OFFLINE),
dbesc($posturl)
);
// extract the baseurl and set site.site_dead to match
$m = parse_url($posturl);
$h = $m['scheme'] . '://' . $m['host'];
$r = q(
"update site set site_dead = 1 where site_url = '%s'",
dbesc($h)
);
}
function hubloc_delete($hubloc) {
if (is_array($hubloc) && array_key_exists('hubloc_id',$hubloc)) {
q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d",
2024-03-10 02:40:50 +00:00
dbesc(Time::convert()),
intval($hubloc['hubloc_id']),
);
}
}
2022-09-11 07:41:37 +00:00
/**
* @brief return comma separated string of non-dead clone locations (net addresses) for a given netid
*
* @param string $netid network identity (typically xchan_hash or hubloc_hash)
* @return string
2021-12-03 03:01:39 +00:00
*/
2021-12-03 03:01:39 +00:00
function locations_by_netid($netid)
{
$locs = q(
"select hubloc_addr as location from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_deleted = 0 and site_dead = 0",
dbesc($netid)
);
2021-12-03 03:01:39 +00:00
return array_elm_to_str($locs, 'location', ', ', 'trim_and_unpunify');
}
2021-12-03 03:01:39 +00:00
function ping_site($url)
{
$ret = [ 'success' => false ];
2022-09-04 22:39:58 +00:00
$result = Url::get($url . '/api/z/1.0/version');
if (! $result['success']) {
2021-12-03 03:01:39 +00:00
$ret['message'] = 'no answer from ' . $url;
return $ret;
}
$ret['success'] = true;
return $ret;
}
2019-04-16 04:55:59 +00:00
2023-11-27 06:10:26 +00:00
function get_locations_by_hash($hash)
2021-12-03 03:01:39 +00:00
{
return q(
2023-11-27 06:10:26 +00:00
"select hubloc_addr, hubloc_id_url from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
2021-12-03 03:01:39 +00:00
dbesc($hash)
);
}
2022-06-17 02:46:54 +00:00
function hubloc_id_query($s, $limit = 0) {
if ($limit) {
$qlimit = 'limit ' . intval($limit);
}
$r = q("select * from hubloc where (hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 $qlimit",
dbesc($s),
dbesc($s)
);
return $r;
}
function hublocx_id_query($s, $limit = 0) {
if ($limit) {
$qlimit = 'limit ' . intval($limit);
}
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where (hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 $qlimit",
2022-06-17 02:46:54 +00:00
dbesc($s),
dbesc($s)
);
return $r;
}
2023-02-15 20:16:58 +00:00
function get_hubloc_id_urls_by_portable_id($xchan) {
$r = q("SELECT hubloc_id_url FROM hubloc WHERE hubloc_deleted = 0 AND hubloc_hash = '%s' order by hubloc_primary desc",
dbesc($xchan)
);
return flatten_array_recursive($r);
}
2022-06-17 02:46:54 +00:00
function hubloc_id_addr_query($s, $limit = 0) {
if ($limit) {
$qlimit = 'limit ' . intval($limit);
}
2022-12-21 18:48:23 +00:00
$r = q("select * from hubloc where (hubloc_id_url = '%s' or hubloc_hash = '%s' or hubloc_addr = '%s') and hubloc_deleted = 0 order by hubloc_id desc $qlimit",
2022-06-17 02:46:54 +00:00
dbesc($s),
dbesc($s),
dbesc(str_replace('acct:' , '', $s))
);
return $r;
}
2023-01-02 03:02:11 +00:00
/** @noinspection PhpUnused */
2022-06-17 02:46:54 +00:00
function hublocx_id_addr_query($s, $limit = 0) {
if ($limit) {
$qlimit = 'limit ' . intval($limit);
}
2022-12-21 18:48:23 +00:00
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where (hubloc_id_url = '%s' or hubloc_hash = '%s' or hubloc_addr = '%s') and hubloc_deleted = 0 order by hubloc_id desc $qlimit",
2022-06-17 02:46:54 +00:00
dbesc($s),
dbesc($s),
dbesc(str_replace('acct:' , '', $s))
);
return $r;
}