2017-03-24 22:32:53 +00:00
< ? php
2021-12-03 03:01:39 +00:00
2017-03-24 22:32:53 +00:00
/**
* @ file include / hubloc . php
* @ brief Hubloc related functions .
*/
2022-06-18 02:24:50 +00:00
use Code\Lib\Channel ;
2024-04-02 23:36:17 +00:00
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
2017-03-24 22:32:53 +00:00
/**
* @ brief Create an array for hubloc table and insert record .
*
* Creates an assoziative array which will be inserted into the hubloc table .
*
* @ param array $arr An assoziative array with hubloc values
2021-12-02 23:02:31 +00:00
* @ return bool | PDOStatement
2017-03-24 22:32:53 +00:00
*/
2021-12-03 03:01:39 +00:00
function hubloc_store_lowlevel ( $arr )
{
2022-01-23 10:13:59 +00:00
$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-05-21 06:34:07 +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
2022-01-23 10:13:59 +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 );
2017-04-03 23:43:30 +00:00
}
2024-04-02 23:36:17 +00:00
/**
* @ brief Removes foreign location records which are no longer valid
* @ return void
*/
2021-12-03 03:01:39 +00:00
function prune_hub_reinstalls ()
{
2014-03-20 02:53:14 +00:00
2021-12-03 03:01:39 +00:00
$r = q (
2024-04-02 23:36:17 +00:00
" select site_url from site where site_type = %d && 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' ])
);
2014-03-20 02:53:14 +00:00
2021-12-03 03:01:39 +00:00
// see if this url has more than one sitekey, indicating it has been re-installed.
2014-03-20 02:53:14 +00:00
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' );
2014-03-20 02:53:14 +00:00
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.
2014-03-20 02:53:14 +00:00
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' ]);
2024-04-02 23:36:17 +00:00
hubloc_delete ( $x [ 0 ]);
2021-12-03 03:01:39 +00:00
}
}
}
}
2014-09-13 23:00:09 +00:00
}
2014-09-15 05:19:19 +00:00
2017-03-24 22:32:53 +00:00
/**
2024-04-02 23:36:17 +00:00
* @ brief checks and repairs local hubloc records
2017-03-24 22:32:53 +00:00
*
2024-04-02 23:36:17 +00:00
* This shouldn ' t happen . But it does .
2017-03-24 22:32:53 +00:00
*/
2024-04-02 23:36:17 +00:00
function check_hublocs ()
2021-12-03 03:01:39 +00:00
{
2024-04-02 23:36:17 +00:00
$sitekey = Config :: Get ( 'system' , 'pubkey' );
$interval = Config :: Get ( 'system' , 'delivery_interval' , 2 );
2021-12-03 03:01:39 +00:00
2024-04-02 23:36:17 +00:00
$wrong_urls = q (
2021-12-03 03:01:39 +00:00
" select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s' " ,
2024-04-02 23:36:17 +00:00
dbesc ( $sitekey ),
2021-12-03 03:01:39 +00:00
dbesc ( z_root ())
);
2024-04-02 23:36:17 +00:00
$wrong_keys = q (
2021-12-03 03:01:39 +00:00
" select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s' " ,
2024-04-02 23:36:17 +00:00
dbesc ( $sitekey ),
2021-12-03 03:01:39 +00:00
dbesc ( z_root ())
);
2024-04-02 23:36:17 +00:00
if ( is_array ( $wrong_urls ) && is_array ( $wrong_keys )) {
$invalids = array_merge ( $wrong_urls , $wrong_keys );
2021-12-03 03:01:39 +00:00
}
2024-04-02 23:36:17 +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
}
2024-04-02 23:36:17 +00:00
$channels = q ( " select * from channel where channel_removed = 0 " );
2021-12-03 03:01:39 +00:00
2024-04-02 23:36:17 +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
}
}
}
2014-09-13 23:00:09 +00:00
}
2017-03-24 22:32:53 +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
2017-03-24 22:32:53 +00:00
*/
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 ()) {
2022-06-18 02:24:50 +00:00
$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' ]),
2022-06-18 02:24:50 +00:00
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
}
2015-02-27 21:43:12 +00:00
2017-03-24 22:32:53 +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 .
2020-10-19 00:59:41 +00:00
* Also set site_dead for the corresponding entry in the site table
2017-03-24 22:32:53 +00:00
*
* @ 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 )
);
2015-02-27 21:43:12 +00:00
}
2022-01-23 10:13:59 +00:00
function hubloc_delete ( $hubloc ) {
if ( is_array ( $hubloc ) && array_key_exists ( 'hubloc_id' , $hubloc )) {
2022-06-18 02:24:50 +00:00
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 ()),
2022-06-18 02:24:50 +00:00
intval ( $hubloc [ 'hubloc_id' ]),
2022-01-23 10:13:59 +00:00
);
}
}
2022-09-11 07:41:37 +00:00
2018-02-01 23:09:51 +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
*/
2018-02-01 23:09:51 +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 )
);
2018-02-01 23:09:51 +00:00
2021-12-03 03:01:39 +00:00
return array_elm_to_str ( $locs , 'location' , ', ' , 'trim_and_unpunify' );
2018-02-01 23:09:51 +00:00
}
2015-09-14 05:48:18 +00:00
2021-12-03 03:01:39 +00:00
function ping_site ( $url )
{
2022-01-23 10:13:59 +00:00
$ret = [ 'success' => false ];
2015-09-14 05:48:18 +00:00
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 ;
}
2015-09-14 05:48:18 +00:00
2022-01-23 10:13:59 +00:00
$ret [ 'success' ] = true ;
return $ret ;
2015-09-14 05:48:18 +00:00
}
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 );
}
2022-06-17 06:12:42 +00:00
$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 ;
}