2018-06-05 01:40:11 +00:00
< ? php
2022-02-16 04:08:28 +00:00
namespace Code\Lib ;
2018-06-05 01:40:11 +00:00
2018-08-28 01:58:47 +00:00
use App ;
2022-08-23 11:01:09 +00:00
2022-02-16 04:08:28 +00:00
use Code\Daemon\Run ;
use Code\Extend\Hook ;
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
class Libsync
{
/**
* @ brief Builds and sends a sync packet .
*
* Send a zot packet to all hubs where this channel is duplicated , refreshing
* such things as personal settings , channel permissions , address book updates , etc .
*
* By default , sync the channel and any pconfig changes which were made in the current process
* AccessLists ( aka privacy groups ) will also be included if $groups_changed is true .
* To include other data sources , provide them as $packet .
*
* @ param int $uid ( optional ) default 0
* @ param array $packet ( optional ) default null
* @ param bool $groups_changed ( optional ) default false
*/
public static function build_sync_packet ( $uid = 0 , $packet = null , $groups_changed = false )
{
2022-03-18 02:26:10 +00:00
// logger('build_sync_packet');
2021-12-02 23:02:31 +00:00
2022-09-27 11:56:42 +00:00
$keychange = $packet && array_key_exists ( 'keychange' , $packet );
2021-12-02 23:02:31 +00:00
if ( $keychange ) {
logger ( 'keychange sync' );
}
if ( ! $uid ) {
$uid = local_channel ();
}
if ( ! $uid ) {
return ;
}
2022-01-25 01:26:12 +00:00
$channel = Channel :: from_id ( $uid );
2021-12-02 23:02:31 +00:00
if ( ! $channel ) {
return ;
}
// don't provide these in the export
unset ( $channel [ 'channel_active' ]);
unset ( $channel [ 'channel_password' ]);
unset ( $channel [ 'channel_salt' ]);
2018-06-05 01:40:11 +00:00
2022-07-20 05:31:55 +00:00
$h = q ( " select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url
where hubloc_hash = '%s' and hubloc_network in ( 'nomad' , 'zot6' ) and hubloc_deleted = 0 " ,
dbesc (( $keychange ) ? $packet [ 'keychange' ][ 'old_hash' ] : $channel [ 'channel_hash' ])
);
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $h ) {
return ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$synchubs = [];
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
foreach ( $h as $x ) {
if ( $x [ 'hubloc_host' ] == App :: get_hostname ()) {
continue ;
}
2018-06-05 01:40:11 +00:00
2021-12-03 03:01:39 +00:00
$y = q (
" select site_dead from site where site_url = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $x [ 'hubloc_url' ])
);
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if (( ! $y ) || ( $y [ 0 ][ 'site_dead' ] == 0 )) {
$synchubs [] = $x ;
}
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $synchubs ) {
return ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$env_recips = [ $channel [ 'channel_hash' ]];
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( $packet ) {
logger ( 'packet: ' . print_r ( $packet , true ), LOGGER_DATA , LOG_DEBUG );
}
2018-06-05 01:40:11 +00:00
2022-09-27 11:56:42 +00:00
$info = (( $packet ) ? : []);
2021-12-02 23:02:31 +00:00
$info [ 'type' ] = 'sync' ;
$info [ 'encoding' ] = 'red' ; // note: not zot, this packet is very platform specific
$info [ 'relocate' ] = [ 'channel_address' => $channel [ 'channel_address' ], 'url' => z_root ()];
2022-05-06 05:32:09 +00:00
$info [ 'schema' ] = 'streams' ;
2022-07-20 05:31:55 +00:00
2021-12-02 23:02:31 +00:00
if ( array_key_exists ( $uid , App :: $config ) && array_key_exists ( 'transient' , App :: $config [ $uid ])) {
$settings = App :: $config [ $uid ][ 'transient' ];
if ( $settings ) {
$info [ 'config' ] = $settings ;
}
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( $channel ) {
$info [ 'channel' ] = [];
foreach ( $channel as $k => $v ) {
// filter out any joined tables like xchan
2018-06-05 01:40:11 +00:00
2022-09-27 11:56:42 +00:00
if ( ! str_starts_with ( $k , 'channel_' )) {
2021-12-02 23:02:31 +00:00
continue ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
// don't pass these elements, they should not be synchronised
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$disallowed = [ 'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_address' ,
'channel_deleted' , 'channel_removed' , 'channel_system' ];
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $keychange ) {
$disallowed [] = 'channel_prvkey' ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( in_array ( $k , $disallowed )) {
continue ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$info [ 'channel' ][ $k ] = $v ;
}
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( $groups_changed ) {
2021-12-03 03:01:39 +00:00
$r = q (
" select hash as collection, visible, deleted, rule, gname as name from pgrp where uid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $uid )
);
if ( $r ) {
$info [ 'collections' ] = $r ;
}
2018-06-05 01:40:11 +00:00
2021-12-03 03:01:39 +00:00
$r = q (
2022-07-20 05:31:55 +00:00
" select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid
where pgrp_member . uid = % d " ,
2021-12-02 23:02:31 +00:00
intval ( $uid )
);
if ( $r ) {
$info [ 'collection_members' ] = $r ;
}
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$interval = get_config ( 'system' , 'delivery_interval' , 2 );
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
logger ( 'Packet: ' . print_r ( $info , true ), LOGGER_DATA , LOG_DEBUG );
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$total = count ( $synchubs );
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
foreach ( $synchubs as $hub ) {
$hash = random_string ();
$n = Libzot :: build_packet ( $channel , 'sync' , $env_recips , json_encode ( $info ), 'red' , $hub [ 'hubloc_sitekey' ], $hub [ 'site_crypto' ]);
Queue :: insert ([
'hash' => $hash ,
'account_id' => $channel [ 'channel_account_id' ],
'channel_id' => $channel [ 'channel_id' ],
'posturl' => $hub [ 'hubloc_callback' ],
'notify' => $n ,
'msg' => EMPTY_STR
]);
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$x = q ( " select count(outq_hash) as total from outq where outq_delivered = 0 " );
if ( intval ( $x [ 0 ][ 'total' ]) > intval ( get_config ( 'system' , 'force_queue_threshold' , 3000 ))) {
logger ( 'immediate delivery deferred.' , LOGGER_DEBUG , LOG_INFO );
2022-08-31 00:30:11 +00:00
Queue :: update ( $hash , 'Delivery deferred' );
2021-12-02 23:02:31 +00:00
continue ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
Run :: Summon ([ 'Deliver' , $hash ]);
$total = $total - 1 ;
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( $interval && $total ) {
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
}
}
}
2018-06-05 01:40:11 +00:00
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
public static function build_link_packet ( $uid = 0 , $packet = null )
{
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
// logger('build_link_packet');
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $uid ) {
$uid = local_channel ();
}
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $uid ) {
return ;
}
2018-08-28 01:58:47 +00:00
2022-01-25 01:26:12 +00:00
$channel = Channel :: from_id ( $uid );
2021-12-02 23:02:31 +00:00
if ( ! $channel ) {
return ;
}
2018-08-28 01:58:47 +00:00
2021-12-03 03:01:39 +00:00
$l = q (
" select link from linkid where ident = '%s' and sigtype = 2 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $channel [ 'channel_hash' ])
);
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $l ) {
return ;
}
$hashes = ids_to_querystr ( $l , 'link' , true );
2018-08-28 01:58:47 +00:00
2022-07-20 05:31:55 +00:00
$h = q ( " select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in ( " . protect_sprintf ( $hashes ) . " ) and hubloc_network in ('nomad','zot6') and hubloc_deleted = 0 " );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $h ) {
return ;
}
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
$interval = get_config ( 'system' , 'delivery_interval' , 2 );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
foreach ( $h as $x ) {
if ( $x [ 'hubloc_host' ] == App :: get_hostname ()) {
continue ;
}
2021-12-03 03:01:39 +00:00
$y = q (
" select site_dead from site where site_url = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $x [ 'hubloc_url' ])
);
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if (( $y ) && ( intval ( $y [ 0 ][ 'site_dead' ]) == 1 )) {
2022-08-23 11:01:09 +00:00
continue ;
2021-12-02 23:02:31 +00:00
}
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
$env_recips = [ $x [ 'hubloc_hash' ]];
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( $packet ) {
logger ( 'packet: ' . print_r ( $packet , true ), LOGGER_DATA , LOG_DEBUG );
}
2022-09-27 11:56:42 +00:00
$info = (( $packet ) ? : []);
2021-12-02 23:02:31 +00:00
$info [ 'type' ] = 'sync' ;
$info [ 'encoding' ] = 'red' ; // note: not zot, this packet is very platform specific
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
logger ( 'Packet: ' . print_r ( $info , true ), LOGGER_DATA , LOG_DEBUG );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
$hash = random_string ();
$n = Libzot :: build_packet ( $channel , 'sync' , $env_recips , json_encode ( $info ), 'red' , $x [ 'hubloc_sitekey' ], $x [ 'site_crypto' ]);
Queue :: insert ([
'hash' => $hash ,
'account_id' => $channel [ 'channel_account_id' ],
'channel_id' => $channel [ 'channel_id' ],
'posturl' => $x [ 'hubloc_callback' ],
'notify' => $n ,
'msg' => EMPTY_STR
]);
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
$y = q ( " select count(outq_hash) as total from outq where outq_delivered = 0 " );
if ( intval ( $y [ 0 ][ 'total' ]) > intval ( get_config ( 'system' , 'force_queue_threshold' , 3000 ))) {
logger ( 'immediate delivery deferred.' , LOGGER_DEBUG , LOG_INFO );
2022-08-31 00:30:11 +00:00
Queue :: update ( $hash , 'Delivery deferred' );
2021-12-02 23:02:31 +00:00
continue ;
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
Run :: Summon ([ 'Deliver' , $hash ]);
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
if ( $interval && count ( $h ) > 1 ) {
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
}
}
}
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
/**
* @ brief
*
2022-08-23 11:01:09 +00:00
* @ param string $sender
2021-12-02 23:02:31 +00:00
* @ param array $arr
* @ param array $deliveries
* @ return array
*/
2018-06-05 01:40:11 +00:00
2021-12-02 23:02:31 +00:00
public static function process_channel_sync_delivery ( $sender , $arr , $deliveries )
{
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
require_once ( 'include/import.php' );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
$result = [];
2022-05-06 05:32:09 +00:00
$schema = ( isset ( $arr [ 'schema' ]) && $arr [ 'schema' ]) ? $arr [ 'schema' ] : 'unknown' ;
2022-09-27 11:56:42 +00:00
$keychange = array_key_exists ( 'keychange' , $arr );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
foreach ( $deliveries as $d ) {
$linked_channel = false ;
2018-08-28 01:58:47 +00:00
2021-12-03 03:01:39 +00:00
$r = q (
" select * from channel where channel_hash = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender )
);
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
$DR = new DReport ( z_root (), $sender , $d , 'sync' );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( ! $r ) {
2021-12-03 03:01:39 +00:00
$l = q (
" select ident from linkid where link = '%s' and sigtype = 2 limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender )
);
if ( $l ) {
$linked_channel = true ;
2021-12-03 03:01:39 +00:00
$r = q (
" select * from channel where channel_hash = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $l [ 0 ][ 'ident' ])
);
}
}
if ( ! $r ) {
$DR -> update ( 'recipient not found' );
$result [] = $DR -> get ();
continue ;
}
$channel = $r [ 0 ];
2022-01-25 01:26:12 +00:00
$DR -> set_name ( $channel [ 'channel_name' ] . ' <' . Channel :: get_webfinger ( $channel ) . '>' );
2021-12-02 23:02:31 +00:00
2022-01-25 01:26:12 +00:00
$max_friends = ServiceClass :: fetch ( $channel [ 'channel_id' ], 'total_channels' );
$max_feeds = ServiceClass :: account_fetch ( $channel [ 'channel_account_id' ], 'total_feeds' );
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( $channel [ 'channel_hash' ] != $sender && ( ! $linked_channel )) {
logger ( 'Possible forgery. Sender ' . $sender . ' is not ' . $channel [ 'channel_hash' ]);
$DR -> update ( 'channel mismatch' );
$result [] = $DR -> get ();
continue ;
}
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( $keychange ) {
self :: keychange ( $channel , $arr );
continue ;
}
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
// if the clone is active, so are we
2018-08-28 01:58:47 +00:00
2021-12-02 23:02:31 +00:00
if ( substr ( $channel [ 'channel_active' ], 0 , 10 ) !== substr ( datetime_convert (), 0 , 10 )) {
2021-12-03 03:01:39 +00:00
q (
" UPDATE channel set channel_active = '%s' where channel_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
intval ( $channel [ 'channel_id' ])
);
}
if ( array_key_exists ( 'config' , $arr ) && is_array ( $arr [ 'config' ]) && count ( $arr [ 'config' ])) {
foreach ( $arr [ 'config' ] as $cat => $k ) {
foreach ( $arr [ 'config' ][ $cat ] as $k => $v ) {
set_pconfig ( $channel [ 'channel_id' ], $cat , $k , $v );
}
}
}
if ( array_key_exists ( 'atoken' , $arr ) && $arr [ 'atoken' ]) {
sync_atoken ( $channel , $arr [ 'atoken' ]);
}
if ( array_key_exists ( 'xign' , $arr ) && $arr [ 'xign' ]) {
sync_xign ( $channel , $arr [ 'xign' ]);
}
2022-03-22 19:45:55 +00:00
if ( array_key_exists ( 'block_xchan' , $arr ) && $arr [ 'block_xchan' ]) {
import_xchans ( $arr [ 'block_xchan' ]);
}
2021-12-02 23:02:31 +00:00
if ( array_key_exists ( 'block' , $arr ) && $arr [ 'block' ]) {
sync_block ( $channel , $arr [ 'block' ]);
}
if ( array_key_exists ( 'obj' , $arr ) && $arr [ 'obj' ]) {
sync_objs ( $channel , $arr [ 'obj' ]);
}
if ( array_key_exists ( 'likes' , $arr ) && $arr [ 'likes' ]) {
import_likes ( $channel , $arr [ 'likes' ]);
}
if ( array_key_exists ( 'app' , $arr ) && $arr [ 'app' ]) {
sync_apps ( $channel , $arr [ 'app' ]);
}
if ( array_key_exists ( 'sysapp' , $arr ) && $arr [ 'sysapp' ]) {
sync_sysapps ( $channel , $arr [ 'sysapp' ]);
}
if ( array_key_exists ( 'chatroom' , $arr ) && $arr [ 'chatroom' ]) {
sync_chatrooms ( $channel , $arr [ 'chatroom' ]);
}
if ( array_key_exists ( 'conv' , $arr ) && $arr [ 'conv' ]) {
import_conv ( $channel , $arr [ 'conv' ]);
}
if ( array_key_exists ( 'event' , $arr ) && $arr [ 'event' ]) {
sync_events ( $channel , $arr [ 'event' ]);
}
if ( array_key_exists ( 'event_item' , $arr ) && $arr [ 'event_item' ]) {
sync_items ( $channel , $arr [ 'event_item' ], (( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
}
if ( array_key_exists ( 'item' , $arr ) && $arr [ 'item' ]) {
sync_items ( $channel , $arr [ 'item' ], (( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
}
if ( array_key_exists ( 'menu' , $arr ) && $arr [ 'menu' ]) {
sync_menus ( $channel , $arr [ 'menu' ]);
}
if ( array_key_exists ( 'file' , $arr ) && $arr [ 'file' ]) {
sync_files ( $channel , $arr [ 'file' ]);
}
if ( array_key_exists ( 'wiki' , $arr ) && $arr [ 'wiki' ]) {
sync_items ( $channel , $arr [ 'wiki' ], (( array_key_exists ( 'relocate' , $arr )) ? $arr [ 'relocate' ] : null ));
}
if ( array_key_exists ( 'channel' , $arr ) && is_array ( $arr [ 'channel' ]) && count ( $arr [ 'channel' ])) {
if ( array_key_exists ( 'channel_pageflags' , $arr [ 'channel' ]) && intval ( $arr [ 'channel' ][ 'channel_pageflags' ])) {
// Several pageflags are site-specific and cannot be sync'd.
// Only allow those bits which are shareable from the remote and then
// logically OR with the local flags
$arr [ 'channel' ][ 'channel_pageflags' ] = $arr [ 'channel' ][ 'channel_pageflags' ] & ( PAGE_HIDDEN | PAGE_AUTOCONNECT | PAGE_APPLICATION | PAGE_PREMIUM | PAGE_ADULT );
$arr [ 'channel' ][ 'channel_pageflags' ] = $arr [ 'channel' ][ 'channel_pageflags' ] | $channel [ 'channel_pageflags' ];
}
$columns = db_columns ( 'channel' );
$disallowed = [
'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_prvkey' ,
'channel_address' , 'channel_notifyflags' , 'channel_removed' , 'channel_deleted' ,
'channel_system' , 'channel_r_stream' , 'channel_r_profile' , 'channel_r_abook' ,
'channel_r_storage' , 'channel_r_pages' , 'channel_w_stream' , 'channel_w_wall' ,
'channel_w_comment' , 'channel_w_mail' , 'channel_w_like' , 'channel_w_tagwall' ,
'channel_w_chat' , 'channel_w_storage' , 'channel_w_pages' , 'channel_a_republish' ,
'channel_a_delegate' , 'channel_moved'
];
foreach ( $arr [ 'channel' ] as $k => $v ) {
if ( in_array ( $k , $disallowed )) {
continue ;
}
if ( ! in_array ( $k , $columns )) {
continue ;
}
$r = dbq ( " UPDATE channel set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where channel_id = " . intval ( $channel [ 'channel_id' ]));
}
}
if ( array_key_exists ( 'abook' , $arr ) && is_array ( $arr [ 'abook' ]) && count ( $arr [ 'abook' ])) {
$total_friends = 0 ;
$total_feeds = 0 ;
2021-12-03 03:01:39 +00:00
$r = q (
" select abook_id, abook_feed from abook where abook_channel = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $channel [ 'channel_id' ])
);
if ( $r ) {
// don't count yourself
$total_friends = (( count ( $r ) > 0 ) ? count ( $r ) - 1 : 0 );
foreach ( $r as $rr ) {
if ( intval ( $rr [ 'abook_feed' ])) {
$total_feeds ++ ;
}
}
}
$disallowed = [ 'abook_id' , 'abook_account' , 'abook_channel' , 'abook_rating' , 'abook_rating_text' , 'abook_not_here' ];
$fields = db_columns ( 'abook' );
foreach ( $arr [ 'abook' ] as $abook ) {
// this is here for debugging so we can find the issue source
if ( ! is_array ( $abook )) {
btlogger ( 'abook is not an array' );
continue ;
}
$abconfig = null ;
if ( array_key_exists ( 'abconfig' , $abook ) && is_array ( $abook [ 'abconfig' ]) && count ( $abook [ 'abconfig' ])) {
2022-07-20 05:31:55 +00:00
2021-12-02 23:02:31 +00:00
$abconfig = $abook [ 'abconfig' ];
2022-07-20 05:31:55 +00:00
2021-12-02 23:02:31 +00:00
}
$clean = [];
if ( $abook [ 'abook_xchan' ] && $abook [ 'entry_deleted' ]) {
logger ( 'Removing abook entry for ' . $abook [ 'abook_xchan' ]);
2021-12-03 03:01:39 +00:00
$r = q (
" select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $abook [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
if ( $r ) {
contact_remove ( $channel [ 'channel_id' ], $r [ 0 ][ 'abook_id' ]);
if ( $total_friends ) {
$total_friends -- ;
}
if ( intval ( $r [ 0 ][ 'abook_feed' ])) {
$total_feeds -- ;
}
}
continue ;
}
// Perform discovery if the referenced xchan hasn't ever been seen on this hub.
// This relies on the undocumented behaviour that red sites send xchan info with the abook
// and import_author_xchan will look them up on all federated networks
$found = false ;
if ( $abook [ 'abook_xchan' ] && $abook [ 'xchan_addr' ] && ( ! in_array ( $abook [ 'xchan_network' ], [ 'token' , 'unknown' ]))) {
$h = Libzot :: get_hublocs ( $abook [ 'abook_xchan' ]);
if ( $h ) {
$found = true ;
} else {
$xhash = import_author_xchan ( encode_item_xchan ( $abook ));
if ( $xhash ) {
$found = true ;
} else {
logger ( 'Import of ' . $abook [ 'xchan_addr' ] . ' failed.' );
}
}
}
2021-12-06 21:19:19 +00:00
if (( ! $found ) && ( ! in_array ( $abook [ 'xchan_network' ], [ 'nomad' , 'zot6' , 'activitypub' ]))) {
2021-12-02 23:02:31 +00:00
// just import the record.
$xc = [];
foreach ( $abook as $k => $v ) {
2022-09-27 11:56:42 +00:00
if ( str_starts_with ( $k , 'xchan_' )) {
2021-12-02 23:02:31 +00:00
$xc [ $k ] = $v ;
}
}
2021-12-03 03:01:39 +00:00
$r = q (
" select * from xchan where xchan_hash = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( $xc [ 'xchan_hash' ])
);
if ( ! $r ) {
xchan_store_lowlevel ( $xc );
}
}
foreach ( $abook as $k => $v ) {
2022-09-27 11:56:42 +00:00
if ( in_array ( $k , $disallowed ) || ( ! str_starts_with ( $k , 'abook_' ))) {
2021-12-02 23:02:31 +00:00
continue ;
}
if ( ! in_array ( $k , $fields )) {
continue ;
}
$clean [ $k ] = $v ;
}
if ( ! array_key_exists ( 'abook_xchan' , $clean )) {
continue ;
}
$reconnect = false ;
2022-09-27 11:56:42 +00:00
if ( array_key_exists ( 'abook_instance' , $clean ) && $clean [ 'abook_instance' ] && ! str_contains ( $clean [ 'abook_instance' ], z_root ())) {
2021-12-02 23:02:31 +00:00
// guest pass or access token - don't try to probe since it is one-way
// we are relying on the undocumented behaviour that the abook record also contains the xchan
if ( $abook [ 'xchan_network' ] === 'token' ) {
$clean [ 'abook_instance' ] .= ',' ;
$clean [ 'abook_instance' ] .= z_root ();
$clean [ 'abook_not_here' ] = 0 ;
} else {
$clean [ 'abook_not_here' ] = 1 ;
if ( ! ( $abook [ 'abook_pending' ] || $abook [ 'abook_blocked' ])) {
$reconnect = true ;
}
}
}
2021-12-03 03:01:39 +00:00
$r = q (
" select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $clean [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
// make sure we have an abook entry for this xchan on this system
if ( ! $r ) {
if ( $max_friends !== false && $total_friends > $max_friends ) {
logger ( 'total_channels service class limit exceeded' );
continue ;
}
if ( $max_feeds !== false && intval ( $clean [ 'abook_feed' ]) && $total_feeds > $max_feeds ) {
logger ( 'total_feeds service class limit exceeded' );
continue ;
}
abook_store_lowlevel (
[
'abook_xchan' => $clean [ 'abook_xchan' ],
'abook_account' => $channel [ 'channel_account_id' ],
'abook_channel' => $channel [ 'channel_id' ]
]
);
$total_friends ++ ;
if ( intval ( $clean [ 'abook_feed' ])) {
$total_feeds ++ ;
}
}
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
if ( $k == 'abook_dob' ) {
$v = dbescdate ( $v );
}
$r = dbq ( " UPDATE abook set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where abook_xchan = ' " . dbesc ( $clean [ 'abook_xchan' ]) . " ' and abook_channel = " . intval ( $channel [ 'channel_id' ]));
}
}
// This will set abconfig vars if the sender is using old-style fixed permissions
// using the raw abook record as passed to us. New-style permissions will fall through
// and be set using abconfig
// translate_abook_perms_inbound($channel,$abook);
if ( $abconfig ) {
/// @fixme does not handle sync of del_abconfig
foreach ( $abconfig as $abc ) {
2022-05-06 05:32:09 +00:00
if ( $abc [ 'cat' ] === 'system' && $abc [ 'k' ] === 'my_perms' && $schema !== 'streams' ) {
2022-05-05 13:04:30 +00:00
$x = explode ( ',' , $abc [ 'v' ]);
if ( in_array ( 'view_stream' , $x ) && ! in_array ( 'deliver_stream' , $x )) {
2022-05-05 20:53:37 +00:00
$x [] = 'deliver_stream' ;
2022-05-05 13:04:30 +00:00
}
2022-05-05 20:17:09 +00:00
set_abconfig ( $channel [ 'channel_id' ], $abc [ 'xchan' ], $abc [ 'cat' ], $abc [ 'k' ], implode ( ',' , $x ));
2022-05-05 13:04:30 +00:00
}
else {
set_abconfig ( $channel [ 'channel_id' ], $abc [ 'xchan' ], $abc [ 'cat' ], $abc [ 'k' ], $abc [ 'v' ]);
}
2021-12-02 23:02:31 +00:00
}
}
if ( $reconnect ) {
Connect :: connect ( $channel , $abook [ 'abook_xchan' ]);
}
}
}
// sync collections (privacy groups) oh joy...
if ( array_key_exists ( 'collections' , $arr ) && is_array ( $arr [ 'collections' ]) && count ( $arr [ 'collections' ])) {
2021-12-03 03:01:39 +00:00
$x = q (
" select * from pgrp where uid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $channel [ 'channel_id' ])
);
foreach ( $arr [ 'collections' ] as $cl ) {
$found = false ;
if ( $x ) {
foreach ( $x as $y ) {
if ( $cl [ 'collection' ] == $y [ 'hash' ]) {
$found = true ;
break ;
}
}
if ( $found ) {
2021-12-03 03:01:39 +00:00
if (
( $y [ 'gname' ] != $cl [ 'name' ])
2021-12-02 23:02:31 +00:00
|| ( $y [ 'visible' ] != $cl [ 'visible' ])
2021-12-03 03:01:39 +00:00
|| ( $y [ 'deleted' ] != $cl [ 'deleted' ])
) {
q (
" update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( $cl [ 'name' ]),
intval ( $cl [ 'visible' ]),
intval ( $cl [ 'deleted' ]),
dbesc ( $cl [ 'collection' ]),
intval ( $channel [ 'channel_id' ])
);
}
if ( intval ( $cl [ 'deleted' ]) && ( ! intval ( $y [ 'deleted' ]))) {
2021-12-03 03:01:39 +00:00
q (
" delete from pgrp_member where gid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $y [ 'id' ])
);
}
}
}
if ( ! $found ) {
2021-12-03 03:01:39 +00:00
$r = q (
" INSERT INTO pgrp ( hash, uid, visible, deleted, gname, rule )
2022-07-20 05:31:55 +00:00
VALUES ( '%s' , % d , % d , % d , '%s' , '%s' ) " ,
2021-12-02 23:02:31 +00:00
dbesc ( $cl [ 'collection' ]),
intval ( $channel [ 'channel_id' ]),
intval ( $cl [ 'visible' ]),
intval ( $cl [ 'deleted' ]),
dbesc ( $cl [ 'name' ]),
dbesc ( $cl [ 'rule' ])
);
}
// now look for any collections locally which weren't in the list we just received.
// They need to be removed by marking deleted and removing the members.
// This shouldn't happen except for clones created before this function was written.
if ( $x ) {
$found_local = false ;
foreach ( $x as $y ) {
foreach ( $arr [ 'collections' ] as $cl ) {
if ( $cl [ 'collection' ] == $y [ 'hash' ]) {
$found_local = true ;
break ;
}
}
if ( ! $found_local ) {
2021-12-03 03:01:39 +00:00
q (
" delete from pgrp_member where gid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $y [ 'id' ])
);
2021-12-03 03:01:39 +00:00
q (
" update pgrp set deleted = 1 where id = %d and uid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
}
}
}
}
// reload the group list with any updates
2021-12-03 03:01:39 +00:00
$x = q (
" select * from pgrp where uid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $channel [ 'channel_id' ])
);
// now sync the members
2021-12-03 03:01:39 +00:00
if (
array_key_exists ( 'collection_members' , $arr )
2021-12-02 23:02:31 +00:00
&& is_array ( $arr [ 'collection_members' ])
2021-12-03 03:01:39 +00:00
&& count ( $arr [ 'collection_members' ])
) {
2021-12-02 23:02:31 +00:00
// first sort into groups keyed by the group hash
$members = [];
foreach ( $arr [ 'collection_members' ] as $cm ) {
if ( ! array_key_exists ( $cm [ 'collection' ], $members )) {
$members [ $cm [ 'collection' ]] = [];
}
$members [ $cm [ 'collection' ]][] = $cm [ 'member' ];
}
// our group list is already synchronised
if ( $x ) {
foreach ( $x as $y ) {
// for each group, loop on members list we just received
if ( isset ( $y [ 'hash' ]) && isset ( $members [ $y [ 'hash' ]])) {
foreach ( $members [ $y [ 'hash' ]] as $member ) {
$found = false ;
2021-12-03 03:01:39 +00:00
$z = q (
" select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ]),
dbesc ( $member )
);
if ( $z ) {
$found = true ;
}
// if somebody is in the group that wasn't before - add them
if ( ! $found ) {
2021-12-03 03:01:39 +00:00
q (
" INSERT INTO pgrp_member (uid, gid, xchan)
2022-07-20 05:31:55 +00:00
VALUES ( % d , % d , '%s' ) " ,
2021-12-02 23:02:31 +00:00
intval ( $channel [ 'channel_id' ]),
intval ( $y [ 'id' ]),
dbesc ( $member )
);
}
}
}
// now retrieve a list of members we have on this site
2021-12-03 03:01:39 +00:00
$m = q (
" select xchan from pgrp_member where gid = %d and uid = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
if ( $m ) {
foreach ( $m as $mm ) {
// if the local existing member isn't in the list we just received - remove them
if ( ! in_array ( $mm [ 'xchan' ], $members [ $y [ 'hash' ]])) {
2021-12-03 03:01:39 +00:00
q (
" delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( $mm [ 'xchan' ]),
intval ( $y [ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
}
}
}
}
}
}
}
if ( array_key_exists ( 'profile' , $arr ) && is_array ( $arr [ 'profile' ]) && count ( $arr [ 'profile' ])) {
2022-09-27 11:56:42 +00:00
$disallowed = [ 'id' , 'aid' , 'uid' , 'guid' ];
2021-12-02 23:02:31 +00:00
foreach ( $arr [ 'profile' ] as $profile ) {
2022-09-05 06:55:55 +00:00
// Multiple profiles are not supported here.
if ( ! $profile [ 'is_default' ]) {
continue ;
}
2021-12-03 03:01:39 +00:00
$x = q (
" select * from profile where profile_guid = '%s' and uid = %d limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $profile [ 'profile_guid' ]),
intval ( $channel [ 'channel_id' ])
);
if ( ! $x ) {
2022-01-25 01:26:12 +00:00
Channel :: profile_store_lowlevel (
2021-12-02 23:02:31 +00:00
[
'aid' => $channel [ 'channel_account_id' ],
'uid' => $channel [ 'channel_id' ],
'profile_guid' => $profile [ 'profile_guid' ],
]
);
2021-12-03 03:01:39 +00:00
$x = q (
" select * from profile where profile_guid = '%s' and uid = %d limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $profile [ 'profile_guid' ]),
intval ( $channel [ 'channel_id' ])
);
if ( ! $x ) {
continue ;
}
}
$clean = [];
foreach ( $profile as $k => $v ) {
if ( in_array ( $k , $disallowed )) {
continue ;
}
2022-09-05 06:55:55 +00:00
if ( in_array ( $k , [ 'photo' , 'thumb' ])) {
2021-12-02 23:02:31 +00:00
continue ;
}
if ( $k === 'name' ) {
$clean [ 'fullname' ] = $v ;
} elseif ( $k === 'with' ) {
$clean [ 'partner' ] = $v ;
} elseif ( $k === 'work' ) {
$clean [ 'employment' ] = $v ;
} elseif ( array_key_exists ( $k , $x [ 0 ])) {
$clean [ $k ] = $v ;
}
/**
* @ TODO
* We also need to import local photos if a custom photo is selected
*/
2022-09-05 06:55:55 +00:00
$profile [ 'photo' ] = z_root () . '/photo/profile/l/' . $channel [ 'channel_id' ];
$profile [ 'thumb' ] = z_root () . '/photo/profile/m/' . $channel [ 'channel_id' ];
2021-12-02 23:02:31 +00:00
}
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
$r = dbq ( " UPDATE profile set " . TQUOT . dbesc ( $k ) . TQUOT . " = ' " . dbesc ( $v )
. " ' where profile_guid = ' " . dbesc ( $profile [ 'profile_guid' ])
. " ' and uid = " . intval ( $channel [ 'channel_id' ]));
}
}
}
}
$addon = [ 'channel' => $channel , 'data' => $arr ];
/**
* @ hooks process_channel_sync_delivery
* Called when accepting delivery of a 'sync packet' containing structure and table updates from a channel clone .
* * \e array \b channel
* * \e array \b data
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'process_channel_sync_delivery' , $addon );
2021-12-02 23:02:31 +00:00
$DR = new DReport ( z_root (), $d , $d , 'sync' , 'channel sync delivered' );
2022-01-25 01:26:12 +00:00
$DR -> set_name ( $channel [ 'channel_name' ] . ' <' . Channel :: get_webfinger ( $channel ) . '>' );
2021-12-02 23:02:31 +00:00
$result [] = $DR -> get ();
}
return $result ;
}
/**
* @ brief Synchronises locations .
*
* @ param array $sender
* @ param array $arr
* @ return array
*/
2022-06-07 01:55:58 +00:00
public static function sync_locations ( $sender , $arr )
2021-12-02 23:02:31 +00:00
{
$ret = [];
$what = EMPTY_STR ;
$changed = false ;
// If a sender reports that the channel has been deleted, delete its hubloc
if ( isset ( $arr [ 'deleted_locally' ]) && intval ( $arr [ 'deleted_locally' ])) {
2021-12-03 03:01:39 +00:00
q (
" UPDATE hubloc SET hubloc_deleted = 1, hubloc_updated = '%s' WHERE hubloc_hash = '%s' AND hubloc_url = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
dbesc ( $sender [ 'hash' ]),
dbesc ( $sender [ 'site' ][ 'url' ])
);
}
if ( $arr [ 'locations' ]) {
2021-12-03 03:01:39 +00:00
$x = q (
" select * from xchan where xchan_hash = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender [ 'hash' ])
);
if ( $x ) {
$xchan = array_shift ( $x );
}
2022-09-25 08:57:14 +00:00
// Libzot::check_location_move($sender['hash'], $arr['locations']);
2022-07-20 05:31:55 +00:00
2022-09-27 11:56:42 +00:00
$existing = q (
2022-06-17 02:46:54 +00:00
" select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender [ 'hash' ])
);
2022-09-27 11:56:42 +00:00
if ( ! $existing ) {
$existing = [];
2021-12-02 23:02:31 +00:00
}
// See if a primary is specified
$has_primary = false ;
foreach ( $arr [ 'locations' ] as $location ) {
if ( $location [ 'primary' ]) {
$has_primary = true ;
break ;
}
}
// Ensure that they have one primary hub
2021-12-03 03:01:39 +00:00
if ( ! $has_primary ) {
2021-12-02 23:02:31 +00:00
$arr [ 'locations' ][ 0 ][ 'primary' ] = true ;
2021-12-03 03:01:39 +00:00
}
2021-12-02 23:02:31 +00:00
foreach ( $arr [ 'locations' ] as $location ) {
2021-12-06 21:19:19 +00:00
$network = isset ( $location [ 'driver' ]) ? $location [ 'driver' ] : 'zot6' ;
// only set nomad if the location info is coming from the same site as the original zotinfo packet
if ( isset ( $sender [ 'site' ]) && isset ( $sender [ 'site' ][ 'url' ]) && $sender [ 'site' ][ 'url' ] === $location [ 'url' ]) {
2022-07-20 05:31:55 +00:00
if ( isset ( $sender [ 'site' ][ 'protocol_version' ]) && intval ( $sender [ 'site' ][ 'protocol_version' ]) > 10 ) {
2021-12-06 21:19:19 +00:00
$network = 'nomad' ;
}
}
2022-07-20 05:31:55 +00:00
2021-12-02 23:02:31 +00:00
if ( ! Libzot :: verify ( $location [ 'url' ], $location [ 'url_sig' ], $sender [ 'public_key' ])) {
logger ( 'Unable to verify site signature for ' . $location [ 'url' ]);
$ret [ 'message' ] .= sprintf ( t ( 'Unable to verify site signature for %s' ), $location [ 'url' ]) . EOL ;
continue ;
}
2022-09-27 11:56:42 +00:00
for ( $x = 0 ; $x < count ( $existing ); $x ++ ) {
2021-12-03 03:01:39 +00:00
if (
2022-09-27 11:56:42 +00:00
( $existing [ $x ][ 'hubloc_url' ] === $location [ 'url' ])
&& ( $existing [ $x ][ 'hubloc_sitekey' ] === $location [ 'sitekey' ])
2021-12-03 03:01:39 +00:00
) {
2022-09-27 11:56:42 +00:00
$existing [ $x ][ 'updated' ] = true ;
2021-12-02 23:02:31 +00:00
}
}
if ( ! $location [ 'sitekey' ]) {
logger ( 'Empty hubloc sitekey. ' . print_r ( $location , true ));
continue ;
}
// match as many fields as possible in case anything at all changed.
2021-12-03 03:01:39 +00:00
$r = q (
2022-06-17 02:46:54 +00:00
" select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%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' and hubloc_deleted = 0 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender [ 'hash' ]),
dbesc ( $sender [ 'id' ]),
dbesc ( $sender [ 'id_sig' ]),
dbesc ( $location [ 'id_url' ]),
dbesc ( $location [ 'url' ]),
dbesc ( $location [ 'url_sig' ]),
dbesc ( $location [ 'host' ]),
dbesc ( $location [ 'address' ]),
dbesc ( $location [ 'callback' ]),
dbesc ( $location [ 'sitekey' ])
);
if ( $r ) {
logger ( 'Hub exists: ' . $location [ 'url' ], LOGGER_DEBUG );
// generate a new hubloc_site_id if it's wrong due to historical bugs 2021-11-30
if ( $r [ 0 ][ 'hubloc_site_id' ] !== $location [ 'site_id' ]) {
2021-12-03 03:01:39 +00:00
q (
" update hubloc set hubloc_site_id = '%s' where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( Libzot :: make_xchan_hash ( $location [ 'url' ], $location [ 'sitekey' ])),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
}
// update connection timestamp if this is the site we're talking to
// This only happens when called from import_xchan
$current_site = false ;
$t = datetime_convert ( 'UTC' , 'UTC' , 'now - 15 minutes' );
2021-12-06 21:19:19 +00:00
if ( isset ( $location [ 'driver' ]) && $location [ 'driver' ] === 'nomad' && $location [ 'driver' ] !== $r [ 0 ][ 'hubloc_network' ]) {
q ( " update hubloc set hubloc_network = '%s' where hubloc_id = %d " ,
dbesc ( $location [ 'driver' ]),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
2022-09-04 03:15:54 +00:00
}
if ( isset ( $location [ 'callback' ]) && $location [ 'callback' ] !== $r [ 0 ][ 'hubloc_callback' ]) {
q ( " update hubloc set hubloc_callback = '%s' where hubloc_id = %d " ,
dbesc ( $location [ 'callback' ]),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
2022-07-20 05:31:55 +00:00
}
2021-12-06 21:19:19 +00:00
2021-12-02 23:02:31 +00:00
if ( array_key_exists ( 'site' , $arr ) && $location [ 'url' ] == $arr [ 'site' ][ 'url' ]) {
2021-12-03 03:01:39 +00:00
q (
" update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_updated < '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ]),
dbesc ( $t )
);
$current_site = true ;
}
if ( $current_site && ( intval ( $r [ 0 ][ 'hubloc_error' ]) || intval ( $r [ 0 ][ 'hubloc_deleted' ]))) {
2021-12-03 03:01:39 +00:00
q (
" update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $r [ 0 ][ 'hubloc_id' ])
);
if ( intval ( $r [ 0 ][ 'hubloc_orphancheck' ])) {
2021-12-03 03:01:39 +00:00
q (
" update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $r [ 0 ][ 'hubloc_id' ])
);
}
2021-12-03 03:01:39 +00:00
q (
" update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( $sender [ 'hash' ])
);
}
// Remove pure duplicates
if ( count ( $r ) > 1 ) {
for ( $h = 1 ; $h < count ( $r ); $h ++ ) {
2021-12-03 03:01:39 +00:00
q (
" delete from hubloc where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $r [ $h ][ 'hubloc_id' ])
);
$what .= 'duplicate_hubloc_removed ' ;
$changed = true ;
}
}
if ( intval ( $r [ 0 ][ 'hubloc_primary' ]) && ( ! $location [ 'primary' ])) {
2021-12-03 03:01:39 +00:00
$m = q (
" update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
$r [ 0 ][ 'hubloc_primary' ] = intval ( $location [ 'primary' ]);
hubloc_change_primary ( $r [ 0 ]);
$what .= 'primary_hub ' ;
$changed = true ;
} elseif (( ! intval ( $r [ 0 ][ 'hubloc_primary' ])) && ( $location [ 'primary' ])) {
2021-12-03 03:01:39 +00:00
$m = q (
" update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
// make sure hubloc_change_primary() has current data
$r [ 0 ][ 'hubloc_primary' ] = intval ( $location [ 'primary' ]);
hubloc_change_primary ( $r [ 0 ]);
$what .= 'primary_hub ' ;
$changed = true ;
} elseif ( intval ( $r [ 0 ][ 'hubloc_primary' ]) && $xchan && $xchan [ 'xchan_url' ] !== $r [ 0 ][ 'hubloc_id_url' ]) {
$pr = hubloc_change_primary ( $r [ 0 ]);
if ( $pr ) {
$what .= 'xchan_primary ' ;
$changed = true ;
}
}
if ( intval ( $r [ 0 ][ 'hubloc_deleted' ]) && ( ! intval ( $location [ 'deleted' ]))) {
2021-12-03 03:01:39 +00:00
$n = q (
" update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
intval ( $r [ 0 ][ 'hubloc_id' ])
);
$what .= 'undelete_hub ' ;
$changed = true ;
} elseif (( ! intval ( $r [ 0 ][ 'hubloc_deleted' ])) && ( intval ( $location [ 'deleted' ]))) {
logger ( 'deleting hubloc: ' . $r [ 0 ][ 'hubloc_addr' ]);
2022-06-18 02:24:50 +00:00
hubloc_delete ( $r [ 0 ]);
2021-12-02 23:02:31 +00:00
$what .= 'delete_hub ' ;
$changed = true ;
}
continue ;
}
// Existing hubs are dealt with. Now let's process any new ones.
// New hub claiming to be primary. Make it so by removing any existing primaries.
if ( intval ( $location [ 'primary' ])) {
2021-12-03 03:01:39 +00:00
$r = q (
" update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( datetime_convert ()),
dbesc ( $sender [ 'hash' ])
);
}
logger ( 'New hub: ' . $location [ 'url' ]);
$r = hubloc_store_lowlevel (
[
'hubloc_guid' => $sender [ 'id' ],
'hubloc_guid_sig' => $sender [ 'id_sig' ],
'hubloc_id_url' => $location [ 'id_url' ],
'hubloc_hash' => $sender [ 'hash' ],
'hubloc_addr' => $location [ 'address' ],
2021-12-06 21:19:19 +00:00
'hubloc_network' => $network ,
2021-12-02 23:02:31 +00:00
'hubloc_primary' => intval ( $location [ 'primary' ]),
'hubloc_url' => $location [ 'url' ],
'hubloc_url_sig' => $location [ 'url_sig' ],
'hubloc_site_id' => Libzot :: make_xchan_hash ( $location [ 'url' ], $location [ 'sitekey' ]),
'hubloc_host' => $location [ 'host' ],
'hubloc_callback' => $location [ 'callback' ],
'hubloc_sitekey' => $location [ 'sitekey' ],
'hubloc_updated' => datetime_convert (),
'hubloc_connected' => datetime_convert ()
]
);
$what .= 'newhub ' ;
$changed = true ;
if ( $location [ 'primary' ]) {
2022-09-27 11:56:42 +00:00
$result = q (
2021-12-03 03:01:39 +00:00
" select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $location [ 'address' ]),
dbesc ( $location [ 'sitekey' ])
);
2022-09-27 11:56:42 +00:00
if ( $result ) {
hubloc_change_primary ( array_shift ( $result )); }
2021-12-02 23:02:31 +00:00
}
}
// get rid of any hubs we have for this channel which weren't reported.
2022-09-27 11:56:42 +00:00
if ( $existing ) {
foreach ( $existing as $x ) {
2021-12-02 23:02:31 +00:00
if ( ! array_key_exists ( 'updated' , $x )) {
logger ( 'Deleting unreferenced hub location ' . $x [ 'hubloc_addr' ]);
2022-06-18 02:24:50 +00:00
hubloc_delete ( $x );
2021-12-02 23:02:31 +00:00
$what .= 'removed_hub ' ;
$changed = true ;
}
}
}
} else {
logger ( 'No locations to sync!' );
}
$ret [ 'change_message' ] = $what ;
$ret [ 'changed' ] = $changed ;
return $ret ;
}
public static function keychange ( $channel , $arr )
{
// verify the keychange operation
if ( ! Libzot :: verify ( $arr [ 'channel' ][ 'channel_pubkey' ], $arr [ 'keychange' ][ 'new_sig' ], $channel [ 'channel_prvkey' ])) {
logger ( 'sync keychange: verification failed' );
return ;
}
$sig = Libzot :: sign ( $channel [ 'channel_guid' ], $arr [ 'channel' ][ 'channel_prvkey' ]);
$hash = Libzot :: make_xchan_hash ( $channel [ 'channel_guid' ], $arr [ 'channel' ][ 'channel_pubkey' ]);
2021-12-03 03:01:39 +00:00
$r = q (
" update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s',
2022-07-20 05:31:55 +00:00
channel_hash = '%s' where channel_id = % d " ,
2021-12-02 23:02:31 +00:00
dbesc ( $arr [ 'channel' ][ 'channel_prvkey' ]),
dbesc ( $arr [ 'channel' ][ 'channel_pubkey' ]),
dbesc ( $sig ),
dbesc ( $hash ),
intval ( $channel [ 'channel_id' ])
);
if ( ! $r ) {
logger ( 'keychange sync: channel update failed' );
return ;
}
2021-12-03 03:01:39 +00:00
$r = q (
" select * from channel where channel_id = %d " ,
2021-12-02 23:02:31 +00:00
intval ( $channel [ 'channel_id' ])
);
if ( ! $r ) {
logger ( 'keychange sync: channel retrieve failed' );
return ;
}
$channel = $r [ 0 ];
2021-12-03 03:01:39 +00:00
$h = q (
2022-06-17 02:46:54 +00:00
" select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' and hubloc_deleted = 0 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $arr [ 'keychange' ][ 'old_hash' ]),
dbesc ( z_root ())
);
if ( $h ) {
foreach ( $h as $hv ) {
$hv [ 'hubloc_guid_sig' ] = $sig ;
$hv [ 'hubloc_hash' ] = $hash ;
$hv [ 'hubloc_url_sig' ] = Libzot :: sign ( z_root (), $channel [ 'channel_prvkey' ]);
hubloc_store_lowlevel ( $hv );
}
}
2021-12-03 03:01:39 +00:00
$x = q (
" select * from xchan where xchan_hash = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( $arr [ 'keychange' ][ 'old_hash' ])
);
2021-12-03 03:01:39 +00:00
$check = q (
" select * from xchan where xchan_hash = '%s' " ,
2021-12-02 23:02:31 +00:00
dbesc ( $hash )
);
if (( $x ) && ( ! $check )) {
$oldxchan = $x [ 0 ];
foreach ( $x as $xv ) {
$xv [ 'xchan_guid_sig' ] = $sig ;
$xv [ 'xchan_hash' ] = $hash ;
$xv [ 'xchan_pubkey' ] = $channel [ 'channel_pubkey' ];
$xv [ 'xchan_updated' ] = datetime_convert ();
xchan_store_lowlevel ( $xv );
$newxchan = $xv ;
}
}
2021-12-03 03:01:39 +00:00
$a = q (
" select * from abook where abook_xchan = '%s' and abook_self = 1 " ,
2021-12-02 23:02:31 +00:00
dbesc ( $arr [ 'keychange' ][ 'old_hash' ])
);
if ( $a ) {
2021-12-03 03:01:39 +00:00
q (
" update abook set abook_xchan = '%s' where abook_id = %d " ,
2021-12-02 23:02:31 +00:00
dbesc ( $hash ),
intval ( $a [ 0 ][ 'abook_id' ])
);
}
2022-11-20 06:44:13 +00:00
xchan_change_key ( $oldxchan , $newxchan );
2021-12-02 23:02:31 +00:00
}
2021-12-03 03:01:39 +00:00
}