2018-08-23 06:04:37 +00:00
< ? php
namespace Zotlabs\Module ;
use Zotlabs\Web\HTTPSig ;
use Zotlabs\Lib\ActivityStreams ;
use Zotlabs\Lib\Activity ;
2018-08-23 06:15:44 +00:00
use Zotlabs\Web\Controller ;
2018-08-23 06:04:37 +00:00
2018-08-23 06:15:44 +00:00
require_once ( 'include/items.php' );
2018-08-23 06:04:37 +00:00
2018-08-23 06:15:44 +00:00
class Inbox extends Controller {
2018-08-23 06:04:37 +00:00
function post () {
2018-10-04 02:10:52 +00:00
if ( defined ( 'NOMADIC' )) {
return ;
}
2018-10-11 00:58:51 +00:00
// This SHOULD be handled by the webserver, but in the RFC it is only indicated as
// a SHOULD and not a MUST, so some webservers fail to reject appropriately.
logger ( 'accepting: ' . $_SERVER [ 'HTTP_ACCEPT' ], LOGGER_DEBUG );
if (( array_key_exists ( 'HTTP_ACCEPT' , $_SERVER )) && ( $_SERVER [ 'HTTP_ACCEPT' ])
&& ( strpos ( $_SERVER [ 'HTTP_ACCEPT' ], '*' ) === false ) && ( ! ActivityStreams :: is_as_request ())) {
http_status_exit ( 406 , 'not acceptable' );
}
2018-08-23 06:04:37 +00:00
$sys_disabled = (( get_config ( 'system' , 'disable_discover_tab' ) || get_config ( 'system' , 'disable_activitypub_discover_tab' )) ? true : false );
$is_public = false ;
if ( argc () == 1 || argv ( 1 ) === '[public]' ) {
$is_public = true ;
}
else {
$channels = [ channelx_by_nick ( argv ( 1 )) ];
}
$data = file_get_contents ( 'php://input' );
if ( ! $data )
return ;
logger ( 'inbox_activity: ' . jindent ( $data ), LOGGER_DATA );
2018-09-07 04:24:56 +00:00
$hsig = HTTPSig :: verify ( $data );
2018-08-23 06:04:37 +00:00
$AS = new ActivityStreams ( $data );
//logger('debug: ' . $AS->debug());
2018-10-10 04:08:57 +00:00
if ( ! $AS -> is_valid ()) {
if ( $AS -> deleted ) {
// process mastodon user deletion activities, but only if we can validate the signature
if ( $hsig [ 'header_valid' ] && $hsig [ 'content_valid' ] && $hsig [ 'portable_id' ]) {
logger ( 'removing deleted actor' );
remove_all_xchan_resources ( $hsig [ 'portable_id' ]);
}
else {
logger ( 'ignoring deleted actor' );
}
}
2018-08-23 06:04:37 +00:00
return ;
2018-10-10 04:08:57 +00:00
}
2018-08-23 06:04:37 +00:00
2018-09-07 05:52:48 +00:00
// $observer_hash in this case is the sender
2018-09-07 04:51:52 +00:00
if ( $hsig [ 'header_valid' ] && $hsig [ 'content_valid' ] && $hsig [ 'portable_id' ]) {
$observer_hash = $hsig [ 'portable_id' ];
2018-09-07 04:24:56 +00:00
}
else {
$observer_hash = $AS -> actor [ 'id' ];
}
2018-08-23 06:04:37 +00:00
if ( ! $observer_hash )
return ;
2018-09-01 22:52:28 +00:00
if ( is_array ( $AS -> actor ) && array_key_exists ( 'id' , $AS -> actor )) {
2018-08-23 06:04:37 +00:00
Activity :: actor_store ( $AS -> actor [ 'id' ], $AS -> actor );
2018-09-01 22:52:28 +00:00
}
2018-08-23 06:04:37 +00:00
2018-10-05 01:40:57 +00:00
if ( is_array ( $AS -> obj ) && ActivityStreams :: is_an_actor ( $AS -> obj [ 'type' ])) {
2018-09-01 22:52:28 +00:00
Activity :: actor_store ( $AS -> obj [ 'id' ], $AS -> obj );
}
2018-08-23 06:04:37 +00:00
2018-10-12 04:05:30 +00:00
if ( is_array ( $AS -> obj ) && is_array ( $AS -> obj [ 'actor' ]) && array_key_exists ( 'id' , $AS -> obj [ 'actor' ]) && $AS -> obj [ 'actor' ][ 'id' ] !== $AS -> actor [ 'id' ]) {
2018-09-01 22:52:28 +00:00
Activity :: actor_store ( $AS -> obj [ 'actor' ][ 'id' ], $AS -> obj [ 'actor' ]);
2018-08-23 06:04:37 +00:00
}
if ( $is_public ) {
2018-10-05 01:40:57 +00:00
if ( $AS -> type === 'Follow' && $AS -> obj && ActivityStreams :: is_an_actor ( $AS -> obj [ 'type' ])) {
2018-09-04 01:22:31 +00:00
$channels = q ( " SELECT * from channel where channel_address = '%s' and channel_removed = 0 " ,
dbesc ( basename ( $AS -> obj [ 'id' ]))
2018-08-23 06:04:37 +00:00
);
}
else {
2018-09-04 01:22:31 +00:00
// deliver to anybody following $AS->actor
2018-08-23 06:04:37 +00:00
2018-09-04 01:22:31 +00:00
$channels = q ( " SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network = 'activitypub' and xchan_hash = '%s' ) and channel_removed = 0 " ,
dbesc ( $observer_hash )
);
2018-09-04 04:30:39 +00:00
if ( ! $channels ) {
$channels = [];
}
$parent = $AS -> parent_id ;
if ( $parent ) {
//this is a comment - deliver to everybody who owns the parent
$owners = q ( " SELECT * from channel where channel_id in ( SELECT uid from item where mid = '%s' ) " ,
dbesc ( $parent )
);
if ( $owners ) {
$channels = array_merge ( $channels , $owners );
}
}
2018-08-23 06:04:37 +00:00
}
if ( $channels === false )
$channels = [];
if ( in_array ( ACTIVITY_PUBLIC_INBOX , $AS -> recips )) {
// look for channels with send_stream = PERMS_PUBLIC
$r = q ( " select * from channel where channel_id in (select uid from pconfig where cat = 'perm_limits' and k = 'send_stream' and v = '1' ) and channel_removed = 0 " );
if ( $r ) {
$channels = array_merge ( $channels , $r );
}
if ( ! $sys_disabled ) {
$channels [] = get_sys_channel ();
}
}
}
2018-09-04 01:22:31 +00:00
if ( ! $channels ) {
logger ( 'no deliveries on this site' );
2018-08-23 06:04:37 +00:00
return ;
2018-09-04 01:22:31 +00:00
}
2018-08-23 06:04:37 +00:00
$saved_recips = [];
foreach ( [ 'to' , 'cc' , 'audience' ] as $x ) {
if ( array_key_exists ( $x , $AS -> data )) {
$saved_recips [ $x ] = $AS -> data [ $x ];
}
}
$AS -> set_recips ( $saved_recips );
foreach ( $channels as $channel ) {
switch ( $AS -> type ) {
case 'Follow' :
2018-10-05 01:40:57 +00:00
if ( $AS -> obj & ActivityStreams :: is_an_actor ( $AS -> obj [ 'type' ])) {
2018-08-23 06:04:37 +00:00
// do follow activity
Activity :: follow ( $channel , $AS );
continue ;
}
break ;
case 'Accept' :
if ( $AS -> obj & $AS -> obj [ 'type' ] === 'Follow' ) {
// do follow activity
Activity :: follow ( $channel , $AS );
continue ;
}
break ;
case 'Reject' :
default :
break ;
}
// These activities require permissions
$item = null ;
switch ( $AS -> type ) {
case 'Create' :
case 'Update' :
case 'Like' :
case 'Dislike' :
case 'Announce' :
2018-10-12 04:05:30 +00:00
// These require a resolvable object structure
if ( is_array ( $AS -> obj )) {
$item = Activity :: decode_note ( $AS );
}
else {
logger ( 'unresolved object: ' . print_r ( $AS -> obj , true ));
}
2018-08-23 06:04:37 +00:00
break ;
case 'Undo' :
if ( $AS -> obj & $AS -> obj [ 'type' ] === 'Follow' ) {
// do unfollow activity
Activity :: unfollow ( $channel , $AS );
break ;
}
case 'Delete' :
2018-10-11 01:53:26 +00:00
Activity :: drop ( $channel , $observer_hash , $AS );
break ;
2018-08-23 06:04:37 +00:00
case 'Add' :
case 'Remove' :
default :
break ;
}
if ( $item ) {
2018-10-16 02:29:32 +00:00
logger ( 'parsed_item: ' . print_r ( $item , true ), LOGGER_DATA );
2018-08-23 06:04:37 +00:00
Activity :: store ( $channel , $observer_hash , $AS , $item );
}
}
http_status_exit ( 200 , 'OK' );
}
function get () {
}
}