|
|
|
@ -10,70 +10,28 @@
|
|
|
|
|
#include "model/account.h"
|
|
|
|
|
#include "model/ap/activity.h"
|
|
|
|
|
#include "model/ap/inbox_envelope.h"
|
|
|
|
|
#include "model/crypto/http_sign.h"
|
|
|
|
|
|
|
|
|
|
// Stdlib
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
extern bool terminate;
|
|
|
|
|
|
|
|
|
|
static void io_copy( FILE* in, FILE* out )
|
|
|
|
|
{
|
|
|
|
|
char buffer[512];
|
|
|
|
|
for(;;) {
|
|
|
|
|
int count = fread( buffer, 1, 512, in );
|
|
|
|
|
if( count == 0 ) { return; }
|
|
|
|
|
fwrite( buffer, 1, count, out );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool route_inbox( struct http_request* req )
|
|
|
|
|
{
|
|
|
|
|
// No subroutes
|
|
|
|
|
if( !http_request_route_term( req, "" ) ) { return false; }
|
|
|
|
|
if( !http_request_route_method( req, "POST" ) ) { return false; }
|
|
|
|
|
|
|
|
|
|
printf( "Queue inbox items for later processing\n" );
|
|
|
|
|
|
|
|
|
|
const char* signature = http_request_get_header(req,"Signature");
|
|
|
|
|
const char* date = http_request_get_header(req,"Date");
|
|
|
|
|
|
|
|
|
|
printf( "Signature: %s\nDate: %s", signature, date );
|
|
|
|
|
|
|
|
|
|
FILE* body = http_request_get_request_data(req);
|
|
|
|
|
|
|
|
|
|
uint64_t time_ns;
|
|
|
|
|
struct timespec ts;
|
|
|
|
|
clock_gettime( CLOCK_REALTIME, &ts );
|
|
|
|
|
time_ns = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
|
|
|
|
|
|
|
|
|
|
int head = fs_list_get( "data/inbox/HEAD" );
|
|
|
|
|
head += 1;
|
|
|
|
|
fs_list_set( "data/inbox/HEAD", head );
|
|
|
|
|
|
|
|
|
|
// TODO: change to envelope_save()
|
|
|
|
|
char filename[512];
|
|
|
|
|
snprintf( filename, 512, "data/inbox/%d.json", head );
|
|
|
|
|
char tmp_filename[512+32];
|
|
|
|
|
snprintf( tmp_filename, 512+32, "%s.tmp-%d", filename, rand() );
|
|
|
|
|
|
|
|
|
|
FILE* f = fopen( tmp_filename, "w" );
|
|
|
|
|
if( !f ) {
|
|
|
|
|
printf( "Failed to open %s\n", tmp_filename );
|
|
|
|
|
return false;
|
|
|
|
|
if( envelope_create_from_request( req ) ) {
|
|
|
|
|
http_request_send_headers( req, 200, "text/plain", true );
|
|
|
|
|
} else {
|
|
|
|
|
http_request_send_headers( req, 400, "text/plain", true );
|
|
|
|
|
}
|
|
|
|
|
#define RENDER
|
|
|
|
|
#include "src/view/inbox_envelope.json.inc"
|
|
|
|
|
#undef RENDER
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
rename( tmp_filename, filename );
|
|
|
|
|
|
|
|
|
|
http_request_send_headers( req, 200, "text/plain", true );
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@ -184,44 +142,63 @@ bool validate_signature( struct ap_envelope* env )
|
|
|
|
|
|
|
|
|
|
bool process_one()
|
|
|
|
|
{
|
|
|
|
|
// Items requiring cleanup
|
|
|
|
|
struct ap_activity* act = NULL;
|
|
|
|
|
struct ap_envelope* env = NULL;
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
int tail_pos = fs_list_get("data/inbox/TAIL");
|
|
|
|
|
int head_pos = fs_list_get("data/inbox/HEAD");
|
|
|
|
|
if( head_pos > tail_pos ) {
|
|
|
|
|
// We have data to process
|
|
|
|
|
printf( "Inbox has %d items pending processing...\n", (head_pos - tail_pos) );
|
|
|
|
|
if( head_pos <= tail_pos ) { return false; }
|
|
|
|
|
|
|
|
|
|
int id = tail_pos + 1;
|
|
|
|
|
// We have data to process
|
|
|
|
|
printf( "Inbox has %d items pending processing...\n", (head_pos - tail_pos) );
|
|
|
|
|
|
|
|
|
|
struct ap_envelope* env = ap_envelope_from_id(id);
|
|
|
|
|
bool step_tail = false;
|
|
|
|
|
int id = tail_pos + 1;
|
|
|
|
|
|
|
|
|
|
if( !env ) {
|
|
|
|
|
printf( "Failed to parse envelope+activity for data/inbox/%d.json\n", id );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
validate_signature(env);
|
|
|
|
|
env = ap_envelope_from_id(id);
|
|
|
|
|
bool step_tail = false;
|
|
|
|
|
|
|
|
|
|
// Discard delete requests
|
|
|
|
|
if( env->activity.type == apat_delete ) {
|
|
|
|
|
step_tail = true;
|
|
|
|
|
goto step;
|
|
|
|
|
}
|
|
|
|
|
if( !env ) {
|
|
|
|
|
printf( "Failed to parse envelope+activity for data/inbox/%d.json\n", id );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
validate_signature(env);
|
|
|
|
|
|
|
|
|
|
if( !env->validated ) { return false; }
|
|
|
|
|
// Load activity
|
|
|
|
|
FILE* f = fmemopen( env->body, strlen(env->body), "r" );
|
|
|
|
|
act = ap_activity_from_FILE(f);
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
printf( "Processing %d\n", id );
|
|
|
|
|
step_tail = route_activity( &env->activity );
|
|
|
|
|
ap_envelope_free(env);
|
|
|
|
|
if( !act ) { goto failed; }
|
|
|
|
|
|
|
|
|
|
step:
|
|
|
|
|
printf( "handled: %c\n", step_tail ? 'T' : 'F' );
|
|
|
|
|
if( step_tail ) {
|
|
|
|
|
fs_list_set( "data/inbox/TAIL", id );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Discard delete requests
|
|
|
|
|
if( act->type == apat_delete ) {
|
|
|
|
|
step_tail = true;
|
|
|
|
|
goto step;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
if( !env->validated ) { goto failed; }
|
|
|
|
|
|
|
|
|
|
printf( "Processing %d\n", id );
|
|
|
|
|
step_tail = route_activity( act );
|
|
|
|
|
|
|
|
|
|
finished:
|
|
|
|
|
printf( "handled: %c\n", step_tail ? 'T' : 'F' );
|
|
|
|
|
if( step_tail ) {
|
|
|
|
|
fs_list_set( "data/inbox/TAIL", id );
|
|
|
|
|
result = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ap_activity_free(act);
|
|
|
|
|
ap_envelope_free(env);
|
|
|
|
|
return result;
|
|
|
|
|
failed:
|
|
|
|
|
result = false;
|
|
|
|
|
goto finished;
|
|
|
|
|
step:
|
|
|
|
|
result = true;
|
|
|
|
|
goto finished;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool cleanup_inbox()
|
|
|
|
|