@ -1,6 +1,11 @@
# define _GNU_SOURCE
# include "fetch.h"
// Model
# include "model/crypto/keys.h"
# include "model/crypto/http_sign.h"
# include "model/server.h"
// Submodules
# include "http/client/client.h"
# include "util/format.h"
@ -16,27 +21,76 @@
static bool do_fetch ( const char * uri , FILE * result )
{
char user_agent [ 512 ] ;
snprintf ( user_agent , sizeof ( user_agent ) , " User-Agent: curl (Apogee/0.1; +https://%s/owner/actor) " , g_server - > domain ) ;
long status_code ;
const void * request [ ] = {
HTTP_REQ_URL , uri ,
HTTP_REQ_HEADER , " Accept: application/ld+json; profile= \" https://www.w3.org/ns/activitystreams \" " ,
HTTP_REQ_HEADER , user_agent ,
HTTP_REQ_OUTFILE , result ,
HTTP_REQ_RESULT_STATUS , & status_code ,
NULL ,
} ;
printf ( " GET %s \n " , uri ) ;
if ( ! http_client_do ( request ) ) {
printf ( " GET %s -> %ld \n " , uri , status_code ) ;
printf ( " ! Unable to fetch %s \n " , uri ) ;
return false ;
}
http_client_do ( request ) ;
printf ( " GET %s -> %ld \n " , uri , status_code ) ;
if ( status_code = = 401 ) {
printf ( " Retrying request with HTTP Signature header... \n " ) ;
// Load crypto keys
struct crypto_keys * keys = crypto_keys_new ( ) ;
if ( ! crypto_keys_load_private ( keys , " data/owner/private.pem " ) ) {
printf ( " Failed to load private key \n " ) ;
return false ;
}
// TODO: do signed fetch
printf ( " TODO: perform signed fetch \n " ) ;
return false ;
struct http_signature hs ;
memset ( & hs , 0 , sizeof ( hs ) ) ;
hs . input . method = " get " ;
hs . input . url = uri ;
if ( ! http_signature_make ( keys , & hs ) ) {
return false ;
}
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 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 ) ;
const void * request2 [ ] = {
HTTP_REQ_URL , uri ,
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 , " Accept: application/ld+json; profile= \" https://www.w3.org/ns/activitystreams \" " ,
HTTP_REQ_OUTFILE , result ,
HTTP_REQ_RESULT_STATUS , & status_code ,
NULL ,
} ;
if ( ! http_client_do ( request2 ) ) {
printf ( " Failed to perform get \n " ) ;
}
printf ( " GET %s -> %ld \n " , uri , status_code ) ;
}
return ( status_code = = 200 ) ;
}