2013-02-26 01:09:40 +00:00
< ? php /** @file */
2012-07-29 00:21:42 +00:00
2012-11-13 04:59:18 +00:00
require_once ( 'include/crypto.php' );
2012-11-27 05:20:16 +00:00
require_once ( 'include/items.php' );
2013-11-29 02:10:04 +00:00
/**
* Red implementation of zot protocol .
*
* https :// github . com / friendica / red / wiki / zot
* https :// github . com / friendica / red / wiki / Zot --- A - High - Level - Overview
*
*/
2012-07-29 00:21:42 +00:00
/**
*
2012-09-26 00:57:20 +00:00
* @ function zot_new_uid ( $channel_nick )
2013-11-29 01:47:33 +00:00
*
* Generates a unique string for use as a zot guid using our DNS - based url , the channel nickname and some entropy .
* The entropy ensures uniqueness against re - installs where the same URL and nickname are chosen .
* NOTE : zot doesn ' t require this to be unique . Internally we use a whirlpool hash of this guid and the signature
* of this guid signed with the channel private key . This can be verified and should make the probability of
* collision of the verified result negligible within the constraints of our immediate universe .
*
* @ param string channel_nickname = unique nickname of controlling entity
*
2012-07-29 00:21:42 +00:00
* @ returns string
*
*/
2012-09-26 00:57:20 +00:00
function zot_new_uid ( $channel_nick ) {
$rawstr = z_root () . '/' . $channel_nick . '.' . mt_rand ();
2012-08-27 06:05:00 +00:00
return ( base64url_encode ( hash ( 'whirlpool' , $rawstr , true ), true ));
2012-07-29 00:21:42 +00:00
}
/**
2013-11-27 10:51:16 +00:00
* @ function zot_get_hublocs ( $hash )
2013-11-29 00:46:47 +00:00
* Given a zot hash , return all distinct hubs .
* This function is used in building the zot discovery packet
2013-11-29 01:47:33 +00:00
* and therefore should only be used by channels which are defined
* on this hub
2013-11-27 10:51:16 +00:00
* @ param string $hash - xchan_hash
2013-11-29 01:47:33 +00:00
* @ retuns array of hubloc ( hub location structures )
* hubloc_id int
* hubloc_guid char ( 255 )
* hubloc_guid_sig text
* hubloc_hash char ( 255 )
* hubloc_addr char ( 255 )
* hubloc_flags int
* hubloc_status int
* hubloc_url char ( 255 )
* hubloc_url_sig text
* hubloc_host char ( 255 )
* hubloc_callback char ( 255 )
* hubloc_connect char ( 255 )
* hubloc_sitekey text
* hubloc_updated datetime
* hubloc_connected datetime
2012-07-29 00:21:42 +00:00
*
*/
2013-11-27 10:51:16 +00:00
function zot_get_hublocs ( $hash ) {
2012-07-29 00:21:42 +00:00
2013-11-29 00:46:47 +00:00
/** Only search for active hublocs - e.g. those that haven't been marked deleted */
2012-07-29 00:21:42 +00:00
2013-11-29 00:46:47 +00:00
$ret = q ( " select * from hubloc where hubloc_hash = '%s' and not ( hubloc_flags & %d ) group by hubloc_url " ,
dbesc ( $hash ),
intval ( HUBLOC_FLAGS_DELETED )
);
2013-11-27 10:51:16 +00:00
return $ret ;
2012-07-29 00:21:42 +00:00
}
2013-11-29 01:47:33 +00:00
/**
*
* @ function zot_build_packet ( $channel , $type = 'notify' , $recipients = null , $remote_key = null , $secret = null )
* builds a zot notification packet that you can either
* store in the queue with a message array or call zot_zot to immediately
* zot it to the other side
2012-11-15 03:27:16 +00:00
*
2013-11-29 01:47:33 +00:00
* @ param array $channel => sender channel structure
2014-02-11 22:19:20 +00:00
* @ param string $type => packet type : one of 'ping' , 'pickup' , 'purge' , 'refresh' , 'force_refresh' , 'notify' , 'auth_check'
2013-11-29 02:46:59 +00:00
* @ param array $recipients => envelope information , array ( 'guid' => string , 'guid_sig' => string ); empty for public posts
2013-11-29 01:47:33 +00:00
* @ param string $remote_key => optional public site key of target hub used to encrypt entire packet
* NOTE : remote_key and encrypted packets are required for 'auth_check' packets , optional for all others
* @ param string $secret => random string , required for packets which require verification / callback
2014-02-11 22:19:20 +00:00
* e . g . 'pickup' , 'purge' , 'notify' , 'auth_check' . Packet types 'ping' , 'force_refresh' , and 'refresh' do not require verification
2012-11-15 03:27:16 +00:00
*
2013-11-29 01:47:33 +00:00
* @ returns string json encoded zot packet
2012-11-15 03:27:16 +00:00
*/
2012-11-19 03:19:16 +00:00
function zot_build_packet ( $channel , $type = 'notify' , $recipients = null , $remote_key = null , $secret = null ) {
2012-11-15 03:27:16 +00:00
$data = array (
'type' => $type ,
'sender' => array (
'guid' => $channel [ 'channel_guid' ],
'guid_sig' => base64url_encode ( rsa_sign ( $channel [ 'channel_guid' ], $channel [ 'channel_prvkey' ])),
'url' => z_root (),
'url_sig' => base64url_encode ( rsa_sign ( z_root (), $channel [ 'channel_prvkey' ]))
),
'callback' => '/post' ,
'version' => ZOT_REVISION
);
if ( $recipients )
$data [ 'recipients' ] = $recipients ;
2013-01-22 03:16:21 +00:00
if ( $secret ) {
2012-11-19 03:19:16 +00:00
$data [ 'secret' ] = $secret ;
2013-01-22 03:16:21 +00:00
$data [ 'secret_sig' ] = base64url_encode ( rsa_sign ( $secret , $channel [ 'channel_prvkey' ]));
}
2012-11-19 03:19:16 +00:00
2013-01-25 03:45:08 +00:00
logger ( 'zot_build_packet: ' . print_r ( $data , true ), LOGGER_DATA );
2012-11-27 11:08:26 +00:00
2012-11-15 03:27:16 +00:00
// Hush-hush ultra top-secret mode
if ( $remote_key ) {
2013-11-20 23:20:12 +00:00
$data = crypto_encapsulate ( json_encode ( $data ), $remote_key );
2012-11-15 03:27:16 +00:00
}
return json_encode ( $data );
}
2013-03-26 04:32:12 +00:00
/**
* @ function : zot_zot
* @ param : string $url
* @ param : array $data
*
* @ returns : array => see z_post_url for returned data format
*/
2012-11-15 03:27:16 +00:00
function zot_zot ( $url , $data ) {
return z_post_url ( $url , array ( 'data' => $data ));
}
2013-03-26 04:32:12 +00:00
/**
* @ function : zot_finger
*
* Look up information about channel
* @ param : string $webbie
* does not have to be host qualified e . g . 'foo' is treated as 'foo@thishub'
* @ param : array $channel
* ( optional ), if supplied permissions will be enumerated specifically for $channel
2013-10-03 05:59:58 +00:00
* @ param : boolean $autofallback
* fallback / failover to http if https connection cannot be established . Default is true .
2013-03-26 04:32:12 +00:00
*
* @ returns : array => see z_post_url and mod / zfinger . php
*/
2013-10-02 05:20:09 +00:00
function zot_finger ( $webbie , $channel , $autofallback = true ) {
2012-11-01 03:53:02 +00:00
2012-11-01 04:42:20 +00:00
2012-11-01 03:53:02 +00:00
if ( strpos ( $webbie , '@' ) === false ) {
$address = $webbie ;
$host = get_app () -> get_hostname ();
}
else {
$address = substr ( $webbie , 0 , strpos ( $webbie , '@' ));
$host = substr ( $webbie , strpos ( $webbie , '@' ) + 1 );
}
$xchan_addr = $address . '@' . $host ;
2013-07-22 05:39:21 +00:00
if (( ! $address ) || ( ! $xchan_addr )) {
logger ( 'zot_finger: no address :' . $webbie );
return array ( 'success' => false );
}
2012-11-01 03:53:02 +00:00
$r = q ( " select xchan.*, hubloc.* from xchan
left join hubloc on xchan_hash = hubloc_hash
where xchan_addr = '%s' and ( hubloc_flags & % d ) limit 1 " ,
2013-08-26 03:11:49 +00:00
dbesc ( $xchan_addr ),
2012-11-01 03:53:02 +00:00
intval ( HUBLOC_FLAGS_PRIMARY )
);
if ( $r ) {
$url = $r [ 0 ][ 'hubloc_url' ];
}
else {
$url = 'https://' . $host ;
}
2012-11-11 07:26:12 +00:00
$rhs = '/.well-known/zot-info' ;
2013-02-14 04:09:30 +00:00
$https = (( strpos ( $url , 'https://' ) === 0 ) ? true : false );
2012-11-01 03:53:02 +00:00
2013-07-22 04:54:20 +00:00
logger ( 'zot_finger: ' . $address . ' at ' . $url , LOGGER_DEBUG );
2013-01-12 23:55:37 +00:00
2012-11-01 03:53:02 +00:00
if ( $channel ) {
$postvars = array (
2012-11-02 22:34:35 +00:00
'address' => $address ,
'target' => $channel [ 'channel_guid' ],
'target_sig' => $channel [ 'channel_guid_sig' ],
'key' => $channel [ 'channel_pubkey' ]
2012-11-01 03:53:02 +00:00
);
2013-01-12 23:55:37 +00:00
2012-11-01 03:53:02 +00:00
$result = z_post_url ( $url . $rhs , $postvars );
2013-02-14 04:09:30 +00:00
2013-10-02 05:20:09 +00:00
if (( ! $result [ 'success' ]) && ( $autofallback )) {
2013-02-14 04:09:30 +00:00
if ( $https ) {
logger ( 'zot_finger: https failed. falling back to http' );
$result = z_post_url ( 'http://' . $host . $rhs , $postvars );
}
}
2012-11-01 03:53:02 +00:00
}
else {
2013-01-12 23:55:37 +00:00
$rhs .= '?f=&address=' . urlencode ( $address );
2012-11-01 03:53:02 +00:00
$result = z_fetch_url ( $url . $rhs );
2013-10-02 05:20:09 +00:00
if (( ! $result [ 'success' ]) && ( $autofallback )) {
2013-02-14 04:09:30 +00:00
if ( $https ) {
logger ( 'zot_finger: https failed. falling back to http' );
$result = z_fetch_url ( 'http://' . $host . $rhs );
}
}
2012-11-01 03:53:02 +00:00
}
2013-02-14 04:09:30 +00:00
if ( ! $result [ 'success' ])
logger ( 'zot_finger: no results' );
2012-11-01 03:53:02 +00:00
return $result ;
}
2013-03-26 04:32:12 +00:00
/**
2014-02-11 22:19:20 +00:00
* @ function : zot_refresh ( $them , $channel = null , $force = false )
2013-03-26 04:32:12 +00:00
*
2013-11-29 02:46:59 +00:00
* zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
* to fetch new permissions via a finger / discovery operation . This may result in a new connection
* ( abook entry ) being added to a local channel and it may result in auto - permissions being granted .
*
* Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a
* permission change has been made by the sender which affects the target channel . The hub controlling
* the target channel does targetted discovery ( a zot - finger request requesting permissions for the local
* channel ) . These are decoded here , and if necessary and abook structure ( addressbook ) is created to store
* the permissions assigned to this channel .
*
* Initially these abook structures are created with a 'pending' flag , so that no reverse permissions are
* implied until this is approved by the owner channel . A channel can also auto - populate permissions in
* return and send back a refresh packet of its own . This is used by forum and group communication channels
* so that friending and membership in the channel ' s " club " is automatic .
*
* @ param array $them => xchan structure of sender
* @ param array $channel => local channel structure of target recipient , required for " friending " operations
2013-03-26 04:32:12 +00:00
*
2013-11-29 02:46:59 +00:00
* @ returns boolean true if successful , else false
2013-03-26 04:32:12 +00:00
*/
2014-02-11 22:19:20 +00:00
function zot_refresh ( $them , $channel = null , $force = false ) {
2012-11-11 04:08:07 +00:00
2012-12-30 23:28:13 +00:00
logger ( 'zot_refresh: them: ' . print_r ( $them , true ), LOGGER_DATA );
2013-01-03 09:53:22 +00:00
if ( $channel )
logger ( 'zot_refresh: channel: ' . print_r ( $channel , true ), LOGGER_DATA );
2012-12-30 23:28:13 +00:00
2012-11-11 04:08:07 +00:00
if ( $them [ 'hubloc_url' ])
$url = $them [ 'hubloc_url' ];
else {
2013-01-04 00:30:35 +00:00
$r = q ( " select hubloc_url from hubloc where hubloc_hash = '%s' and ( hubloc_flags & %d ) limit 1 " ,
2012-11-11 04:08:07 +00:00
dbesc ( $them [ 'xchan_hash' ]),
intval ( HUBLOC_FLAGS_PRIMARY )
);
if ( $r )
$url = $r [ 0 ][ 'hubloc_url' ];
}
2012-12-30 23:28:13 +00:00
if ( ! $url ) {
logger ( 'zot_refresh: no url' );
2012-12-31 06:41:53 +00:00
return false ;
2012-12-30 23:28:13 +00:00
}
2012-11-11 04:08:07 +00:00
2012-11-13 00:16:37 +00:00
$postvars = array ();
if ( $channel ) {
$postvars [ 'target' ] = $channel [ 'channel_guid' ];
$postvars [ 'target_sig' ] = $channel [ 'channel_guid_sig' ];
$postvars [ 'key' ] = $channel [ 'channel_pubkey' ];
}
if ( array_key_exists ( 'xchan_addr' , $them ) && $them [ 'xchan_addr' ])
$postvars [ 'address' ] = $them [ 'xchan_addr' ];
if ( array_key_exists ( 'xchan_hash' , $them ) && $them [ 'xchan_hash' ])
$postvars [ 'guid_hash' ] = $them [ 'xchan_hash' ];
if ( array_key_exists ( 'xchan_guid' , $them ) && $them [ 'xchan_guid' ]
&& array_key_exists ( 'xchan_guid_sig' , $them ) && $them [ 'xchan_guid_sig' ]) {
$postvars [ 'guid' ] = $them [ 'xchan_guid' ];
$postvars [ 'guid_sig' ] = $them [ 'xchan_guid_sig' ];
}
2012-11-11 07:26:12 +00:00
$rhs = '/.well-known/zot-info' ;
2012-11-11 04:08:07 +00:00
$result = z_post_url ( $url . $rhs , $postvars );
2013-01-25 03:45:08 +00:00
logger ( 'zot_refresh: zot-info: ' . print_r ( $result , true ), LOGGER_DATA );
2013-01-04 00:39:22 +00:00
2012-11-11 04:08:07 +00:00
if ( $result [ 'success' ]) {
2012-11-20 00:51:15 +00:00
$j = json_decode ( $result [ 'body' ], true );
2012-11-11 04:08:07 +00:00
2013-02-02 11:11:23 +00:00
if ( ! (( $j ) && ( $j [ 'success' ]))) {
logger ( 'zot_refresh: result not decodable' );
2013-01-26 23:50:31 +00:00
return false ;
2013-02-02 11:11:23 +00:00
}
2013-01-26 23:50:31 +00:00
2014-02-11 22:19:20 +00:00
$x = import_xchan ( $j ,(( $force ) ? ( - 1 ) : 1 ));
2012-11-11 04:08:07 +00:00
2013-01-26 23:50:31 +00:00
if ( ! $x [ 'success' ])
return false ;
2012-11-11 04:08:07 +00:00
$xchan_hash = $x [ 'hash' ];
$their_perms = 0 ;
2012-11-13 00:16:37 +00:00
if ( $channel ) {
$global_perms = get_perms ();
2012-11-20 00:51:15 +00:00
if ( $j [ 'permissions' ][ 'data' ]) {
2013-11-20 23:20:12 +00:00
$permissions = crypto_unencapsulate ( array (
2012-11-20 00:51:15 +00:00
'data' => $j [ 'permissions' ][ 'data' ],
'key' => $j [ 'permissions' ][ 'key' ],
'iv' => $j [ 'permissions' ][ 'iv' ]),
2012-11-13 00:16:37 +00:00
$channel [ 'channel_prvkey' ]);
if ( $permissions )
2012-11-20 00:51:15 +00:00
$permissions = json_decode ( $permissions , true );
2012-11-13 00:16:37 +00:00
logger ( 'decrypted permissions: ' . print_r ( $permissions , true ), LOGGER_DATA );
}
else
2012-11-20 00:51:15 +00:00
$permissions = $j [ 'permissions' ];
2012-11-13 00:16:37 +00:00
2013-01-02 09:44:50 +00:00
if ( $permissions && is_array ( $permissions )) {
foreach ( $permissions as $k => $v ) {
if ( $v ) {
$their_perms = $their_perms | intval ( $global_perms [ $k ][ 1 ]);
}
2012-11-13 00:16:37 +00:00
}
2012-11-11 04:08:07 +00:00
}
2012-11-30 07:06:03 +00:00
2012-12-02 06:37:41 +00:00
$r = q ( " select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1 " ,
2012-11-13 09:42:08 +00:00
dbesc ( $x [ 'hash' ]),
intval ( $channel [ 'channel_id' ]),
2012-12-02 06:37:41 +00:00
intval ( ABOOK_FLAG_SELF )
2012-11-13 00:16:37 +00:00
);
2013-02-07 22:49:09 +00:00
2012-11-30 02:15:13 +00:00
if ( $r ) {
2013-02-07 22:49:09 +00:00
$y = q ( " update abook set abook_their_perms = %d
2012-11-30 02:15:13 +00:00
where abook_xchan = '%s' and abook_channel = % d
2012-12-02 06:37:41 +00:00
and not ( abook_flags & % d ) limit 1 " ,
2012-11-30 02:15:13 +00:00
intval ( $their_perms ),
dbesc ( $x [ 'hash' ]),
intval ( $channel [ 'channel_id' ]),
2012-12-02 06:37:41 +00:00
intval ( ABOOK_FLAG_SELF )
2012-11-30 02:15:13 +00:00
);
if ( ! $y )
logger ( 'abook update failed' );
2013-11-18 00:50:32 +00:00
else {
// if we were just granted read stream permission and didn't have it before, try to pull in some posts
if (( ! ( $r [ 0 ][ 'abook_their_perms' ] & PERMS_R_STREAM )) && ( $their_perms & PERMS_R_STREAM ))
proc_run ( 'php' , 'include/onepoll.php' , $r [ 0 ][ 'abook_id' ]);
}
2012-11-30 02:15:13 +00:00
}
else {
2012-12-02 06:37:41 +00:00
$default_perms = 0 ;
// look for default permissions to apply in return - e.g. auto-friend
$z = q ( " select * from abook where abook_channel = %d and (abook_flags & %d) limit 1 " ,
intval ( $channel [ 'channel_id' ]),
intval ( ABOOK_FLAG_SELF )
);
2013-02-07 22:49:09 +00:00
2012-12-02 06:37:41 +00:00
if ( $z )
2013-02-07 22:49:09 +00:00
$default_perms = intval ( $z [ 0 ][ 'abook_my_perms' ]);
2012-12-02 06:37:41 +00:00
2013-01-03 09:53:22 +00:00
$y = q ( " insert into abook ( abook_account, abook_channel, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_flags ) values ( %d, %d, '%s', %d, %d, '%s', '%s', %d ) " ,
2012-11-30 02:15:13 +00:00
intval ( $channel [ 'channel_account_id' ]),
intval ( $channel [ 'channel_id' ]),
dbesc ( $x [ 'hash' ]),
intval ( $their_perms ),
2012-12-02 06:37:41 +00:00
intval ( $default_perms ),
2012-11-30 02:15:13 +00:00
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
2012-12-20 00:48:17 +00:00
intval (( $default_perms ) ? 0 : ABOOK_FLAG_PENDING )
2012-11-30 02:15:13 +00:00
);
2013-02-07 22:49:09 +00:00
2012-12-02 06:37:41 +00:00
if ( $y ) {
2012-11-30 02:15:13 +00:00
logger ( " New introduction received for { $channel [ 'channel_name' ] } " );
2012-12-02 06:37:41 +00:00
if ( $default_perms ) {
// send back a permissions update for auto-friend/auto-permissions
$z = q ( " select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1 " ,
dbesc ( $x [ 'hash' ]),
intval ( $channel [ 'channel_id' ]),
intval ( ABOOK_FLAG_SELF )
);
if ( $z )
2013-05-20 03:16:05 +00:00
proc_run ( 'php' , 'include/notifier.php' , 'permission_update' , $z [ 0 ][ 'abook_id' ]);
2012-12-02 06:37:41 +00:00
}
2013-11-18 03:22:24 +00:00
$new_connection = q ( " select abook_id, abook_flags from abook where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1 " ,
2013-11-18 00:50:32 +00:00
intval ( $channel [ 'channel_id' ]),
dbesc ( $x [ 'hash' ])
);
2013-11-18 03:22:24 +00:00
if ( $new_connection && ( ! ( $new_connection [ 0 ][ 'abook_flags' ] & ABOOK_FLAG_PENDING )) && ( $their_perms & PERMS_R_STREAM ))
2013-11-18 00:50:32 +00:00
proc_run ( 'php' , 'include/onepoll.php' , $new_connection [ 0 ][ 'abook_id' ]);
2012-12-02 06:37:41 +00:00
}
2012-11-30 02:15:13 +00:00
}
2012-11-11 04:08:07 +00:00
}
return true ;
}
return false ;
}
2013-03-26 04:32:12 +00:00
/**
* @ function : zot_gethub
*
* A guid and a url , both signed by the sender , distinguish a known sender at a known location
2013-11-29 00:13:09 +00:00
* This function looks these up to see if the channel is known and therefore previously verified .
* If not , we will need to verify it .
*
* @ param array $arr
* $arr must contain :
* string $arr [ 'guid' ] => guid of conversant
* string $arr [ 'guid_sig' ] => guid signed with conversant ' s private key
* string $arr [ 'url' ] => URL of the origination hub of this communication
* string $arr [ 'url_sig' ] => URL signed with conversant ' s private key
*
*
2013-03-26 04:32:12 +00:00
* @ returns : array => hubloc record
*/
2012-08-01 00:55:27 +00:00
2012-11-20 00:51:15 +00:00
function zot_gethub ( $arr ) {
2012-11-13 04:59:18 +00:00
2012-11-20 00:51:15 +00:00
if ( $arr [ 'guid' ] && $arr [ 'guid_sig' ] && $arr [ 'url' ] && $arr [ 'url_sig' ]) {
2012-08-10 03:31:06 +00:00
$r = q ( " select * from hubloc
2012-08-27 06:05:00 +00:00
where hubloc_guid = '%s' and hubloc_guid_sig = '%s'
and hubloc_url = '%s' and hubloc_url_sig = '%s'
2012-08-10 03:31:06 +00:00
limit 1 " ,
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'guid' ]),
dbesc ( $arr [ 'guid_sig' ]),
dbesc ( $arr [ 'url' ]),
dbesc ( $arr [ 'url_sig' ])
2012-08-10 03:31:06 +00:00
);
2013-01-05 03:24:17 +00:00
if ( $r && count ( $r )) {
logger ( 'zot_gethub: found' , LOGGER_DEBUG );
2012-08-10 03:31:06 +00:00
return $r [ 0 ];
2013-01-05 03:24:17 +00:00
}
2012-08-10 03:31:06 +00:00
}
2013-07-15 03:42:06 +00:00
logger ( 'zot_gethub: not found: ' . print_r ( $arr , true ), LOGGER_DEBUG );
2012-08-10 03:31:06 +00:00
return null ;
}
2013-11-29 00:13:09 +00:00
/**
* @ function zot_register_hub ( $arr )
*
* A communication has been received which has an unknown ( to us ) sender .
* Perform discovery based on our calculated hash of the sender at the origination address .
* This will fetch the discovery packet of the sender , which contains the public key we
* need to verify our guid and url signatures .
*
* @ param array $arr
* $arr must contain :
* string $arr [ 'guid' ] => guid of conversant
* string $arr [ 'guid_sig' ] => guid signed with conversant ' s private key
* string $arr [ 'url' ] => URL of the origination hub of this communication
* string $arr [ 'url_sig' ] => URL signed with conversant ' s private key
*
*
* @ returns array => 'success' ( boolean true or false )
* 'message' ( optional error string only if success is false )
*/
2012-08-10 03:31:06 +00:00
function zot_register_hub ( $arr ) {
2012-11-11 07:26:12 +00:00
$result = array ( 'success' => false );
2012-12-30 07:45:06 +00:00
if ( $arr [ 'url' ] && $arr [ 'url_sig' ] && $arr [ 'guid' ] && $arr [ 'guid_sig' ]) {
2012-11-11 07:26:12 +00:00
2012-11-20 00:51:15 +00:00
$guid_hash = base64url_encode ( hash ( 'whirlpool' , $arr [ 'guid' ] . $arr [ 'guid_sig' ], true ));
2012-11-11 07:26:12 +00:00
2013-01-03 00:28:47 +00:00
$url = $arr [ 'url' ] . '/.well-known/zot-info/?f=&guid_hash=' . $guid_hash ;
2013-01-25 03:45:08 +00:00
logger ( 'zot_register_hub: ' . $url , LOGGER_DEBUG );
2013-01-03 00:28:47 +00:00
$x = z_fetch_url ( $url );
2013-01-25 03:45:08 +00:00
logger ( 'zot_register_hub: ' . print_r ( $x , true ), LOGGER_DATA );
2012-11-11 07:26:12 +00:00
2012-08-10 03:31:06 +00:00
if ( $x [ 'success' ]) {
2012-11-20 00:51:15 +00:00
$record = json_decode ( $x [ 'body' ], true );
2013-11-29 00:13:09 +00:00
/*
* We now have a key - only continue registration if our signatures are valid
* AND the guid and guid sig in the returned packet match those provided in
* our current communication .
*/
if (( rsa_verify ( $arr [ 'guid' ], base64url_decode ( $arr [ 'guid_sig' ]), $record [ 'key' ]))
&& ( rsa_verify ( $arr [ 'url' ], base64url_decode ( $arr [ 'url_sig' ]), $record [ 'key' ]))
&& ( $arr [ 'guid' ] === $record [ 'guid' ])
&& ( $arr [ 'guid_sig' ] === $record [ 'guid_sig' ])) {
$c = import_xchan ( $record );
if ( $c [ 'success' ])
$result [ 'success' ] = true ;
}
else {
logger ( 'zot_register_hub: failure to verify returned packet.' );
}
2012-08-10 03:31:06 +00:00
}
}
2012-11-11 07:26:12 +00:00
return $result ;
2012-08-22 06:11:27 +00:00
}
2012-11-02 05:23:13 +00:00
2013-11-29 00:13:09 +00:00
/**
* @ function import_xchan ( $arr , $ud_flags = 1 )
2014-02-11 04:38:26 +00:00
* Takes an associative array of a fetched discovery packet and updates
2013-11-29 00:13:09 +00:00
* all internal data structures which need to be updated as a result .
*
* @ param array $arr => json_decoded discovery packet
* @ param int $ud_flags
* Determines whether to create a directory update record if any changes occur , default 1 or true
2014-02-11 22:19:20 +00:00
* $ud_flags = ( - 1 ) indicates a forced refresh where we unconditionally create a directory update record
* this typically occurs once a month for each channel as part of a scheduled ping to notify the directory
* that the channel still exists
2013-11-29 00:13:09 +00:00
*
* @ returns array => 'success' ( boolean true or false )
* 'message' ( optional error string only if success is false )
*/
2012-11-15 03:27:16 +00:00
2013-09-25 03:13:53 +00:00
function import_xchan ( $arr , $ud_flags = 1 ) {
2012-11-15 03:27:16 +00:00
2013-12-04 01:55:10 +00:00
call_hooks ( 'import_xchan' , $arr );
2012-11-15 03:27:16 +00:00
$ret = array ( 'success' => false );
2013-07-24 05:33:56 +00:00
$dirmode = intval ( get_config ( 'system' , 'directory_mode' ));
2013-03-21 09:21:44 +00:00
$changed = false ;
2013-09-15 10:48:43 +00:00
$what = '' ;
2012-11-15 03:27:16 +00:00
2013-07-19 01:22:08 +00:00
if ( ! ( is_array ( $arr ) && array_key_exists ( 'success' , $arr ) && $arr [ 'success' ])) {
logger ( 'import_xchan: invalid data packet: ' . print_r ( $arr , true ));
$ret [ 'message' ] = t ( 'Invalid data packet' );
return $ret ;
}
2012-11-20 00:51:15 +00:00
$xchan_hash = base64url_encode ( hash ( 'whirlpool' , $arr [ 'guid' ] . $arr [ 'guid_sig' ], true ));
2012-11-15 03:27:16 +00:00
$import_photos = false ;
2012-11-20 00:51:15 +00:00
if ( ! rsa_verify ( $arr [ 'guid' ], base64url_decode ( $arr [ 'guid_sig' ]), $arr [ 'key' ])) {
2012-12-30 23:28:13 +00:00
logger ( 'import_xchan: Unable to verify channel signature for ' . $arr [ 'address' ]);
2012-11-15 03:27:16 +00:00
$ret [ 'message' ] = t ( 'Unable to verify channel signature' );
return $ret ;
}
2013-04-30 01:21:23 +00:00
logger ( 'import_xchan: ' . $xchan_hash , LOGGER_DEBUG );
2012-11-15 03:27:16 +00:00
$r = q ( " select * from xchan where xchan_hash = '%s' limit 1 " ,
dbesc ( $xchan_hash )
);
2013-08-22 00:34:04 +00:00
if ( ! array_key_exists ( 'connect_url' , $arr ))
$arr [ 'connect_url' ] = '' ;
2013-08-26 03:17:45 +00:00
if ( strpos ( $arr [ 'address' ], '/' ) !== false )
$arr [ 'address' ] = substr ( $arr [ 'address' ], 0 , strpos ( $arr [ 'address' ], '/' ));
2013-01-22 08:20:25 +00:00
2012-11-15 03:27:16 +00:00
if ( $r ) {
2012-11-20 00:51:15 +00:00
if ( $r [ 0 ][ 'xchan_photo_date' ] != $arr [ 'photo_updated' ])
2013-01-22 08:20:25 +00:00
$import_photos = true ;
2013-01-22 10:56:32 +00:00
// if we import an entry from a site that's not ours and either or both of us is off the grid - hide the entry.
// TODO: check if we're the same directory realm, which would mean we are allowed to see it
$dirmode = get_config ( 'system' , 'directory_mode' );
if ((( $arr [ 'site' ][ 'directory_mode' ] === 'standalone' ) || ( $dirmode & DIRECTORY_MODE_STANDALONE ))
&& ( $arr [ 'site' ][ 'url' ] != z_root ()))
$arr [ 'searchable' ] = false ;
2013-02-02 11:11:23 +00:00
$hidden = ( 1 - intval ( $arr [ 'searchable' ]));
2013-01-22 10:56:32 +00:00
// Be careful - XCHAN_FLAGS_HIDDEN should evaluate to 1
2013-02-02 11:11:23 +00:00
if (( $r [ 0 ][ 'xchan_flags' ] & XCHAN_FLAGS_HIDDEN ) != $hidden )
2013-01-22 08:20:25 +00:00
$new_flags = $r [ 0 ][ 'xchan_flags' ] ^ XCHAN_FLAGS_HIDDEN ;
else
$new_flags = $r [ 0 ][ 'xchan_flags' ];
2013-08-22 00:34:04 +00:00
2013-09-23 03:38:24 +00:00
$adult = (( $r [ 0 ][ 'xchan_flags' ] & XCHAN_FLAGS_SELFCENSORED ) ? true : false );
$adult_changed = (( intval ( $adult ) != intval ( $arr [ 'adult_content' ])) ? true : false );
if ( $adult_changed )
$new_flags = $new_flags ^ XCHAN_FLAGS_SELFCENSORED ;
2013-08-26 03:17:45 +00:00
2013-03-13 00:39:35 +00:00
if (( $r [ 0 ][ 'xchan_name_date' ] != $arr [ 'name_updated' ])
|| ( $r [ 0 ][ 'xchan_connurl' ] != $arr [ 'connections_url' ])
|| ( $r [ 0 ][ 'xchan_flags' ] != $new_flags )
|| ( $r [ 0 ][ 'xchan_addr' ] != $arr [ 'address' ])
2013-08-22 00:34:04 +00:00
|| ( $r [ 0 ][ 'xchan_follow' ] != $arr [ 'follow_url' ])
|| ( $r [ 0 ][ 'xchan_connpage' ] != $arr [ 'connect_url' ])
2013-03-13 00:39:35 +00:00
|| ( $r [ 0 ][ 'xchan_url' ] != $arr [ 'url' ])) {
2013-08-22 00:34:04 +00:00
$r = q ( " update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s',
xchan_connpage = '%s' , xchan_flags = % d ,
2013-03-13 00:39:35 +00:00
xchan_addr = '%s' , xchan_url = '%s' where xchan_hash = '%s' limit 1 " ,
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'name' ]),
dbesc ( $arr [ 'name_updated' ]),
2013-01-01 10:06:41 +00:00
dbesc ( $arr [ 'connections_url' ]),
2013-08-22 00:34:04 +00:00
dbesc ( $arr [ 'follow_url' ]),
dbesc ( $arr [ 'connect_url' ]),
2013-01-22 08:20:25 +00:00
intval ( $new_flags ),
2013-03-13 00:39:35 +00:00
dbesc ( $arr [ 'address' ]),
dbesc ( $arr [ 'url' ]),
2012-11-15 03:27:16 +00:00
dbesc ( $xchan_hash )
);
2013-04-30 01:21:23 +00:00
logger ( 'import_xchan: existing: ' . print_r ( $r [ 0 ], true ), LOGGER_DATA );
logger ( 'import_xchan: new: ' . print_r ( $arr , true ), LOGGER_DATA );
2013-09-15 10:48:43 +00:00
$what .= 'xchan ' ;
2013-03-21 09:21:44 +00:00
$changed = true ;
2012-11-15 03:27:16 +00:00
}
}
else {
$import_photos = true ;
2013-03-27 02:37:33 +00:00
if ((( $arr [ 'site' ][ 'directory_mode' ] === 'standalone' ) || ( $dirmode & DIRECTORY_MODE_STANDALONE ))
&& ( $arr [ 'site' ][ 'url' ] != z_root ()))
$arr [ 'searchable' ] = false ;
$hidden = ( 1 - intval ( $arr [ 'searchable' ]));
if ( $hidden )
$new_flags = XCHAN_FLAGS_HIDDEN ;
else
$new_flags = 0 ;
2013-09-23 03:38:24 +00:00
if ( $arr [ 'adult_content' ])
$new_flags |= XCHAN_FLAGS_SELFCENSORED ;
2013-03-27 02:37:33 +00:00
2012-11-15 03:27:16 +00:00
$x = q ( " insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype,
2013-08-22 00:34:04 +00:00
xchan_photo_l , xchan_addr , xchan_url , xchan_connurl , xchan_follow , xchan_connpage , xchan_name , xchan_network , xchan_photo_date , xchan_name_date , xchan_flags )
values ( '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , % d ) " ,
2012-11-15 03:27:16 +00:00
dbesc ( $xchan_hash ),
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'guid' ]),
dbesc ( $arr [ 'guid_sig' ]),
dbesc ( $arr [ 'key' ]),
dbesc ( $arr [ 'photo_mimetype' ]),
dbesc ( $arr [ 'photo' ]),
dbesc ( $arr [ 'address' ]),
dbesc ( $arr [ 'url' ]),
2013-01-01 10:06:41 +00:00
dbesc ( $arr [ 'connections_url' ]),
2013-08-22 00:34:04 +00:00
dbesc ( $arr [ 'follow_url' ]),
dbesc ( $arr [ 'connect_url' ]),
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'name' ]),
2012-11-15 03:27:16 +00:00
dbesc ( 'zot' ),
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'photo_updated' ]),
2013-03-27 02:37:33 +00:00
dbesc ( $arr [ 'name_updated' ]),
intval ( $new_flags )
2012-11-15 03:27:16 +00:00
);
2013-09-09 08:05:29 +00:00
2013-09-15 10:48:43 +00:00
$what .= 'new_xchan' ;
2013-03-21 09:21:44 +00:00
$changed = true ;
2012-11-15 03:27:16 +00:00
}
if ( $import_photos ) {
2013-04-26 03:01:24 +00:00
require_once ( 'include/photo/photo_driver.php' );
2012-11-15 03:27:16 +00:00
2013-12-06 02:17:16 +00:00
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
$local = q ( " select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1 " ,
dbesc ( $xchan_hash )
);
if ( $local ) {
$ph = z_fetch_url ( $arr [ 'photo' ], true );
if ( $ph [ 'success' ]) {
import_channel_photo ( $ph [ 'body' ], $arr [ 'photo_mimetype' ], $local [ 0 ][ 'channel_account_id' ], $local [ 0 ][ 'channel_id' ]);
// reset the names in case they got messed up when we had a bug in this function
$photos = array (
z_root () . '/photo/profile/l/' . $local [ 0 ][ 'channel_id' ],
z_root () . '/photo/profile/m/' . $local [ 0 ][ 'channel_id' ],
z_root () . '/photo/profile/s/' . $local [ 0 ][ 'channel_id' ],
$arr [ 'photo_mimetype' ]
);
}
}
else {
$photos = import_profile_photo ( $arr [ 'photo' ], $xchan_hash );
}
if ( $photos ) {
$r = q ( " update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
2012-11-15 03:27:16 +00:00
where xchan_hash = '%s' limit 1 " ,
2013-12-06 02:17:16 +00:00
dbesc ( datetime_convert ( 'UTC' , 'UTC' , $arr [ 'photo_updated' ])),
2012-11-15 03:27:16 +00:00
dbesc ( $photos [ 0 ]),
dbesc ( $photos [ 1 ]),
dbesc ( $photos [ 2 ]),
dbesc ( $photos [ 3 ]),
dbesc ( $xchan_hash )
2013-12-06 02:17:16 +00:00
);
2013-03-21 09:21:44 +00:00
2013-12-06 02:17:16 +00:00
$what .= 'photo ' ;
$changed = true ;
}
2012-11-15 03:27:16 +00:00
}
2013-03-11 01:45:58 +00:00
// what we are missing for true hub independence is for any changes in the primary hub to
// get reflected not only in the hublocs, but also to update the URLs and addr in the appropriate xchan
2012-11-20 00:51:15 +00:00
if ( $arr [ 'locations' ]) {
2013-03-11 01:45:58 +00:00
2013-11-21 05:09:13 +00:00
$xisting = q ( " select hubloc_id, hubloc_url, hubloc_sitekey from hubloc where hubloc_hash = '%s' " ,
2013-03-11 01:45:58 +00:00
dbesc ( $xchan_hash )
);
2013-12-03 07:55:57 +00:00
// See if a primary is specified
$has_primary = false ;
foreach ( $arr [ 'locations' ] as $location ) {
if ( $location [ 'primary' ]) {
$has_primary = true ;
break ;
}
}
2012-11-20 00:51:15 +00:00
foreach ( $arr [ 'locations' ] as $location ) {
if ( ! rsa_verify ( $location [ 'url' ], base64url_decode ( $location [ 'url_sig' ]), $arr [ 'key' ])) {
2012-12-30 23:28:13 +00:00
logger ( 'import_xchan: Unable to verify site signature for ' . $location [ 'url' ]);
2012-11-15 03:27:16 +00:00
$ret [ 'message' ] .= sprintf ( t ( 'Unable to verify site signature for %s' ), $location [ 'url' ]) . EOL ;
continue ;
}
2013-12-03 07:55:57 +00:00
// Ensure that they have one primary hub
if ( ! $has_primary )
$location [ 'primary' ] = true ;
2013-03-11 01:45:58 +00:00
for ( $x = 0 ; $x < count ( $xisting ); $x ++ ) {
2013-11-21 05:09:13 +00:00
if (( $xisting [ $x ][ 'hubloc_url' ] === $location [ 'url' ]) && ( $xisting [ $x ][ 'hubloc_sitekey' ] === $location [ 'sitekey' ])) {
2013-03-11 01:45:58 +00:00
$xisting [ $x ][ 'updated' ] = true ;
}
}
2014-02-20 09:35:08 +00:00
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' ], '/' ));
2013-09-14 08:56:25 +00:00
// match as many fields as possible in case anything at all changed.
2013-11-21 05:09:13 +00:00
$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' " ,
2012-11-15 03:27:16 +00:00
dbesc ( $xchan_hash ),
2013-07-15 03:42:06 +00:00
dbesc ( $arr [ 'guid' ]),
dbesc ( $arr [ 'guid_sig' ]),
dbesc ( $location [ 'url' ]),
2013-09-14 08:56:25 +00:00
dbesc ( $location [ 'url_sig' ]),
dbesc ( $location [ 'host' ]),
dbesc ( $location [ 'address' ]),
dbesc ( $location [ 'callback' ]),
dbesc ( $location [ 'sitekey' ])
2012-11-15 03:27:16 +00:00
);
if ( $r ) {
2013-07-15 01:32:20 +00:00
logger ( 'import_xchan: hub exists: ' . $location [ 'url' ]);
2013-10-25 02:38:50 +00:00
// update connection timestamp if this is the site we're talking to
if ( $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' ])
);
}
2013-11-21 05:09:13 +00:00
// Remove pure duplicates
2013-11-22 01:23:14 +00:00
if ( count ( $r ) > 1 ) {
2013-11-21 05:09:13 +00:00
for ( $h = 1 ; $h < count ( $r ); $h ++ ) {
q ( " delete from hubloc where hubloc_id = %d limit 1 " ,
intval ( $r [ $h ][ 'hubloc_id' ])
);
}
}
2013-03-11 01:45:58 +00:00
if ((( $r [ 0 ][ 'hubloc_flags' ] & HUBLOC_FLAGS_PRIMARY ) && ( ! $location [ 'primary' ]))
|| (( ! ( $r [ 0 ][ 'hubloc_flags' ] & HUBLOC_FLAGS_PRIMARY )) && ( $location [ 'primary' ]))) {
2013-08-28 00:08:59 +00:00
$r = q ( " update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_id = %d limit 1 " ,
2012-11-15 03:27:16 +00:00
intval ( HUBLOC_FLAGS_PRIMARY ),
2013-08-28 00:08:59 +00:00
dbesc ( datetime_convert ()),
2012-11-15 03:27:16 +00:00
intval ( $r [ 0 ][ 'hubloc_id' ])
);
2013-09-15 10:48:43 +00:00
$what = 'primary_hub ' ;
2013-08-11 23:12:40 +00:00
$changed = true ;
2012-11-15 03:27:16 +00:00
}
2013-09-18 03:50:09 +00:00
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 ;
}
2013-08-11 23:12:40 +00:00
continue ;
}
2013-03-11 01:45:58 +00:00
// new hub claiming to be primary. Make it so.
if ( intval ( $location [ 'primary' ])) {
2013-08-28 00:08:59 +00:00
$r = q ( " update hubloc set hubloc_flags = (hubloc_flags ^ %d), hubloc_updated = '%s' where hubloc_hash = '%s' and (hubloc_flags & %d ) " ,
2013-03-11 01:45:58 +00:00
intval ( HUBLOC_FLAGS_PRIMARY ),
2013-08-28 00:08:59 +00:00
dbesc ( datetime_convert ()),
2013-03-11 01:45:58 +00:00
dbesc ( $xchan_hash ),
intval ( HUBLOC_FLAGS_PRIMARY )
);
}
2013-07-15 01:32:20 +00:00
logger ( 'import_xchan: new hub: ' . $location [ 'url' ]);
2013-08-28 00:08:59 +00:00
$r = q ( " insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_flags, hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey, hubloc_updated, hubloc_connected)
values ( '%s' , '%s' , '%s' , '%s' , % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' ) " ,
2012-11-20 00:51:15 +00:00
dbesc ( $arr [ 'guid' ]),
dbesc ( $arr [ 'guid_sig' ]),
2012-11-15 03:27:16 +00:00
dbesc ( $xchan_hash ),
dbesc ( $location [ 'address' ]),
intval (( intval ( $location [ 'primary' ])) ? HUBLOC_FLAGS_PRIMARY : 0 ),
dbesc ( $location [ 'url' ]),
dbesc ( $location [ 'url_sig' ]),
dbesc ( $location [ 'host' ]),
dbesc ( $location [ 'callback' ]),
2013-08-28 00:08:59 +00:00
dbesc ( $location [ 'sitekey' ]),
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ())
2012-11-15 03:27:16 +00:00
);
2013-09-15 10:48:43 +00:00
$what .= 'newhub ' ;
2013-03-21 09:21:44 +00:00
$changed = true ;
2014-02-20 09:35:08 +00:00
2012-11-15 03:27:16 +00:00
}
2013-03-11 01:45:58 +00:00
// get rid of any hubs we have for this channel which weren't reported.
2014-02-20 09:35:08 +00:00
2013-03-11 01:45:58 +00:00
if ( $xisting ) {
foreach ( $xisting as $x ) {
if ( ! array_key_exists ( 'updated' , $x )) {
2013-03-12 01:22:40 +00:00
logger ( 'import_xchan: removing unreferenced hub location ' . $x [ 'hubloc_url' ]);
2013-03-11 01:45:58 +00:00
$r = q ( " delete from hubloc where hubloc_id = %d limit 1 " ,
intval ( $x [ 'hubloc_id' ])
);
2013-09-15 10:48:43 +00:00
$what .= 'removed_hub' ;
2013-03-21 09:21:44 +00:00
$changed = true ;
2013-03-11 01:45:58 +00:00
}
}
}
2012-11-15 03:27:16 +00:00
}
2013-05-01 01:16:51 +00:00
// Are we a directory server of some kind?
2013-07-24 05:33:56 +00:00
2013-05-01 01:16:51 +00:00
if ( $dirmode != DIRECTORY_MODE_NORMAL ) {
if ( array_key_exists ( 'profile' , $arr ) && is_array ( $arr [ 'profile' ])) {
2013-09-26 04:22:36 +00:00
$profile_changed = import_directory_profile ( $xchan_hash , $arr [ 'profile' ], $arr [ 'address' ], $ud_flags , 1 );
2013-05-01 01:16:51 +00:00
if ( $profile_changed ) {
2013-09-15 10:48:43 +00:00
$what .= 'profile ' ;
2013-05-01 01:16:51 +00:00
$changed = true ;
}
}
else {
logger ( 'import_xchan: profile not available - hiding' );
// they may have made it private
$r = q ( " delete from xprof where xprof_hash = '%s' limit 1 " ,
dbesc ( $xchan_hash )
);
$r = q ( " delete from xtag where xtag_hash = '%s' limit 1 " ,
dbesc ( $xchan_hash )
);
}
}
2013-07-24 05:33:56 +00:00
if ( array_key_exists ( 'site' , $arr ) && is_array ( $arr [ 'site' ])) {
$profile_changed = import_site ( $arr [ 'site' ], $arr [ 'key' ]);
if ( $profile_changed ) {
2013-09-15 10:48:43 +00:00
$what .= 'site ' ;
2013-07-24 05:33:56 +00:00
$changed = true ;
}
}
2014-02-11 22:19:20 +00:00
if (( $changed ) || ( $ud_flags == ( - 1 ))) {
2013-09-09 08:05:29 +00:00
$guid = random_string () . '@' . get_app () -> get_hostname ();
2013-09-25 03:13:53 +00:00
update_modtime ( $xchan_hash , $guid , $arr [ 'address' ], $ud_flags );
2013-09-15 10:48:43 +00:00
logger ( 'import_xchan: changed: ' . $what , LOGGER_DEBUG );
2013-03-21 09:21:44 +00:00
}
2013-10-15 05:20:14 +00:00
elseif ( ! $ud_flags ) {
// nothing changed but we still need to update the updates record
q ( " update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) " ,
intval ( UPDATE_FLAGS_UPDATED ),
dbesc ( $arr [ 'address' ]),
intval ( UPDATE_FLAGS_UPDATED )
);
}
2013-03-21 09:21:44 +00:00
2012-11-15 03:27:16 +00:00
if ( ! x ( $ret , 'message' )) {
$ret [ 'success' ] = true ;
$ret [ 'hash' ] = $xchan_hash ;
}
2012-12-30 23:28:13 +00:00
logger ( 'import_xchan: result: ' . print_r ( $ret , true ), LOGGER_DATA );
2012-11-15 03:27:16 +00:00
return $ret ;
}
2013-11-29 00:13:09 +00:00
/**
* @ function zot_process_response ( $hub , $arr , $outq ) {
* Called immediately after sending a zot message which is using queue processing
* Updates the queue item according to the response result and logs any information
* returned to aid communications troubleshooting .
*
* @ param string $hub - url of site we just contacted
* @ param array $arr - output of z_post_url ()
* @ param array $outq - The queue structure attached to this request
*
* @ returns nothing
*/
2012-12-31 22:45:26 +00:00
function zot_process_response ( $hub , $arr , $outq ) {
if ( ! $arr [ 'success' ]) {
logger ( 'zot_process_response: failed: ' . $hub );
2012-11-20 00:51:15 +00:00
return ;
2012-12-31 22:45:26 +00:00
}
2012-11-20 00:51:15 +00:00
$x = json_decode ( $arr [ 'body' ], true );
2012-12-31 22:45:26 +00:00
if ( ! $x ) {
logger ( 'zot_process_response: No json from ' . $hub );
logger ( 'zot_process_response: headers: ' . print_r ( $arr [ 'header' ], true ), LOGGER_DATA );
}
2012-11-20 00:51:15 +00:00
// synchronous message types are handled immediately
// async messages remain in the queue until processed.
if ( intval ( $outq [ 'outq_async' ])) {
$r = q ( " update outq set outq_delivered = 1, outq_updated = '%s' where outq_hash = '%s' and outq_channel = %d limit 1 " ,
dbesc ( datetime_convert ()),
dbesc ( $outq [ 'outq_hash' ]),
intval ( $outq [ 'outq_channel' ])
);
}
else {
$r = q ( " delete from outq where outq_hash = '%s' and outq_channel = %d limit 1 " ,
dbesc ( $outq [ 'outq_hash' ]),
intval ( $outq [ 'outq_channel' ])
);
}
logger ( 'zot_process_response: ' . print_r ( $x , true ), LOGGER_DATA );
2012-11-20 04:45:12 +00:00
}
2013-03-26 04:32:12 +00:00
/**
2013-11-29 00:13:09 +00:00
* @ function zot_fetch ( $arr )
2013-03-26 04:32:12 +00:00
*
2013-11-29 00:13:09 +00:00
* We received a notification packet ( in mod / post . php ) that a message is waiting for us , and we ' ve verified the sender .
* Now send back a pickup message , using our message tracking ID ( $arr [ 'secret' ]), which we will sign with our site private key .
* The entire pickup message is encrypted with the remote site ' s public key .
* If everything checks out on the remote end , we will receive back a packet containing one or more messages ,
* which will be processed and delivered before this function ultimately returns .
*
* @ param array $arr
* decrypted and json decoded notify packet from remote site
2013-03-26 04:32:12 +00:00
*/
2012-11-20 04:45:12 +00:00
function zot_fetch ( $arr ) {
logger ( 'zot_fetch: ' . print_r ( $arr , true ), LOGGER_DATA );
$url = $arr [ 'sender' ][ 'url' ] . $arr [ 'callback' ];
$ret_hub = zot_gethub ( $arr [ 'sender' ]);
if ( ! $ret_hub ) {
2013-03-26 04:32:12 +00:00
logger ( 'zot_fetch: no hub: ' . print_r ( $arr [ 'sender' ], true ));
2012-11-20 04:45:12 +00:00
return ;
}
$data = array (
'type' => 'pickup' ,
'url' => z_root (),
'callback_sig' => base64url_encode ( rsa_sign ( z_root () . '/post' , get_config ( 'system' , 'prvkey' ))),
'callback' => z_root () . '/post' ,
'secret' => $arr [ 'secret' ],
'secret_sig' => base64url_encode ( rsa_sign ( $arr [ 'secret' ], get_config ( 'system' , 'prvkey' )))
);
2013-11-20 23:20:12 +00:00
$datatosend = json_encode ( crypto_encapsulate ( json_encode ( $data ), $ret_hub [ 'hubloc_sitekey' ]));
2012-11-20 04:45:12 +00:00
$fetch = zot_zot ( $url , $datatosend );
2013-10-02 09:50:02 +00:00
$result = zot_import ( $fetch , $arr [ 'sender' ][ 'url' ]);
2013-01-01 05:33:11 +00:00
return $result ;
2012-11-20 04:45:12 +00:00
}
2013-03-27 02:53:04 +00:00
/**
* @ function zot_import
*
* Process an incoming array of messages which were obtained via pickup , and
* import , update , delete as directed .
*
2013-11-29 00:13:09 +00:00
* @ param array $arr => 'pickup' structure returned from remote site
* @ param string $sender_url => the url specified by the sender in the initial communication
* 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'
*
* @ 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 .
*
2013-03-27 02:53:04 +00:00
*/
2012-11-20 04:45:12 +00:00
2013-10-02 09:50:02 +00:00
function zot_import ( $arr , $sender_url ) {
2012-11-20 04:45:12 +00:00
$data = json_decode ( $arr [ 'body' ], true );
2012-11-28 01:09:01 +00:00
2013-01-29 04:51:37 +00:00
if ( ! $data ) {
logger ( 'zot_import: empty body' );
return array ();
}
2012-11-20 04:45:12 +00:00
if ( array_key_exists ( 'iv' , $data )) {
2013-11-20 23:20:12 +00:00
$data = json_decode ( crypto_unencapsulate ( $data , get_config ( 'system' , 'prvkey' )), true );
2012-11-20 04:45:12 +00:00
}
$incoming = $data [ 'pickup' ];
2013-01-01 08:45:44 +00:00
$return = array ();
2012-11-20 04:45:12 +00:00
if ( is_array ( $incoming )) {
foreach ( $incoming as $i ) {
2013-01-01 08:45:44 +00:00
$result = null ;
2012-11-27 05:20:16 +00:00
2012-11-28 01:09:01 +00:00
if ( array_key_exists ( 'iv' , $i [ 'notify' ])) {
2013-11-20 23:20:12 +00:00
$i [ 'notify' ] = json_decode ( crypto_unencapsulate ( $i [ 'notify' ], get_config ( 'system' , 'prvkey' )), true );
2012-11-28 01:09:01 +00:00
}
2013-01-25 03:45:08 +00:00
logger ( 'zot_import: notify: ' . print_r ( $i [ 'notify' ], true ), LOGGER_DATA );
2012-12-06 00:44:07 +00:00
2013-10-02 09:50:02 +00:00
$hub = zot_gethub ( $i [ 'notify' ][ 'sender' ]);
if (( ! $hub ) || ( $hub [ 'hubloc_url' ] != $sender_url )) {
logger ( 'zot_import: potential forgery: wrong site for sender: ' . $sender_url . ' != ' . print_r ( $i [ 'notify' ], true ));
continue ;
}
2012-11-27 05:20:16 +00:00
$i [ 'notify' ][ 'sender' ][ 'hash' ] = base64url_encode ( hash ( 'whirlpool' , $i [ 'notify' ][ 'sender' ][ 'guid' ] . $i [ 'notify' ][ 'sender' ][ 'guid_sig' ], true ));
2012-11-26 07:18:11 +00:00
$deliveries = null ;
2012-11-27 05:20:16 +00:00
if ( array_key_exists ( 'recipients' , $i [ 'notify' ]) && count ( $i [ 'notify' ][ 'recipients' ])) {
2012-11-27 00:48:04 +00:00
logger ( 'specific recipients' );
2012-11-26 07:18:11 +00:00
$recip_arr = array ();
foreach ( $i [ 'notify' ][ 'recipients' ] as $recip ) {
2012-12-06 00:44:07 +00:00
$recip_arr [] = base64url_encode ( hash ( 'whirlpool' , $recip [ 'guid' ] . $recip [ 'guid_sig' ], true ));
2012-11-26 07:18:11 +00:00
}
stringify_array_elms ( $recip_arr );
2012-12-06 00:44:07 +00:00
$recips = implode ( ',' , $recip_arr );
2014-02-17 00:04:46 +00:00
$r = q ( " select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and not ( channel_pageflags & %d ) " ,
intval ( PAGE_REMOVED )
);
2013-01-01 08:45:44 +00:00
if ( ! $r ) {
logger ( 'recips: no recipients on this site' );
2012-11-26 07:18:11 +00:00
continue ;
2013-01-01 08:45:44 +00:00
}
2012-11-26 07:18:11 +00:00
$deliveries = $r ;
// We found somebody on this site that's in the recipient list.
2012-11-20 04:45:12 +00:00
}
else {
2013-11-15 03:33:28 +00:00
if (( $i [ 'message' ]) && ( array_key_exists ( 'flags' , $i [ 'message' ])) && ( in_array ( 'private' , $i [ 'message' ][ 'flags' ]))) {
2013-09-13 05:50:41 +00:00
// This should not happen but until we can stop it...
logger ( 'private message was delivered with no recipients.' );
continue ;
}
2012-11-27 00:48:04 +00:00
logger ( 'public post' );
2012-11-20 04:45:12 +00:00
2013-01-25 04:43:33 +00:00
// Public post. look for any site members who are or may be accepting posts from this sender
2013-02-15 22:13:58 +00:00
// and who are allowed to see them based on the sender's permissions
$deliveries = allowed_public_recips ( $i );
2013-08-22 12:50:15 +00:00
2012-11-26 07:18:11 +00:00
}
2013-11-18 04:43:50 +00:00
// Go through the hash array and remove duplicates. array_unique() won't do this because the array is more than one level.
$no_dups = array ();
if ( $deliveries ) {
foreach ( $deliveries as $d ) {
if ( ! in_array ( $d [ 'hash' ], $no_dups ))
$no_dups [] = $d [ 'hash' ];
}
if ( $no_dups ) {
$deliveries = array ();
foreach ( $no_dups as $n ) {
$deliveries [] = array ( 'hash' => $n );
}
}
}
2013-01-01 08:45:44 +00:00
if ( ! $deliveries ) {
logger ( 'zot_import: no deliveries on this site' );
2012-11-27 00:48:04 +00:00
continue ;
2013-01-01 08:45:44 +00:00
}
2013-11-18 04:43:50 +00:00
2012-11-26 07:18:11 +00:00
if ( $i [ 'message' ]) {
if ( $i [ 'message' ][ 'type' ] === 'activity' ) {
2012-11-27 05:20:16 +00:00
$arr = get_item_elements ( $i [ 'message' ]);
2013-07-29 04:04:03 +00:00
2013-01-26 23:50:31 +00:00
if ( ! array_key_exists ( 'created' , $arr )) {
logger ( 'Activity rejected: probable failure to lookup author/owner. ' . print_r ( $i [ 'message' ], true ));
continue ;
}
2013-08-01 21:27:40 +00:00
2013-01-25 03:45:08 +00:00
logger ( 'Activity received: ' . print_r ( $arr , true ), LOGGER_DATA );
logger ( 'Activity recipients: ' . print_r ( $deliveries , true ), LOGGER_DATA );
2012-12-03 04:54:20 +00:00
2012-11-28 01:09:01 +00:00
$relay = (( array_key_exists ( 'flags' , $i [ 'message' ]) && in_array ( 'relay' , $i [ 'message' ][ 'flags' ])) ? true : false );
2013-01-01 05:33:11 +00:00
$result = process_delivery ( $i [ 'notify' ][ 'sender' ], $arr , $deliveries , $relay );
2012-12-03 04:54:20 +00:00
2012-11-26 07:18:11 +00:00
}
elseif ( $i [ 'message' ][ 'type' ] === 'mail' ) {
2012-12-06 00:44:07 +00:00
$arr = get_mail_elements ( $i [ 'message' ]);
2013-01-25 03:45:08 +00:00
logger ( 'Mail received: ' . print_r ( $arr , true ), LOGGER_DATA );
logger ( 'Mail recipients: ' . print_r ( $deliveries , true ), LOGGER_DATA );
2012-12-06 00:44:07 +00:00
2013-01-01 05:33:11 +00:00
$result = process_mail_delivery ( $i [ 'notify' ][ 'sender' ], $arr , $deliveries );
2012-11-20 04:45:12 +00:00
2012-11-26 07:18:11 +00:00
}
2012-12-22 12:33:32 +00:00
elseif ( $i [ 'message' ][ 'type' ] === 'profile' ) {
$arr = get_profile_elements ( $i [ 'message' ]);
2013-01-25 03:45:08 +00:00
logger ( 'Profile received: ' . print_r ( $arr , true ), LOGGER_DATA );
logger ( 'Profile recipients: ' . print_r ( $deliveries , true ), LOGGER_DATA );
2012-12-22 12:33:32 +00:00
2013-01-01 05:33:11 +00:00
$result = process_profile_delivery ( $i [ 'notify' ][ 'sender' ], $arr , $deliveries );
2012-12-03 04:54:20 +00:00
2012-12-22 12:33:32 +00:00
}
2013-06-27 00:31:02 +00:00
elseif ( $i [ 'message' ][ 'type' ] === 'channel_sync' ) {
// $arr = get_channelsync_elements($i['message']);
2013-04-22 05:12:18 +00:00
2013-06-27 00:31:02 +00:00
$arr = $i [ 'message' ];
2013-04-22 05:12:18 +00:00
2013-06-27 00:31:02 +00:00
logger ( 'Channel sync received: ' . print_r ( $arr , true ), LOGGER_DATA );
logger ( 'Channel sync recipients: ' . print_r ( $deliveries , true ), LOGGER_DATA );
2013-07-26 05:57:06 +00:00
$result = process_channel_sync_delivery ( $i [ 'notify' ][ 'sender' ], $arr , $deliveries );
2013-06-27 00:31:02 +00:00
}
2012-12-22 12:33:32 +00:00
}
2013-09-11 11:59:45 +00:00
if ( $result ){
2013-01-01 08:45:44 +00:00
$return = array_merge ( $return , $result );
2013-09-11 11:59:45 +00:00
}
2012-11-20 04:45:12 +00:00
}
}
2013-01-01 05:33:11 +00:00
2013-01-01 08:45:44 +00:00
return $return ;
2013-01-01 05:33:11 +00:00
2012-11-20 04:45:12 +00:00
}
2012-11-27 00:48:04 +00:00
2012-11-27 05:20:16 +00:00
// A public message with no listed recipients can be delivered to anybody who
// has PERMS_NETWORK for that type of post, or PERMS_SITE and is one the same
// site, or PERMS_SPECIFIC and the sender is a contact who is granted
// permissions via their connection permissions in the address book.
// Here we take a given message and construct a list of hashes of everybody
// on the site that we should deliver to.
2012-11-27 00:48:04 +00:00
function public_recips ( $msg ) {
2013-08-22 12:50:15 +00:00
$check_mentions = false ;
2012-11-27 00:48:04 +00:00
if ( $msg [ 'message' ][ 'type' ] === 'activity' ) {
2013-09-13 03:11:56 +00:00
$col = 'channel_w_stream' ;
$field = PERMS_W_STREAM ;
2012-11-27 00:48:04 +00:00
if ( array_key_exists ( 'flags' , $msg [ 'message' ]) && in_array ( 'thread_parent' , $msg [ 'message' ][ 'flags' ])) {
2013-09-13 03:11:56 +00:00
// check mention recipient permissions on top level posts only
2013-08-22 12:50:15 +00:00
$check_mentions = true ;
2012-11-27 00:48:04 +00:00
}
else {
2013-09-13 03:11:56 +00:00
// if this is a comment and it wasn't sent by the post owner, check to see who is allowing them to comment.
// We should have one specific recipient and this step shouldn't be needed unless somebody stuffed up their software.
// We may need this step to protect us from bad guys intentionally stuffing up their software.
// If it is sent by the post owner, we don't need to do this. We only need to see who is receiving the
// owner's stream (which was already set above) - as they control the comment permissions
if ( $msg [ 'notify' ][ 'sender' ][ 'guid_sig' ] != $msg [ 'message' ][ 'owner' ][ 'guid_sig' ]) {
$col = 'channel_w_comment' ;
$field = PERMS_W_COMMENT ;
}
2012-11-27 00:48:04 +00:00
}
}
elseif ( $msg [ 'message' ][ 'type' ] === 'mail' ) {
$col = 'channel_w_mail' ;
$field = PERMS_W_MAIL ;
}
if ( ! $col )
return NULL ;
2013-08-22 12:50:15 +00:00
2012-11-27 00:48:04 +00:00
if ( $msg [ 'notify' ][ 'sender' ][ 'url' ] === z_root ())
2013-09-11 05:45:04 +00:00
$sql = " where (( " . $col . " & " . PERMS_NETWORK . " ) or ( " . $col . " & " . PERMS_SITE . " ) or ( " . $col . " & " . PERMS_PUBLIC . " )) " ;
2012-11-27 00:48:04 +00:00
else
2013-09-11 05:45:04 +00:00
$sql = " where (( " . $col . " & " . PERMS_NETWORK . " ) or ( " . $col . " & " . PERMS_PUBLIC . " )) " ;
2012-11-27 00:48:04 +00:00
2013-09-20 12:45:11 +00:00
$r = q ( " select channel_hash as hash from channel $sql or channel_hash = '%s' " ,
dbesc ( $msg [ 'notify' ][ 'sender' ][ 'hash' ])
);
2012-11-27 00:48:04 +00:00
if ( ! $r )
$r = array ();
2014-02-17 00:04:46 +00:00
$x = q ( " select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and not ( channel_pageflags & " . PAGE_REMOVED . " ) and (( " . $col . " & " . PERMS_SPECIFIC . " ) and ( abook_my_perms & " . $field . " )) OR ( " . $col . " & " . PERMS_CONTACTS . " ) " ,
2012-11-27 05:20:16 +00:00
dbesc ( $msg [ 'notify' ][ 'sender' ][ 'hash' ])
2012-11-27 00:48:04 +00:00
);
if ( ! $x )
$x = array ();
$r = array_merge ( $r , $x );
2013-08-22 12:50:15 +00:00
// look for any public mentions on this site
// They will get filtered by tgroup_check() so we don't need to check permissions now
if ( $check_mentions && $msg [ 'message' ][ 'tags' ]) {
if ( is_array ( $msg [ 'message' ][ 'tags' ]) && $msg [ 'message' ][ 'tags' ]) {
foreach ( $msg [ 'message' ][ 'tags' ] as $tag ) {
if (( $tag [ 'type' ] === 'mention' ) && ( strpos ( $tag [ 'url' ], z_root ()) !== false )) {
$address = basename ( $tag [ 'url' ]);
if ( $address ) {
$z = q ( " select channel_hash as hash from channel where channel_address = '%s' limit 1 " ,
dbesc ( $address )
);
if ( $z )
$r = array_merge ( $r , $z );
}
}
}
}
}
2013-07-15 10:12:51 +00:00
logger ( 'public_recips: ' . print_r ( $r , true ), LOGGER_DATA );
2012-11-27 00:48:04 +00:00
return $r ;
2012-11-27 05:20:16 +00:00
}
2013-02-15 22:13:58 +00:00
// This is the second part of the above function. We'll find all the channels willing to accept public posts from us,
// then match them against the sender privacy scope and see who in that list that the sender is allowing.
function allowed_public_recips ( $msg ) {
logger ( 'allowed_public_recips: ' . print_r ( $msg , true ));
$recips = public_recips ( $msg );
if ( ! $recips )
return $recips ;
if ( $msg [ 'message' ][ 'type' ] === 'mail' )
return $recips ;
if ( array_key_exists ( 'public_scope' , $msg [ 'message' ]))
$scope = $msg [ 'message' ][ 'public_scope' ];
// we can pull out these two lines once everybody has upgraded to >= 2013-02-15.225
else
$scope = 'public' ;
$hash = base64url_encode ( hash ( 'whirlpool' , $msg [ 'notify' ][ 'sender' ][ 'guid' ] . $msg [ 'notify' ][ 'sender' ][ 'guid_sig' ], true ));
if ( $scope === 'public' || $scope === 'network: red' )
return $recips ;
if ( strpos ( $scope , 'site:' ) === 0 ) {
if (( $scope === 'site: ' . get_app () -> get_hostname ()) && ( $msg [ 'notify' ][ 'sender' ][ 'url' ] === z_root ()))
return $recips ;
else
return array ();
}
if ( $scope === 'self' ) {
foreach ( $recips as $r )
if ( $r [ 'hash' ] === $hash )
return array ( 'hash' => $hash );
}
if ( $scope === 'contacts' ) {
$condensed_recips = array ();
foreach ( $recips as $rr )
$condensed_recips [] = $rr [ 'hash' ];
$results = array ();
2014-02-17 00:04:46 +00:00
$r = q ( " select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and not ( channel_pageflags & %d ) " ,
dbesc ( $hash ),
intval ( PAGE_REMOVED )
2013-02-15 22:13:58 +00:00
);
if ( $r ) {
foreach ( $r as $rr )
if ( in_array ( $rr [ 'hash' ], $condensed_recips ))
$results [] = array ( 'hash' => $rr [ 'hash' ]);
}
return $results ;
}
return array ();
}
2012-11-27 05:20:16 +00:00
2012-11-28 01:09:01 +00:00
function process_delivery ( $sender , $arr , $deliveries , $relay ) {
2012-11-27 05:20:16 +00:00
2013-01-01 05:33:11 +00:00
$result = array ();
2013-10-02 09:50:02 +00:00
// We've validated the sender. Now make sure that the sender is the owner or author
2013-10-02 11:13:35 +00:00
if ( $sender [ 'hash' ] != $arr [ 'owner_xchan' ] && $sender [ 'hash' ] != $arr [ 'author_xchan' ]) {
2013-10-02 09:50:02 +00:00
logger ( 'process_delivery: sender is not owner or author' );
return ;
}
2012-11-27 05:20:16 +00:00
foreach ( $deliveries as $d ) {
$r = q ( " select * from channel where channel_hash = '%s' limit 1 " ,
dbesc ( $d [ 'hash' ])
);
2013-01-01 05:33:11 +00:00
if ( ! $r ) {
2013-07-22 00:19:16 +00:00
$result [] = array ( $d [ 'hash' ], 'recipients not found' );
2012-11-27 05:20:16 +00:00
continue ;
2013-01-01 05:33:11 +00:00
}
2013-01-01 08:45:44 +00:00
2012-11-27 05:20:16 +00:00
$channel = $r [ 0 ];
2013-06-16 07:57:39 +00:00
$tag_delivery = tgroup_check ( $channel [ 'channel_id' ], $arr );
2013-03-22 01:25:41 +00:00
$perm = (( $arr [ 'mid' ] == $arr [ 'parent_mid' ]) ? 'send_stream' : 'post_comments' );
2012-11-27 05:20:16 +00:00
2013-07-30 00:30:46 +00:00
// This is our own post, possibly coming from a channel clone
if ( $arr [ 'owner_xchan' ] == $d [ 'hash' ]) {
$arr [ 'item_flags' ] = $arr [ 'item_flags' ] | ITEM_WALL ;
}
else {
// clear the wall flag if it is set
if ( $arr [ 'item_flags' ] & ITEM_WALL ) {
$arr [ 'item_flags' ] = ( $arr [ 'item_flags' ] ^ ITEM_WALL );
}
}
2013-06-16 07:57:39 +00:00
if (( ! perm_is_allowed ( $channel [ 'channel_id' ], $sender [ 'hash' ], $perm )) && ( ! $tag_delivery )) {
2012-11-27 05:20:16 +00:00
logger ( " permission denied for delivery { $channel [ 'channel_id' ] } " );
2013-07-22 00:19:16 +00:00
$result [] = array ( $d [ 'hash' ], 'permission denied' , $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2012-11-27 05:20:16 +00:00
continue ;
}
2012-11-28 01:09:01 +00:00
2012-11-27 05:20:16 +00:00
if ( $arr [ 'item_restrict' ] & ITEM_DELETED ) {
2013-07-02 02:41:11 +00:00
// remove_community_tag is a no-op if this isn't a community tag activity
remove_community_tag ( $sender , $arr , $channel [ 'channel_id' ]);
2014-01-10 20:37:48 +00:00
2013-01-29 03:24:36 +00:00
$item_id = delete_imported_item ( $sender , $arr , $channel [ 'channel_id' ]);
2014-01-04 11:58:21 +00:00
$result [] = array ( $d [ 'hash' ],(( $item_id ) ? 'deleted' : 'delete_failed' ), $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2013-01-29 03:24:36 +00:00
if ( $relay && $item_id ) {
logger ( 'process_delivery: invoking relay' );
proc_run ( 'php' , 'include/notifier.php' , 'relay' , intval ( $item_id ));
2013-07-22 00:19:16 +00:00
$result [] = array ( $d [ 'hash' ], 'relayed' , $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2013-01-29 03:24:36 +00:00
}
2012-11-27 05:20:16 +00:00
continue ;
}
2013-06-24 06:13:07 +00:00
// for events, extract the event info and create an event linked to an item
2013-01-16 08:59:43 +00:00
2013-01-16 11:18:32 +00:00
if (( x ( $arr , 'obj_type' )) && ( activity_match ( $arr [ 'obj_type' ], ACTIVITY_OBJ_EVENT ))) {
2013-01-16 08:59:43 +00:00
require_once ( 'include/event.php' );
$ev = bbtoevent ( $arr [ 'body' ]);
2013-12-26 08:14:17 +00:00
if ( x ( $ev , 'desc' ) && x ( $ev , 'start' )) {
2013-01-16 08:59:43 +00:00
$ev [ 'event_xchan' ] = $arr [ 'author_xchan' ];
$ev [ 'uid' ] = $channel [ 'channel_id' ];
$ev [ 'account' ] = $channel [ 'channel_account_id' ];
$ev [ 'edited' ] = $arr [ 'edited' ];
2013-03-22 01:25:41 +00:00
$ev [ 'mid' ] = $arr [ 'mid' ];
2013-01-20 23:36:04 +00:00
$ev [ 'private' ] = $arr [ 'item_private' ];
2013-01-16 08:59:43 +00:00
// is this an edit?
2013-03-22 01:25:41 +00:00
$r = q ( " SELECT resource_id FROM item where mid = '%s' and uid = %d and resource_type = 'event' limit 1 " ,
dbesc ( $arr [ 'mid' ]),
2013-01-16 11:18:32 +00:00
intval ( $channel [ 'channel_id' ])
2013-01-16 08:59:43 +00:00
);
2013-01-20 23:36:04 +00:00
if ( $r ) {
$ev [ 'event_hash' ] = $r [ 0 ][ 'resource_id' ];
}
2013-01-25 03:45:08 +00:00
2013-01-16 08:59:43 +00:00
$xyz = event_store ( $ev );
2013-01-25 03:45:08 +00:00
2013-07-22 00:19:16 +00:00
$result = array ( $d [ 'hash' ], 'event processed' , $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2013-01-16 08:59:43 +00:00
continue ;
}
}
2013-03-22 01:25:41 +00:00
$r = q ( " select id, edited from item where mid = '%s' and uid = %d limit 1 " ,
dbesc ( $arr [ 'mid' ]),
2012-11-28 01:09:01 +00:00
intval ( $channel [ 'channel_id' ])
2012-11-27 05:20:16 +00:00
);
2012-11-28 01:09:01 +00:00
if ( $r ) {
2013-03-01 02:20:42 +00:00
if ( $arr [ 'edited' ] > $r [ 0 ][ 'edited' ]) {
$arr [ 'id' ] = $r [ 0 ][ 'id' ];
2013-03-01 02:59:03 +00:00
$arr [ 'uid' ] = $channel [ 'channel_id' ];
2012-11-28 01:09:01 +00:00
update_imported_item ( $sender , $arr , $channel [ 'channel_id' ]);
2013-03-01 02:20:42 +00:00
}
2013-07-22 00:19:16 +00:00
$result [] = array ( $d [ 'hash' ], 'updated' , $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2012-11-28 01:09:01 +00:00
$item_id = $r [ 0 ][ 'id' ];
}
2012-11-27 05:20:16 +00:00
else {
$arr [ 'aid' ] = $channel [ 'channel_account_id' ];
$arr [ 'uid' ] = $channel [ 'channel_id' ];
2013-09-11 02:06:06 +00:00
$item_result = item_store ( $arr );
$item_id = $item_result [ 'item_id' ];
$result [] = array ( $d [ 'hash' ],(( $item_id ) ? 'posted' : 'storage failed:' . $item_result [ 'message' ]), $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2012-11-27 05:20:16 +00:00
}
2012-11-28 01:09:01 +00:00
if ( $relay && $item_id ) {
logger ( 'process_delivery: invoking relay' );
proc_run ( 'php' , 'include/notifier.php' , 'relay' , intval ( $item_id ));
2013-07-22 00:19:16 +00:00
$result [] = array ( $d [ 'hash' ], 'relayed' , $channel [ 'channel_name' ] . ' <' . $channel [ 'channel_address' ] . '@' . get_app () -> get_hostname () . '>' );
2012-11-28 01:09:01 +00:00
}
2012-11-27 05:20:16 +00:00
}
2013-01-01 08:45:44 +00:00
if ( ! $deliveries )
$result [] = array ( '' , 'no recipients' );
2013-01-25 03:45:08 +00:00
logger ( 'process_delivery: local results: ' . print_r ( $result , true ), LOGGER_DEBUG );
2013-01-03 10:21:35 +00:00
2013-01-01 05:33:11 +00:00
return $result ;
2012-11-27 05:20:16 +00:00
}
2012-12-06 00:44:07 +00:00
2013-07-02 02:41:11 +00:00
function remove_community_tag ( $sender , $arr , $uid ) {
if ( ! ( activity_match ( $arr [ 'verb' ], ACTIVITY_TAG ) && ( $arr [ 'obj_type' ] == ACTIVITY_OBJ_TAGTERM )))
return ;
logger ( 'remove_community_tag: invoked' );
if ( ! get_pconfig ( $uid , 'system' , 'blocktags' )) {
logger ( 'remove_community tag: permission denied.' );
return ;
}
$r = q ( " select * from item where mid = '%s' and uid = %d limit 1 " ,
dbesc ( $arr [ 'mid' ]),
intval ( $uid )
);
if ( ! $r ) {
logger ( 'remove_community_tag: no item' );
return ;
}
if (( $sender [ 'hash' ] != $r [ 0 ][ 'owner_xchan' ]) && ( $sender [ 'hash' ] != $r [ 0 ][ 'author_xchan' ])) {
logger ( 'remove_community_tag: sender not authorised.' );
return ;
}
$i = $r [ 0 ];
if ( $i [ 'target' ])
2013-08-06 10:54:49 +00:00
$i [ 'target' ] = json_decode_plus ( $i [ 'target' ]);
2013-07-02 02:41:11 +00:00
if ( $i [ 'object' ])
2013-08-06 10:54:49 +00:00
$i [ 'object' ] = json_decode_plus ( $i [ 'object' ]);
2013-07-02 02:41:11 +00:00
if ( ! ( $i [ 'target' ] && $i [ 'object' ])) {
logger ( 'remove_community_tag: no target/object' );
return ;
}
$message_id = $i [ 'target' ][ 'id' ];
$r = q ( " select id from item where mid = '%s' and uid = %d limit 1 " ,
dbesc ( $message_id ),
intval ( $uid )
);
if ( ! $r ) {
logger ( 'remove_community_tag: no parent message' );
return ;
}
$x = q ( " delete from term where uid = %d and oid = %d and otype = %d and type = %d and term = '%s' and url = '%s' limit 1 " ,
intval ( $uid ),
intval ( $r [ 0 ][ 'id' ]),
intval ( TERM_OBJ_POST ),
intval ( TERM_HASHTAG ),
dbesc ( $i [ 'object' ][ 'title' ]),
dbesc ( get_rel_link ( $i [ 'object' ][ 'link' ], 'alternate' ))
);
return ;
}
2012-11-27 05:20:16 +00:00
function update_imported_item ( $sender , $item , $uid ) {
2013-03-01 02:20:42 +00:00
2013-09-11 02:06:06 +00:00
$x = item_store_update ( $item );
if ( ! $x [ 'item_id' ])
logger ( 'update_imported_item: failed: ' . $x [ 'message' ]);
else
logger ( 'update_imported_item' );
2012-11-27 05:20:16 +00:00
}
function delete_imported_item ( $sender , $item , $uid ) {
2013-01-29 03:24:36 +00:00
logger ( 'delete_imported_item invoked' , LOGGER_DEBUG );
2014-01-10 20:37:48 +00:00
$r = q ( " select id, item_restrict from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
2013-03-22 01:25:41 +00:00
and mid = '%s' and uid = % d limit 1 " ,
2012-11-27 05:20:16 +00:00
dbesc ( $sender [ 'hash' ]),
2014-01-04 11:58:21 +00:00
dbesc ( $sender [ 'hash' ]),
2012-11-27 05:20:16 +00:00
dbesc ( $sender [ 'hash' ]),
2013-03-22 01:25:41 +00:00
dbesc ( $item [ 'mid' ]),
2012-11-27 05:20:16 +00:00
intval ( $uid )
);
2013-01-29 03:24:36 +00:00
2012-11-27 05:20:16 +00:00
if ( ! $r ) {
logger ( 'delete_imported_item: failed: ownership issue' );
2013-01-29 03:24:36 +00:00
return false ;
2012-11-27 05:20:16 +00:00
}
2014-01-10 20:37:48 +00:00
if ( $r [ 0 ][ 'item_restrict' ] & ITEM_DELETED ) {
logger ( 'delete_imported_item: item was already deleted' );
return false ;
}
2012-11-27 05:20:16 +00:00
2013-01-25 00:44:10 +00:00
require_once ( 'include/items.php' );
drop_item ( $r [ 0 ][ 'id' ], false );
2013-12-26 08:14:17 +00:00
tag_deliver ( $uid , $r [ 0 ][ 'id' ]);
2013-01-29 03:24:36 +00:00
return $r [ 0 ][ 'id' ];
2012-11-27 05:20:16 +00:00
}
2012-12-06 00:44:07 +00:00
function process_mail_delivery ( $sender , $arr , $deliveries ) {
2013-05-17 03:43:24 +00:00
$result = array ();
2013-10-03 04:04:48 +00:00
if ( $sender [ 'hash' ] != $arr [ 'from_xchan' ]) {
logger ( 'process_mail_delivery: sender is not mail author' );
return ;
}
2012-12-06 00:44:07 +00:00
foreach ( $deliveries as $d ) {
$r = q ( " select * from channel where channel_hash = '%s' limit 1 " ,
dbesc ( $d [ 'hash' ])
);
2013-05-17 03:43:24 +00:00
if ( ! $r ) {
$result [] = array ( $d [ 'hash' ], 'not found' );
2012-12-06 00:44:07 +00:00
continue ;
2013-05-17 03:43:24 +00:00
}
2012-12-06 00:44:07 +00:00
$channel = $r [ 0 ];
if ( ! perm_is_allowed ( $channel [ 'channel_id' ], $sender [ 'hash' ], 'post_mail' )) {
logger ( " permission denied for mail delivery { $channel [ 'channel_id' ] } " );
2013-07-16 02:04:23 +00:00
$result [] = array ( $d [ 'hash' ], 'permission denied' , $channel [ 'channel_name' ]);
2012-12-06 00:44:07 +00:00
continue ;
}
2013-03-22 01:25:41 +00:00
$r = q ( " select id from mail where mid = '%s' and channel_id = %d limit 1 " ,
dbesc ( $arr [ 'mid' ]),
2012-12-06 00:44:07 +00:00
intval ( $channel [ 'channel_id' ])
);
if ( $r ) {
2013-02-28 04:38:33 +00:00
if ( $arr [ 'mail_flags' ] & MAIL_RECALLED ) {
$x = q ( " delete from mail where id = %d and channel_id = %d limit 1 " ,
intval ( $r [ 0 ][ 'id' ]),
intval ( $channel [ 'channel_id' ])
);
2013-07-16 02:04:23 +00:00
$result [] = array ( $d [ 'hash' ], 'mail recalled' , $channel [ 'channel_name' ]);
2013-02-28 04:38:33 +00:00
logger ( 'mail_recalled' );
}
else {
2013-07-16 02:04:23 +00:00
$result [] = array ( $d [ 'hash' ], 'duplicate mail received' , $channel [ 'channel_name' ]);
2013-02-28 04:38:33 +00:00
logger ( 'duplicate mail received' );
}
2012-12-06 00:44:07 +00:00
continue ;
}
else {
$arr [ 'account_id' ] = $channel [ 'channel_account_id' ];
$arr [ 'channel_id' ] = $channel [ 'channel_id' ];
$item_id = mail_store ( $arr );
2013-07-16 02:04:23 +00:00
$result [] = array ( $d [ 'hash' ], 'mail delivered' , $channel [ 'channel_name' ]);
2013-01-06 02:08:06 +00:00
2012-12-06 00:44:07 +00:00
}
}
2013-05-17 03:43:24 +00:00
return $result ;
2012-12-06 00:44:07 +00:00
}
2012-12-22 12:33:32 +00:00
function process_profile_delivery ( $sender , $arr , $deliveries ) {
2012-12-28 07:33:37 +00:00
// deliveries is irrelevant, what to do about birthday notification....?
2013-01-25 03:45:08 +00:00
logger ( 'process_profile_delivery' , LOGGER_DEBUG );
2013-09-25 03:13:53 +00:00
$r = q ( " select xchan_addr from xchan where xchan_hash = '%s' limit 1 " ,
dbesc ( $sender [ 'hash' ])
);
if ( $r )
2013-09-26 04:22:36 +00:00
import_directory_profile ( $sender [ 'hash' ], $arr , $r [ 0 ][ 'xchan_addr' ], 1 , 0 );
2012-12-27 02:18:56 +00:00
}
2013-05-01 01:16:51 +00:00
/*
* @ function import_directory_profile
*
* @ returns boolean $updated if something changed
*
*/
2013-09-26 04:22:36 +00:00
function import_directory_profile ( $hash , $profile , $addr , $ud_flags = 1 , $suppress_update = 0 ) {
2012-12-27 02:18:56 +00:00
2013-01-25 03:45:08 +00:00
logger ( 'import_directory_profile' , LOGGER_DEBUG );
2012-12-27 02:18:56 +00:00
if ( ! $hash )
2013-05-01 01:16:51 +00:00
return false ;
2012-12-27 02:18:56 +00:00
$arr = array ();
$arr [ 'xprof_hash' ] = $hash ;
2013-12-12 07:13:36 +00:00
$arr [ 'xprof_desc' ] = (( $profile [ 'description' ]) ? htmlspecialchars ( $profile [ 'description' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
2012-12-27 02:18:56 +00:00
$arr [ 'xprof_dob' ] = datetime_convert ( '' , '' , $profile [ 'birthday' ], 'Y-m-d' ); // !!!! check this for 0000 year
2013-06-30 07:38:02 +00:00
$arr [ 'xprof_age' ] = (( $profile [ 'age' ]) ? intval ( $profile [ 'age' ]) : 0 );
2013-12-12 07:13:36 +00:00
$arr [ 'xprof_gender' ] = (( $profile [ 'gender' ]) ? htmlspecialchars ( $profile [ 'gender' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_marital' ] = (( $profile [ 'marital' ]) ? htmlspecialchars ( $profile [ 'marital' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_sexual' ] = (( $profile [ 'sexual' ]) ? htmlspecialchars ( $profile [ 'sexual' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_locale' ] = (( $profile [ 'locale' ]) ? htmlspecialchars ( $profile [ 'locale' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_region' ] = (( $profile [ 'region' ]) ? htmlspecialchars ( $profile [ 'region' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_postcode' ] = (( $profile [ 'postcode' ]) ? htmlspecialchars ( $profile [ 'postcode' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_country' ] = (( $profile [ 'country' ]) ? htmlspecialchars ( $profile [ 'country' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
2012-12-27 02:18:56 +00:00
2013-12-25 09:57:04 +00:00
$arr [ 'xprof_about' ] = (( $profile [ 'about' ]) ? htmlspecialchars ( $profile [ 'about' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_homepage' ] = (( $profile [ 'homepage' ]) ? htmlspecialchars ( $profile [ 'homepage' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
$arr [ 'xprof_hometown' ] = (( $profile [ 'hometown' ]) ? htmlspecialchars ( $profile [ 'hometown' ], ENT_COMPAT , 'UTF-8' , false ) : '' );
2012-12-27 22:36:06 +00:00
$clean = array ();
2012-12-27 02:18:56 +00:00
if ( array_key_exists ( 'keywords' , $profile ) and is_array ( $profile [ 'keywords' ])) {
2012-12-28 07:33:37 +00:00
import_directory_keywords ( $hash , $profile [ 'keywords' ]);
2012-12-27 22:36:06 +00:00
foreach ( $profile [ 'keywords' ] as $kw ) {
2013-12-12 07:13:36 +00:00
$kw = trim ( htmlspecialchars ( $kw , ENT_COMPAT , 'UTF-8' , false ));
2013-05-09 04:30:54 +00:00
$kw = trim ( $kw , ',' );
2013-09-15 00:20:24 +00:00
$clean [] = $kw ;
2012-12-27 22:36:06 +00:00
}
2012-12-27 02:18:56 +00:00
}
2012-12-27 22:36:06 +00:00
$arr [ 'xprof_keywords' ] = implode ( ' ' , $clean );
2013-09-20 02:50:13 +00:00
// Self censored, make it so
// These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult".
2013-09-26 23:25:28 +00:00
2013-09-20 02:50:13 +00:00
if ( in_arrayi ( 'nsfw' , $clean ) || in_arrayi ( 'adult' , $clean )) {
q ( " update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s' limit 1 " ,
2013-09-26 23:25:28 +00:00
intval ( XCHAN_FLAGS_SELFCENSORED ),
2013-09-20 04:13:45 +00:00
dbesc ( $hash )
2013-09-20 02:50:13 +00:00
);
}
2012-12-27 02:18:56 +00:00
$r = q ( " select * from xprof where xprof_hash = '%s' limit 1 " ,
dbesc ( $hash )
);
if ( $r ) {
2013-05-01 01:16:51 +00:00
$update = false ;
foreach ( $r [ 0 ] as $k => $v ) {
if (( array_key_exists ( $k , $arr )) && ( $arr [ $k ] != $v )) {
2013-09-15 10:48:43 +00:00
logger ( 'import_directory_profile: update' . $k . ' => ' . $arr [ $k ]);
2013-05-01 01:16:51 +00:00
$update = true ;
break ;
}
}
if ( $update ) {
$x = q ( " update xprof set
xprof_desc = '%s' ,
xprof_dob = '%s' ,
2013-07-03 05:29:24 +00:00
xprof_age = % d ,
2013-05-01 01:16:51 +00:00
xprof_gender = '%s' ,
xprof_marital = '%s' ,
xprof_sexual = '%s' ,
xprof_locale = '%s' ,
xprof_region = '%s' ,
xprof_postcode = '%s' ,
xprof_country = '%s' ,
2013-12-25 09:57:04 +00:00
xprof_about = '%s' ,
xprof_homepage = '%s' ,
xprof_hometown = '%s' ,
2013-05-01 01:16:51 +00:00
xprof_keywords = '%s'
where xprof_hash = '%s' limit 1 " ,
dbesc ( $arr [ 'xprof_desc' ]),
dbesc ( $arr [ 'xprof_dob' ]),
2013-07-03 05:22:13 +00:00
intval ( $arr [ 'xprof_age' ]),
2013-05-01 01:16:51 +00:00
dbesc ( $arr [ 'xprof_gender' ]),
dbesc ( $arr [ 'xprof_marital' ]),
dbesc ( $arr [ 'xprof_sexual' ]),
dbesc ( $arr [ 'xprof_locale' ]),
dbesc ( $arr [ 'xprof_region' ]),
dbesc ( $arr [ 'xprof_postcode' ]),
dbesc ( $arr [ 'xprof_country' ]),
2013-12-25 09:57:04 +00:00
dbesc ( $arr [ 'xprof_about' ]),
dbesc ( $arr [ 'xprof_homepage' ]),
dbesc ( $arr [ 'xprof_hometown' ]),
2013-05-01 01:16:51 +00:00
dbesc ( $arr [ 'xprof_keywords' ]),
dbesc ( $arr [ 'xprof_hash' ])
);
}
2012-12-27 02:18:56 +00:00
}
else {
2013-05-01 01:16:51 +00:00
$update = true ;
2013-09-15 10:48:43 +00:00
logger ( 'import_directory_profile: new profile' );
2014-01-05 23:51:44 +00:00
$x = q ( " insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') " ,
2012-12-27 02:18:56 +00:00
dbesc ( $arr [ 'xprof_hash' ]),
dbesc ( $arr [ 'xprof_desc' ]),
dbesc ( $arr [ 'xprof_dob' ]),
2013-07-03 05:22:13 +00:00
intval ( $arr [ 'xprof_age' ]),
2012-12-27 02:18:56 +00:00
dbesc ( $arr [ 'xprof_gender' ]),
dbesc ( $arr [ 'xprof_marital' ]),
dbesc ( $arr [ 'xprof_sexual' ]),
dbesc ( $arr [ 'xprof_locale' ]),
dbesc ( $arr [ 'xprof_region' ]),
dbesc ( $arr [ 'xprof_postcode' ]),
2012-12-27 22:36:06 +00:00
dbesc ( $arr [ 'xprof_country' ]),
2013-12-25 09:57:04 +00:00
dbesc ( $arr [ 'xprof_about' ]),
dbesc ( $arr [ 'xprof_homepage' ]),
dbesc ( $arr [ 'xprof_hometown' ]),
2012-12-27 22:36:06 +00:00
dbesc ( $arr [ 'xprof_keywords' ])
2012-12-27 02:18:56 +00:00
);
}
2012-12-27 03:39:37 +00:00
2013-07-24 05:33:56 +00:00
$d = array ( 'xprof' => $arr , 'profile' => $profile , 'update' => $update );
call_hooks ( 'import_directory_profile' , $d );
2013-09-26 04:22:36 +00:00
if (( $d [ 'update' ]) && ( ! $suppress_update ))
2013-09-25 03:13:53 +00:00
update_modtime ( $arr [ 'xprof_hash' ], random_string () . '@' . get_app () -> get_hostname (), $addr , $ud_flags );
2013-07-24 05:33:56 +00:00
return $d [ 'update' ];
2012-12-27 02:18:56 +00:00
}
2012-12-28 07:33:37 +00:00
function import_directory_keywords ( $hash , $keywords ) {
$existing = array ();
$r = q ( " select * from xtag where xtag_hash = '%s' " ,
dbesc ( $hash )
);
if ( $r ) {
foreach ( $r as $rr )
$existing [] = $rr [ 'xtag_term' ];
}
$clean = array ();
foreach ( $keywords as $kw ) {
2013-12-12 07:13:36 +00:00
$kw = trim ( htmlspecialchars ( $kw , ENT_COMPAT , 'UTF-8' , false ));
2013-09-19 08:45:06 +00:00
$kw = trim ( $kw , ',' );
2012-12-28 07:33:37 +00:00
$clean [] = $kw ;
}
foreach ( $existing as $x ) {
if ( ! in_array ( $x , $clean ))
$r = q ( " delete from xtag where xtag_hash = '%s' and xtag_term = '%s' limit 1 " ,
dbesc ( $hash ),
dbesc ( $x )
);
}
foreach ( $clean as $x ) {
if ( ! in_array ( $x , $existing ))
2013-05-09 04:30:54 +00:00
$r = q ( " insert into xtag ( xtag_hash, xtag_term) values ( '%s' ,'%s' ) " ,
2012-12-28 07:33:37 +00:00
dbesc ( $hash ),
dbesc ( $x )
);
}
2013-03-14 00:27:17 +00:00
}
2013-09-25 03:13:53 +00:00
function update_modtime ( $hash , $guid , $addr , $flags = 0 ) {
2013-11-05 04:43:32 +00:00
$dirmode = intval ( get_config ( 'system' , 'directory_mode' ));
if ( $dirmode == DIRECTORY_MODE_NORMAL )
return ;
2013-10-01 01:33:27 +00:00
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 )
);
}
else {
q ( " update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) " ,
intval ( UPDATE_FLAGS_UPDATED ),
2013-10-15 04:09:39 +00:00
dbesc ( $addr ),
2013-10-01 01:33:27 +00:00
intval ( UPDATE_FLAGS_UPDATED )
);
}
2013-03-14 00:27:17 +00:00
}
2013-07-24 05:33:56 +00:00
function import_site ( $arr , $pubkey ) {
if ( ( ! is_array ( $arr )) || ( ! $arr [ 'url' ]) || ( ! $arr [ 'url_sig' ]))
return false ;
if ( ! rsa_verify ( $arr [ 'url' ], base64url_decode ( $arr [ 'url_sig' ]), $pubkey )) {
logger ( 'import_site: bad url_sig' );
return false ;
}
$update = false ;
2013-09-16 02:04:11 +00:00
$exists = false ;
2013-07-24 05:33:56 +00:00
$r = q ( " select * from site where site_url = '%s' limit 1 " ,
dbesc ( $arr [ 'url' ])
);
2013-09-16 02:04:11 +00:00
if ( $r ) {
$exists = true ;
$siterecord = $r [ 0 ];
}
2013-07-24 05:33:56 +00:00
$site_directory = 0 ;
if ( $arr [ 'directory_mode' ] == 'normal' )
$site_directory = DIRECTORY_MODE_NORMAL ;
if ( $arr [ 'directory_mode' ] == 'primary' )
$site_directory = DIRECTORY_MODE_PRIMARY ;
if ( $arr [ 'directory_mode' ] == 'secondary' )
$site_directory = DIRECTORY_MODE_SECONDARY ;
if ( $arr [ 'directory_mode' ] == 'standalone' )
$site_directory = DIRECTORY_MODE_STANDALONE ;
$register_policy = 0 ;
if ( $arr [ 'register_policy' ] == 'closed' )
$register_policy = REGISTER_CLOSED ;
if ( $arr [ 'register_policy' ] == 'open' )
$register_policy = REGISTER_OPEN ;
if ( $arr [ 'register_policy' ] == 'approve' )
$register_policy = REGISTER_APPROVE ;
2013-09-06 05:00:06 +00:00
$access_policy = 0 ;
if ( array_key_exists ( 'access_policy' , $arr )) {
if ( $arr [ 'access_policy' ] === 'private' )
$access_policy = ACCESS_PRIVATE ;
if ( $arr [ 'access_policy' ] === 'paid' )
$access_policy = ACCESS_PAID ;
if ( $arr [ 'access_policy' ] === 'free' )
$access_policy = ACCESS_FREE ;
2013-09-19 00:47:26 +00:00
if ( $arr [ 'access_policy' ] === 'tiered' )
$access_policy = ACCESS_TIERED ;
2013-09-06 05:00:06 +00:00
}
2014-02-07 08:50:04 +00:00
// don't let insecure sites register as public hubs
if ( strpos ( $arr [ 'url' ], 'https://' ) === false )
$access_policy = ACCESS_PRIVATE ;
if ( $access_policy != ACCESS_PRIVATE ) {
$x = z_fetch_url ( $arr [ 'url' ] . '/siteinfo/json' );
if ( ! $x [ 'success' ])
$access_policy = ACCESS_PRIVATE ;
}
2013-12-12 07:13:36 +00:00
$directory_url = htmlspecialchars ( $arr [ 'directory_url' ], ENT_COMPAT , 'UTF-8' , false );
$url = htmlspecialchars ( $arr [ 'url' ], ENT_COMPAT , 'UTF-8' , false );
$sellpage = htmlspecialchars ( $arr [ 'sellpage' ], ENT_COMPAT , 'UTF-8' , false );
$site_location = htmlspecialchars ( $arr [ 'location' ], ENT_COMPAT , 'UTF-8' , false );
2013-09-16 02:04:11 +00:00
if ( $exists ) {
if (( $siterecord [ 'site_flags' ] != $site_directory )
|| ( $siterecord [ 'site_access' ] != $access_policy )
|| ( $siterecord [ 'site_directory' ] != $directory_url )
2013-09-18 05:27:51 +00:00
|| ( $siterecord [ 'site_sellpage' ] != $sellpage )
2013-10-30 08:58:45 +00:00
|| ( $siterecord [ 'site_location' ] != $site_location )
2013-09-16 02:04:11 +00:00
|| ( $siterecord [ 'site_register' ] != $register_policy )) {
$update = true ;
2013-09-16 06:02:18 +00:00
// logger('import_site: input: ' . print_r($arr,true));
// logger('import_site: stored: ' . print_r($siterecord,true));
2013-09-16 05:19:24 +00:00
2013-10-30 08:58:45 +00:00
$r = q ( " update site set site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s'
2013-09-16 02:04:11 +00:00
where site_url = '%s' limit 1 " ,
2013-10-30 08:58:45 +00:00
dbesc ( $site_location ),
2013-09-16 02:04:11 +00:00
intval ( $site_directory ),
intval ( $access_policy ),
dbesc ( $directory_url ),
intval ( $register_policy ),
dbesc ( datetime_convert ()),
2013-09-18 05:27:51 +00:00
dbesc ( $sellpage ),
2013-09-16 02:04:11 +00:00
dbesc ( $url )
);
if ( ! $r ) {
logger ( 'import_site: update failed. ' . print_r ( $arr , true ));
}
2013-07-24 05:33:56 +00:00
}
}
else {
2013-09-16 02:04:11 +00:00
$update = true ;
2013-10-30 08:58:45 +00:00
$r = q ( " insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage )
values ( '%s' , '%s' , % d , % d , '%s' , '%s' , % d , '%s' ) " ,
dbesc ( $site_location ),
2013-09-16 02:04:11 +00:00
dbesc ( $url ),
2013-09-06 05:00:06 +00:00
intval ( $access_policy ),
2013-10-30 08:30:37 +00:00
intval ( $site_directory ),
2013-07-24 05:33:56 +00:00
dbesc ( datetime_convert ()),
2013-09-16 02:04:11 +00:00
dbesc ( $directory_url ),
2013-09-18 05:27:51 +00:00
intval ( $register_policy ),
dbesc ( $sellpage )
2013-07-24 05:33:56 +00:00
);
if ( ! $r ) {
logger ( 'import_site: record create failed. ' . print_r ( $arr , true ));
}
}
2013-09-16 06:02:18 +00:00
return $update ;
2013-07-24 05:33:56 +00:00
}
2013-07-25 23:00:04 +00:00
/**
* Send a zot packet to all hubs where this channel is duplicated , refreshing
* such things as personal settings , channel permissions , address book updates , etc .
*/
function build_sync_packet ( $uid = 0 , $packet = null ) {
$a = get_app ();
logger ( 'build_sync_packet' );
2013-07-26 03:10:53 +00:00
2013-07-25 23:00:04 +00:00
if ( ! $uid )
$uid = local_user ();
if ( ! $uid )
return ;
2013-07-26 03:10:53 +00:00
$r = q ( " select * from channel where channel_id = %d limit 1 " ,
intval ( $uid )
);
if ( ! $r )
return ;
$channel = $r [ 0 ];
2013-07-25 23:00:04 +00:00
$h = q ( " select * from hubloc where hubloc_hash = '%s' " ,
dbesc ( $channel [ 'channel_hash' ])
);
if ( ! $h )
return ;
$synchubs = array ();
foreach ( $h as $x ) {
if ( $x [ 'hubloc_host' ] == $a -> get_hostname ())
continue ;
$synchubs [] = $x ;
}
if ( ! $synchubs )
return ;
$r = q ( " select xchan_guid, xchan_guid_sig from xchan where xchan_hash = '%s' limit 1 " ,
dbesc ( $channel [ 'channel_hash' ])
);
if ( ! $r )
return ;
$env_recips = array ();
$env_recips [] = array ( 'guid' => $r [ 0 ][ 'xchan_guid' ], 'guid_sig' => $r [ 0 ][ 'xchan_guid_sig' ]);
$info = (( $packet ) ? $packet : array ());
$info [ 'type' ] = 'channel_sync' ;
if ( array_key_exists ( $uid , $a -> config ) && array_key_exists ( 'transient' , $a -> config [ $uid ])) {
$settings = $a -> config [ $uid ][ 'transient' ];
if ( $settings ) {
$info [ 'config' ] = $settings ;
}
}
if ( $channel ) {
$info [ 'channel' ] = array ();
foreach ( $channel as $k => $v ) {
// filter out any joined tables like xchan
if ( strpos ( $k , 'channel_' ) !== 0 )
continue ;
// don't pass these elements, they should not be synchronised
2013-07-29 04:04:03 +00:00
$disallowed = array ( 'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_prvkey' , 'channel_address' );
2013-07-25 23:00:04 +00:00
if ( in_array ( $k , $disallowed ))
continue ;
$info [ 'channel' ][ $k ] = $v ;
}
}
$interval = (( get_config ( 'system' , 'delivery_interval' ) !== false )
? intval ( get_config ( 'system' , 'delivery_interval' )) : 2 );
2013-07-26 02:50:55 +00:00
logger ( 'build_sync_packet: packet: ' . print_r ( $info , true ), LOGGER_DATA );
2013-07-25 23:00:04 +00:00
foreach ( $synchubs as $hub ) {
$hash = random_string ();
$n = zot_build_packet ( $channel , 'notify' , $env_recips , $hub [ 'hubloc_sitekey' ], $hash );
q ( " insert into outq ( outq_hash, outq_account, outq_channel, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s' ) " ,
dbesc ( $hash ),
intval ( $channel [ 'channel_account' ]),
intval ( $channel [ 'channel_id' ]),
dbesc ( $hub [ 'hubloc_callback' ]),
intval ( 1 ),
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
dbesc ( $n ),
dbesc ( json_encode ( $info ))
);
proc_run ( 'php' , 'include/deliver.php' , $hash );
if ( $interval )
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
}
}
2013-07-26 05:57:06 +00:00
function process_channel_sync_delivery ( $sender , $arr , $deliveries ) {
2013-07-26 10:50:46 +00:00
// FIXME - this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic.
// TODO: missing group membership changes
2013-07-26 05:57:06 +00:00
$result = array ();
foreach ( $deliveries as $d ) {
$r = q ( " select * from channel where channel_hash = '%s' limit 1 " ,
dbesc ( $d [ 'hash' ])
);
if ( ! $r ) {
$result [] = array ( $d [ 'hash' ], 'not found' );
continue ;
}
$channel = $r [ 0 ];
if ( $channel [ 'channel_hash' ] != $sender [ 'hash' ]) {
logger ( 'process_channel_sync_delivery: possible forgery. Sender ' . $sender [ 'hash' ] . ' is not ' . $channel [ 'channel_hash' ]);
$result [] = array ( $d [ 'hash' ], 'channel mismatch' , $channel [ 'channel_name' ]);
continue ;
}
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 ( 'channel' , $arr ) && is_array ( $arr [ 'channel' ]) && count ( $arr [ 'channel' ])) {
2014-02-11 03:20:55 +00:00
$disallowed = array ( 'channel_id' , 'channel_account_id' , 'channel_primary' , 'channel_prvkey' , 'channel_address' , 'channel_notifyflags' );
2013-07-26 05:57:06 +00:00
$clean = array ();
foreach ( $arr [ 'channel' ] as $k => $v ) {
if ( in_array ( $k , $disallowed ))
continue ;
$clean [ $k ] = $v ;
}
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
$r = dbq ( " UPDATE channel set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where channel_id = " . intval ( $channel [ 'channel_id' ]) . " limit 1 " );
}
}
}
if ( array_key_exists ( 'abook' , $arr ) && is_array ( $arr [ 'abook' ]) && count ( $arr [ 'abook' ])) {
$disallowed = array ( 'abook_id' , 'abook_account' , 'abook_channel' );
$clean = array ();
foreach ( $arr [ 'abook' ] as $abook ) {
2014-02-10 03:45:22 +00:00
// 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
if ( $abook [ 'abook_xchan' ] && $abook [ 'xchan_address' ]) {
$h = zot_get_hublocs ( $abook [ 'abook_xchan' ]);
if ( ! $h ) {
$f = zot_finger ( $abook [ 'xchan_address' ], $channel );
if ( ! $f [ 'success' ]) {
logger ( 'process_channel_sync_delivery: abook not probe-able' . $abook [ 'xchan_address' ]);
continue ;
}
$j = json_decode ( $f [ 'body' ], true );
if ( ! ( $j [ 'success' ] && $j [ 'guid' ])) {
logger ( 'process_channel_sync_delivery: probe failed.' );
continue ;
}
$x = import_xchan ( $j );
if ( ! $x [ 'success' ]) {
logger ( 'process_channel_sync_delivery: import failed.' );
continue ;
}
}
}
2013-07-26 05:57:06 +00:00
foreach ( $abook as $k => $v ) {
2013-08-27 03:58:07 +00:00
if ( in_array ( $k , $disallowed ) || ( strpos ( $k , 'abook' ) !== 0 ))
2013-07-26 05:57:06 +00:00
continue ;
$clean [ $k ] = $v ;
}
if ( ! array_key_exists ( 'abook_xchan' , $clean ))
continue ;
2013-09-09 03:38:15 +00:00
$r = q ( " select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1 " ,
dbesc ( $clean [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
// make sure we have an abook entry for this xchan on this system
if ( ! $r ) {
q ( " insert into abook ( abook_xchan, abook_channel ) values ('%s', %d ) " ,
dbesc ( $clean [ 'abook_xchan' ]),
intval ( $channel [ 'channel_id' ])
);
}
2013-07-26 05:57:06 +00:00
if ( count ( $clean )) {
foreach ( $clean as $k => $v ) {
$r = dbq ( " UPDATE abook set " . dbesc ( $k ) . " = ' " . dbesc ( $v )
. " ' where abook_xchan = ' " . dbesc ( $clean [ 'abook_xchan' ]) . " ' and abook_channel = " . intval ( $channel [ 'channel_id' ])
. " limit 1 " );
}
}
}
}
$result [] = array ( $d [ 'hash' ], 'channel sync updated' , $channel [ 'channel_name' ]);
}
return $result ;
}
2013-10-30 01:46:51 +00:00
// We probably should make rpost discoverable.
function get_rpost_path ( $observer ) {
if ( ! $observer )
return '' ;
$parsed = parse_url ( $observer [ 'xchan_url' ]);
return $parsed [ 'scheme' ] . '://' . $parsed [ 'host' ] . (( $parsed [ 'port' ]) ? ':' . $parsed [ 'port' ] : '' ) . '/rpost?f=' ;
2013-10-30 04:49:10 +00:00
}
2013-12-04 08:19:29 +00:00
function import_author_zot ( $x ) {
$hash = base64url_encode ( hash ( 'whirlpool' , $x [ 'guid' ] . $x [ 'guid_sig' ], true ));
$r = q ( " select hubloc_url from hubloc where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and (hubloc_flags & %d) limit 1 " ,
dbesc ( $x [ 'guid' ]),
dbesc ( $x [ 'guid_sig' ]),
intval ( HUBLOC_FLAGS_PRIMARY )
);
if ( $r ) {
logger ( 'import_author_zot: in cache' , LOGGER_DEBUG );
return $hash ;
}
logger ( 'import_author_zot: entry not in cache - probing: ' . print_r ( $x , true ), LOGGER_DEBUG );
$them = array ( 'hubloc_url' => $x [ 'url' ], 'xchan_guid' => $x [ 'guid' ], 'xchan_guid_sig' => $x [ 'guid_sig' ]);
if ( zot_refresh ( $them ))
return $hash ;
return false ;
}