@ -19,6 +19,7 @@
// Submodules
# include "http/url.h"
# include "util/format.h"
// Stdlib
# include <stdlib.h>
@ -67,6 +68,102 @@ cleanup:
return result ;
}
static long submit_activity ( const char * postdata , const char * inbox , const char * deliver , struct crypto_keys * keys , struct fetch_data * fd , bool use_tor_proxy )
{
printf ( " Using inbox=%s \n " , inbox ) ;
printf ( " Using deliver=%s \n " , deliver ) ;
printf ( " Using proxy=%c \n " , use_tor_proxy ? ' Y ' : ' N ' ) ;
struct http_signature hs ;
memset ( & hs , 0 , sizeof ( hs ) ) ;
hs . input . url = deliver ;
hs . input . method = " post " ;
hs . input . post_data = postdata ;
if ( ! http_signature_make ( keys , & hs ) ) {
printf ( " ! Failed to make HTTP signature \n " ) ;
return 600 ;
}
char date_header [ 512 ] ;
snprintf ( date_header , sizeof ( date_header ) , " Date: %s " , hs . date ) ;
char sign_header [ 512 ] ;
snprintf ( sign_header , sizeof ( sign_header ) , " Signature: keyId= \" https://%s/owner/actor#mainKey \" ,headers= \" (request-target) host date content-length digest \" ,signature= \" %s \" " ,
g_server - > domain ,
hs . signature
) ;
char user_agent [ 512 ] ;
snprintf ( user_agent , sizeof ( user_agent ) , " User-Agent: curl (Apogee/0.1; +https://%s/owner/actor) " , g_server - > domain ) ;
char digest_header [ 512 ] ;
snprintf ( digest_header , sizeof ( digest_header ) , " Digest: %s " , hs . digest ) ;
char content_length_header [ 512 ] ;
snprintf ( content_length_header , sizeof ( content_length_header ) , " Content-Length: %d " , hs . content_length ) ;
char proxy [ 512 ] ;
snprintf ( proxy , 512 , " socks5h://localhost:%d " , g_server - > tor_socks_port ) ;
printf ( " Performing post to %s \n " , deliver ) ;
long status_code = - 1 ;
const void * request_clearnet [ ] = {
HTTP_REQ_URL , deliver ,
HTTP_REQ_HEADER , user_agent ,
HTTP_REQ_HEADER , date_header ,
HTTP_REQ_HEADER , sign_header ,
HTTP_REQ_HEADER , content_length_header ,
HTTP_REQ_HEADER , digest_header ,
HTTP_REQ_HEADER , " Content-Type: application/activity+json " ,
HTTP_REQ_POSTDATA , postdata ,
HTTP_REQ_RESULT_STATUS , & status_code ,
HTTP_RES_HEADER_CALLBACK , fetch_handle_header , fd ,
//HTTP_REQ_PROXY, proxy,
NULL
} ;
const void * request_tor [ ] = {
HTTP_REQ_URL , deliver ,
HTTP_REQ_HEADER , user_agent ,
HTTP_REQ_HEADER , date_header ,
HTTP_REQ_HEADER , sign_header ,
HTTP_REQ_HEADER , content_length_header ,
HTTP_REQ_HEADER , digest_header ,
HTTP_REQ_HEADER , " Content-Type: application/activity+json " ,
HTTP_REQ_POSTDATA , postdata ,
HTTP_REQ_RESULT_STATUS , & status_code ,
HTTP_RES_HEADER_CALLBACK , fetch_handle_header , fd ,
HTTP_REQ_PROXY , proxy ,
HTTP_REQ_TIMEOUT , ( void * ) 10 ,
NULL
} ;
// POST to inbox
const void * * request = request_clearnet ;
if ( use_tor_proxy ) {
request = request_tor ;
}
printf ( " \n \n Request result: \n " ) ;
fflush ( stdout ) ;
http_client_do ( request ) ;
printf ( " \n \n " ) ;
fflush ( stdout ) ;
http_signature_free ( & hs ) ;
return status_code ;
}
static bool delivery_succeeded ( long status_code )
{
switch ( status_code ) {
case 200 :
case 202 :
return true ;
}
return false ;
}
static bool process_envelope ( struct outbox_envelope * env )
{
bool result = false ;
@ -76,6 +173,7 @@ static bool process_envelope( struct outbox_envelope* env )
struct ap_object * act = NULL ;
struct account * to_account = NULL ;
struct peer * p = NULL ;
char * tor_inbox = NULL ;
if ( env - > sent ) { return false ; }
if ( env - > retry_after > time ( NULL ) ) { return false ; }
@ -99,6 +197,15 @@ static bool process_envelope( struct outbox_envelope* env )
url_get_domain ( inbox , domain , sizeof ( domain ) ) ;
p = peer_create_from_domain ( domain ) ;
// Handle tor delivery
//*
if ( p - > tor_hidden_service ) {
char * path = strchr ( inbox + 9 , ' / ' ) ;
tor_inbox = aformat ( " http://%s%s " , p - > tor_hidden_service , path ) ;
printf ( " Using TOR inbox: %s \n " , tor_inbox ) ;
}
//*/
struct fetch_data fd ;
fd . p = p ;
@ -148,87 +255,62 @@ static bool process_envelope( struct outbox_envelope* env )
postdata [ size ] = ' \0 ' ;
printf ( " post: %s \n " , postdata ) ;
struct http_signature hs ;
memset ( & hs , 0 , sizeof ( hs ) ) ;
hs . input . url = inbox ;
hs . input . method = " post " ;
hs . input . post_data = postdata ;
if ( ! http_signature_make ( keys , & hs ) ) {
printf ( " ! Failed to make HTTP signature \n " ) ;
goto failed ;
}
char date_header [ 512 ] ;
snprintf ( date_header , sizeof ( date_header ) , " Date: %s " , hs . date ) ;
char sign_header [ 512 ] ;
snprintf ( sign_header , sizeof ( sign_header ) , " Signature: keyId= \" https://%s/owner/actor#mainKey \" ,headers= \" (request-target) host date content-length digest \" ,signature= \" %s \" " ,
g_server - > domain ,
hs . signature
) ;
long status_code ;
char user_agent [ 512 ] ;
snprintf ( user_agent , sizeof ( user_agent ) , " User-Agent: curl (Apogee/0.1; +https://%s/owner/actor) " , g_server - > domain ) ;
char digest_header [ 512 ] ;
snprintf ( digest_header , sizeof ( digest_header ) , " Digest: %s " , hs . digest ) ;
char content_length_header [ 512 ] ;
snprintf ( content_length_header , sizeof ( content_length_header ) , " Content-Length: %d " , hs . content_length ) ;
// Try TOR Hidden Service delivery
if ( tor_inbox ) {
status_code = submit_activity ( postdata , inbox , tor_inbox , keys , & fd , true ) ;
if ( delivery_succeeded ( status_code ) ) {
p - > last_hidden_service_delivery = time ( NULL ) ;
goto success ;
}
}
printf ( " Performing post to %s \n " , inbox ) ;
long status_code = - 1 ;
const void * request [ ] = {
HTTP_REQ_URL , inbox ,
HTTP_REQ_HEADER , user_agent ,
HTTP_REQ_HEADER , date_header ,
HTTP_REQ_HEADER , sign_header ,
HTTP_REQ_HEADER , content_length_header ,
HTTP_REQ_HEADER , digest_header ,
HTTP_REQ_HEADER , " Content-Type: application/activity+json " ,
HTTP_REQ_POSTDATA , postdata ,
HTTP_REQ_RESULT_STATUS , & status_code ,
HTTP_RES_HEADER_CALLBACK , fetch_handle_header , & fd ,
NULL
} ;
// Try TOR delivery
status_code = submit_activity ( postdata , inbox , inbox , keys , & fd , true ) ;
if ( delivery_succeeded ( status_code ) ) {
p - > last_tor_delivery = time ( NULL ) ;
goto success ;
}
// POST to inbox
printf ( " \n \n Request result: \n " ) ;
fflush ( stdout ) ;
http_client_do ( request ) ;
printf ( " \n \n " ) ;
fflush ( stdout ) ;
// Try clearnet delivery
status_code = submit_activity ( postdata , inbox , inbox , keys , & fd , false ) ;
http_signature_free ( & hs ) ;
// delivery failed
printf ( " \n Server returned status code %ld \n " , status_code ) ;
if ( env - > retry_after ) {
env - > retries + = 1 ;
}
if ( p ) {
p - > last_failed_delivery = time ( NULL ) ;
if ( status_code = = 200 | | status_code = = 202 ) {
printf ( " Submitted successfully \n " ) ;
if ( p ) {
p - > last_successful_delivery = time ( NULL ) ;
peer_save ( p ) ;
if ( p - > last_successful_delivery - p - > last_failed_delivery > 60 * 60 * 24 * 7 ) {
// At least one week since last successful delivery
printf ( " Over a week since last successful delivery, marking for discard. \n " ) ;
env - > retries = g_server - > outbox_discard_limit ;
}
peer_save ( p ) ;
}
if ( env - > retries > = g_server - > outbox_discard_limit ) {
// Force discard after 10 delivery attempts
// TODO: change this to a configuration option
goto discard ;
} else {
printf ( " \n Server returned status code %ld \n " , status_code ) ;
if ( env - > retry_after ) {
env - > retries + = 1 ;
}
if ( env - > retries > 10 ) {
// Force discard after 10 delivery attempts
// TODO: change this to a configuration option
goto discard ;
}
env - > retry_after = time ( NULL ) + 60 * ( env - > retries + 1 ) * ( env - > retries + 1 ) ;
outbox_envelope_save ( env ) ;
if ( p ) {
p - > last_failed_delivery = time ( NULL ) ;
peer_save ( p ) ;
}
}
env - > retry_after = time ( NULL ) + 60 * ( env - > retries + 1 ) * ( env - > retries + 1 ) ;
outbox_envelope_save ( env ) ;
goto failed ;
success :
printf ( " Submitted successfully \n " ) ;
if ( p ) {
p - > last_successful_delivery = time ( NULL ) ;
peer_save ( p ) ;
}
goto discard ;
cleanup :
free ( tor_inbox ) ;
ap_object_free ( act ) ;
account_free ( to_account ) ;
free ( postdata ) ;
@ -242,6 +324,7 @@ failed:
result = false ;
goto cleanup ;
discard :
printf ( " Discarding. \n " ) ;
env - > sent = true ;
outbox_envelope_save ( env ) ;
result = true ;
@ -253,24 +336,35 @@ static bool process_pending()
int head = fs_list_get ( " data/outbox/HEAD " ) ;
int tail = fs_list_get ( " data/outbox/TAIL " ) ;
bool result = false ;
for ( int i = tail + 1 ; i < = head ; + + i ) {
struct outbox_envelope * env = outbox_envelope_from_id ( i ) ;
if ( ! env ) {
// Envelope file doesn't exist, advance tail
fs_list_set ( " data/outbox/TAIL " , i ) ;
tail + = 1 ;
} else if ( env ) {
if ( env - > sent & & i = = tail + 1 ) {
// Envelope already sent, advance tail
bool do_fork = false ;
//for( int i = tail + 1; i <= head; ++i ) {
for ( int i = head ; i > tail ; - - i ) {
if ( ! do_fork | | ! fork ( ) ) {
struct outbox_envelope * env = outbox_envelope_from_id ( i ) ;
if ( ! env ) {
// Envelope file doesn't exist, advance tail
fs_list_set ( " data/outbox/TAIL " , i ) ;
tail + = 1 ;
} else if ( process_envelope ( env ) ) {
printf ( " Done with outbox/%d.json \n " , i ) ;
result = true ;
} else if ( env ) {
if ( env - > sent ) {
if ( i = = tail + 1 ) {
// Envelope already sent, advance tail
fs_list_set ( " data/outbox/TAIL " , i ) ;
tail + = 1 ;
}
} else if ( process_envelope ( env ) ) {
printf ( " Done with outbox/%d.json \n " , i ) ;
result = true ;
}
outbox_envelope_free ( env ) ;
}
fflush ( stdout ) ;
if ( do_fork ) {
exit ( EXIT_SUCCESS ) ;
}
outbox_envelope_free ( env ) ;
} else {
usleep ( 50000 ) ;
}
fflush ( stdout ) ;
}
return result ;