@@ -1,22 +1,678 @@
# include <glib.h>
# include <json-glib/json-glib.h>
# include <sodium.h>
gboolean do_scuttling = TRUE ;
# include "sbot.h"
struct _SsbScuttler {
GObject parent_instance ;
// If TRUE, the scuttler is already initialised
gboolean initialised ;
// The SSB directory
gchar * ssb_dir ;
guchar * app_key ;
guchar * private_key ;
guchar * encrypt_key ;
guchar * decrypt_key ;
guchar nonce1 [ 24 ] ;
guchar nonce2 [ 24 ] ;
guchar rx_nonce [ 24 ] ;
gsize rx_buf_pos ;
gsize rx_buf_len ;
gboolean noauth ;
gboolean wrote_goodbye ;
GSocketClient * socket_client ;
GSocketConnection * connection ;
} ;
G_DEFINE_QUARK ( ssb_scttler_error_quark , ssb_scuttler_error ) ;
G_DEFINE_TYPE ( SsbScuttler , ssb_scuttler , G_TYPE_INITIALLY_UNOWNED ) ;
typedef struct {
gboolean valid ;
guint line ;
guint column ;
} ParseData ;
static const guchar zeros [ 24 ] = { 0 } ;
static const guchar ssb_cap [ ] = {
0xd4 , 0xa1 , 0xcb , 0x88 , 0xa6 , 0x6f , 0x02 , 0xf8 ,
0xdb , 0x63 , 0x5c , 0xe2 , 0x64 , 0x41 , 0xcc , 0x5d ,
0xac , 0x1b , 0x08 , 0x42 , 0x0c , 0xea , 0xac , 0x23 ,
0x08 , 0x39 , 0xb7 , 0x55 , 0x84 , 0x5a , 0x9f , 0xfb
} ;
GMainLoop * scuttle_loop = NULL ;
SsbScuttler * singleton = NULL ;
static gchar *
read_config ( const gchar * base_dir , const gchar * file_name , GError * * error ) {
gchar * config_file_name ;
GFile * config_file ;
GFileInfo * config_info ;
goffset config_size ;
GFileInputStream * config_stream ;
GError * err = NULL ;
gchar * config_data = NULL ;
config_file_name = g_strdup_printf ( " %s/%s " , base_dir , file_name ) ;
config_file = g_file_new_for_path ( config_file_name ) ;
g_free ( config_file_name ) ;
if ( ( config_info = g_file_query_info ( config_file , G_FILE_ATTRIBUTE_STANDARD_SIZE , G_FILE_QUERY_INFO_NONE , NULL , & err ) ) = = NULL ) {
g_propagate_error ( error , err ) ;
goto ret_err1 ;
}
config_size = g_file_info_get_size ( config_info ) ;
config_data = g_new0 ( gchar , config_size ) ;
if ( ( config_stream = g_file_read ( config_file , NULL , & err ) ) = = NULL ) {
g_propagate_error ( error , err ) ;
g_clear_pointer ( & config_data , g_free ) ;
goto ret_err2 ;
}
if ( ! g_input_stream_read_all ( G_INPUT_STREAM ( config_stream ) , config_data , config_size , NULL , NULL , & err ) ) {
g_propagate_error ( error , err ) ;
g_clear_pointer ( & config_data , g_free ) ;
goto ret_err3 ;
}
if ( ! g_input_stream_close ( G_INPUT_STREAM ( config_stream ) , NULL , & err ) ) {
g_propagate_error ( error , err ) ;
g_clear_pointer ( & config_data , g_free ) ;
goto ret_err3 ;
}
ret_err3 :
g_object_unref ( config_info ) ;
ret_err2 :
g_object_unref ( config_stream ) ;
ret_err1 :
g_object_unref ( config_file ) ;
return config_data ;
}
static void
json_error ( JsonParser * parser , GError * error , ParseData * parse_data )
{
if ( ( error - > domain ! = JSON_PARSER_ERROR ) | | ( error - > code ! = JSON_PARSER_ERROR_INVALID_BAREWORD ) ) {
parse_data - > valid = FALSE ;
} else {
parse_data - > valid = TRUE ;
parse_data - > line = json_parser_get_current_line ( parser ) - 1 ;
parse_data - > column = json_parser_get_current_pos ( parser ) - 1 ;
}
}
static JsonNode *
parse_commented_json ( gchar * json_data , GError * * error )
{
ParseData parse_data ;
JsonParser * parser ;
GError * err = NULL ;
JsonNode * result = NULL ;
parse_data . valid = FALSE ;
parser = json_parser_new ( ) ;
g_signal_connect ( parser , " error " , G_CALLBACK ( json_error ) , & parse_data ) ;
while ( ! json_parser_load_from_data ( parser , json_data , - 1 , & err ) ) {
gchar * * config_lines ;
if ( parse_data . valid ! = TRUE ) {
g_propagate_error ( error , err ) ;
break ;
}
// XXX: Will this work under OS/X and Windows?
config_lines = g_strsplit ( json_data , " \n " , 0 ) ;
if ( config_lines [ parse_data . line ] [ parse_data . column ] = = ' # ' ) {
guint i ;
guint start_pos = 0 ;
guint end_pos ;
for ( i = 0 ; i < = parse_data . line ; i + + ) {
if ( i < parse_data . line ) {
start_pos + = strlen ( config_lines [ i ] ) + 1 ;
}
end_pos = start_pos ;
end_pos + = strlen ( config_lines [ i ] ) ;
}
start_pos + = parse_data . column ;
for ( i = start_pos ; i < end_pos ; i + + ) {
json_data [ i ] = ' ' ;
}
g_clear_error ( & err ) ;
parse_data . valid = FALSE ;
}
g_strfreev ( config_lines ) ;
}
result = json_parser_steal_root ( parser ) ;
g_object_unref ( parser ) ;
return result ;
}
static void
initialise ( SsbScuttler * scuttler , gchar * ssb_dir )
{
gchar * config_data = NULL ;
GError * err = NULL ;
JsonNode * json_content = NULL ;
g_return_if_fail ( scuttler ! = NULL ) ;
if ( scuttler - > initialised = = TRUE ) {
return ;
}
if ( ( config_data = read_config ( ssb_dir , " config " , & err ) ) ! = NULL ) {
if ( ( json_content = parse_commented_json ( config_data , & err ) ) = = NULL ) {
g_critical ( " Could not parse configuration data " ) ;
g_free ( config_data ) ;
return ;
}
g_free ( config_data ) ;
g_clear_pointer ( & json_content , json_node_free ) ;
}
if ( ( config_data = read_config ( ssb_dir , " secret " , & err ) ) ! = NULL ) {
JsonObject * secret_object ;
gchar * private_key = NULL ;
guchar * decoded_private_key = NULL ;
size_t private_key_len ;
gsize key_len ;
if ( ( json_content = parse_commented_json ( config_data , & err ) ) = = NULL ) {
g_critical ( " Could not parse secret data " ) ;
g_free ( config_data ) ;
return ;
}
secret_object = json_node_get_object ( json_content ) ;
if ( ( private_key = g_strdup ( json_object_get_string_member ( secret_object , " private " ) ) ) = = NULL ) {
g_critical ( " Could not read private key, can not continue " ) ;
return ;
}
private_key_len = strlen ( private_key ) ;
if ( ( strlen ( private_key ) > 8 ) & &
( strcmp ( private_key + private_key_len - 8 , " .ed25519 " ) = = 0 ) ) {
private_key [ private_key_len - 8 ] = 0 ;
}
if ( ( decoded_private_key = g_base64_decode ( private_key , & key_len ) ) = = NULL ) {
g_critical ( " Could not decode private key, can not continue " ) ;
g_free ( private_key ) ;
return ;
}
g_free ( private_key ) ;
g_free ( config_data ) ;
g_clear_pointer ( & json_content , json_node_free ) ;
g_clear_pointer ( & ( scuttler - > private_key ) , g_free ) ;
scuttler - > private_key = decoded_private_key ;
}
scuttler - > app_key = g_new0 ( guchar , sizeof ( ssb_cap ) ) ;
memcpy ( scuttler - > app_key , ssb_cap , sizeof ( ssb_cap ) ) ;
scuttler - > initialised = TRUE ;
}
/**
* ensure_scuttler():
* @ssb_dir: (nullable): the SSB directory
*
* Ensure the scuttler singleton is initialised with @ssb_dir as its base directory.
*/
static inline gboolean
ensure_scuttler ( gchar * ssb_dir )
{
if ( singleton ! = NULL ) {
if ( ( ssb_dir ! = NULL ) & & g_strcmp0 ( ssb_dir , singleton - > ssb_dir ) ) {
return FALSE ;
}
return TRUE ;
}
singleton = g_object_new ( SSB_TYPE_SCUTTLER , NULL ) ;
if ( ssb_dir ! = NULL ) {
initialise ( singleton , ssb_dir ) ;
}
return TRUE ;
}
static gboolean
second_hook_cb ( )
{
g_print ( " Scuttling… \n " ) ;
return TRUE ;
}
static gboolean
ssb_scuttler_send ( SsbScuttler * scuttler , gpointer data , gsize data_len , GError * * error )
{
GOutputStream * stream = g_io_stream_get_output_stream ( G_IO_STREAM ( scuttler - > connection ) ) ;
GError * err = NULL ;
if ( ! g_output_stream_write_all ( stream , data , data_len , NULL , NULL , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
return TRUE ;
}
static gboolean
ssb_scuttler_read ( SsbScuttler * scuttler , gpointer buffer , gsize buffer_len , GError * * error )
{
GInputStream * stream = g_io_stream_get_input_stream ( G_IO_STREAM ( scuttler - > connection ) ) ;
GError * err = NULL ;
if ( g_input_stream_read ( stream , buffer , buffer_len , NULL , & err ) < 0 ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
return TRUE ;
}
static gboolean
ssb_scuttler_shs_connect ( SsbScuttler * scuttler , GError * * error )
{
guchar kx_pk [ crypto_box_PUBLICKEYBYTES ] ;
guchar kx_sk [ crypto_box_SECRETKEYBYTES ] ;
guchar local_app_mac [ crypto_box_PUBLICKEYBYTES ] ;
guchar remote_app_mac [ crypto_box_PUBLICKEYBYTES ] ;
guchar remote_kx_pk [ crypto_box_PUBLICKEYBYTES ] ;
guchar buf [ 2 * crypto_box_PUBLICKEYBYTES ] ;
guchar secret [ crypto_box_SECRETKEYBYTES ] ;
guchar remote_pk_curve [ crypto_box_PUBLICKEYBYTES ] ;
guchar a_bob [ crypto_box_PUBLICKEYBYTES ] ;
guchar secret2a [ crypto_box_PUBLICKEYBYTES * 3 ] ;
guchar secret2 [ crypto_box_PUBLICKEYBYTES ] ;
guchar shash [ crypto_box_PUBLICKEYBYTES ] ;
guchar signed1 [ 3 * crypto_box_PUBLICKEYBYTES ] ;
guchar sig [ 2 * crypto_box_PUBLICKEYBYTES ] ;
guchar hello [ 3 * crypto_box_PUBLICKEYBYTES ] ;
guchar boxed_auth [ 112 ] ;
guchar boxed_response [ 80 ] ;
guchar local_sk_curve [ crypto_box_SECRETKEYBYTES ] ;
guchar b_alice [ crypto_box_SECRETKEYBYTES ] ;
guchar secret3a [ 4 * crypto_box_SECRETKEYBYTES ] ;
guchar secret3 [ crypto_box_SECRETKEYBYTES ] ;
guchar signed2 [ 160 ] ;
guchar enc_key_hashed [ crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES ] ;
guchar dec_key_hashed [ crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES ] ;
GError * err = NULL ;
if ( crypto_box_keypair ( kx_pk , kx_sk ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_KEYGEN , " Could not generate auth keypair " ) ;
return FALSE ;
}
if ( crypto_auth ( local_app_mac , kx_pk , crypto_box_PUBLICKEYBYTES , scuttler - > app_key ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_KEYAUTH , " Failed to generate app mac " ) ;
return FALSE ;
}
// Send challenge
memcpy ( buf , local_app_mac , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( buf + crypto_box_PUBLICKEYBYTES , kx_pk , crypto_box_PUBLICKEYBYTES ) ;
if ( ! ssb_scuttler_send ( scuttler , buf , sizeof ( buf ) , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
// Receive challenge response
if ( ! ssb_scuttler_read ( scuttler , buf , sizeof ( buf ) , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
memcpy ( remote_app_mac , buf , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( remote_kx_pk , buf + crypto_box_PUBLICKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
if ( crypto_auth_verify ( buf , remote_kx_pk , crypto_box_PUBLICKEYBYTES , scuttler - > app_key ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_KEYVERIFY , " Wrong protocol (version?) " ) ;
return FALSE ;
}
// Send auth
if ( crypto_scalarmult ( secret , kx_sk , remote_kx_pk ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to derive shared secret " ) ;
return FALSE ;
}
if ( crypto_sign_ed25519_pk_to_curve25519 ( remote_pk_curve , scuttler - > private_key + crypto_box_SECRETKEYBYTES ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to curvify remote public key " ) ;
return FALSE ;
}
if ( crypto_scalarmult ( a_bob , kx_sk , remote_pk_curve ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to derive a_bob " ) ;
return FALSE ;
}
memcpy ( secret2a , scuttler - > app_key , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( secret2a + crypto_box_PUBLICKEYBYTES , secret , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( secret2a + 2 * crypto_box_PUBLICKEYBYTES , a_bob , crypto_box_PUBLICKEYBYTES ) ;
if ( crypto_hash_sha256 ( secret2 , secret2a , sizeof ( secret2a ) ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash secret2 " ) ;
return FALSE ;
}
if ( crypto_hash_sha256 ( shash , secret , sizeof ( secret ) ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash secret " ) ;
return FALSE ;
}
memcpy ( signed1 , scuttler - > app_key , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( signed1 + crypto_box_PUBLICKEYBYTES , scuttler - > private_key + crypto_box_SECRETKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( signed1 + 2 * crypto_box_PUBLICKEYBYTES , shash , crypto_box_PUBLICKEYBYTES ) ;
if ( crypto_sign_detached ( sig , NULL , signed1 , sizeof ( signed1 ) , scuttler - > private_key ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to sign inner hello " ) ;
return FALSE ;
}
memcpy ( hello , sig , 2 * crypto_box_PUBLICKEYBYTES ) ;
memcpy ( hello + 2 * crypto_box_PUBLICKEYBYTES , scuttler - > private_key + crypto_box_SECRETKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
if ( crypto_secretbox_easy ( boxed_auth , hello , sizeof ( hello ) , zeros , secret2 ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to box hello " ) ;
return FALSE ;
}
if ( ! ssb_scuttler_send ( scuttler , boxed_auth , sizeof ( boxed_auth ) , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
// Verify the auth response
if ( ! ssb_scuttler_read ( scuttler , boxed_response , sizeof ( boxed_response ) , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
if ( crypto_sign_ed25519_sk_to_curve25519 ( local_sk_curve , scuttler - > private_key ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to curvify local secret key " ) ;
return FALSE ;
}
if ( crypto_scalarmult ( b_alice , local_sk_curve , remote_kx_pk ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to derive b_alice " ) ;
return FALSE ;
}
memcpy ( secret3a , scuttler - > app_key , 32 ) ;
memcpy ( secret3a + crypto_box_SECRETKEYBYTES , secret , crypto_box_SECRETKEYBYTES ) ;
memcpy ( secret3a + 2 * crypto_box_SECRETKEYBYTES , a_bob , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( secret3a + 2 * crypto_box_SECRETKEYBYTES + crypto_box_PUBLICKEYBYTES , b_alice , crypto_box_SECRETKEYBYTES ) ;
if ( crypto_hash_sha256 ( secret3 , secret3a , sizeof ( secret3a ) ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash secret3 " ) ;
return FALSE ;
}
if ( crypto_secretbox_open_easy ( sig , boxed_response , sizeof ( boxed_response ) , zeros , secret3 ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to unbox the okay " ) ;
return FALSE ;
}
memcpy ( signed2 , scuttler - > app_key , crypto_box_PUBLICKEYBYTES ) ;
memcpy ( signed2 + crypto_box_PUBLICKEYBYTES , hello , 96 ) ;
memcpy ( signed2 + 128 , shash , 32 ) ;
if ( crypto_sign_verify_detached ( sig , signed2 , sizeof ( signed2 ) , scuttler - > private_key + crypto_box_SECRETKEYBYTES ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Server not authenticated " ) ;
return FALSE ;
}
if ( crypto_hash_sha256 ( secret , secret3 , crypto_box_PUBLICKEYBYTES ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash secret3 " ) ;
return FALSE ;
}
memcpy ( enc_key_hashed , secret , crypto_box_SECRETKEYBYTES ) ;
memcpy ( enc_key_hashed + crypto_box_SECRETKEYBYTES , scuttler - > private_key + crypto_box_SECRETKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
g_clear_pointer ( & ( scuttler - > encrypt_key ) , g_free ) ;
scuttler - > encrypt_key = g_new0 ( guchar , crypto_box_SECRETKEYBYTES ) ;
if ( crypto_hash_sha256 ( scuttler - > encrypt_key , enc_key_hashed , 64 ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash the encrypt key " ) ;
return FALSE ;
}
g_clear_pointer ( & ( scuttler - > decrypt_key ) , g_free ) ;
scuttler - > decrypt_key = g_new0 ( guchar , crypto_box_SECRETKEYBYTES ) ;
memcpy ( dec_key_hashed , secret , crypto_box_SECRETKEYBYTES ) ;
memcpy ( dec_key_hashed + crypto_box_SECRETKEYBYTES , scuttler - > private_key + crypto_box_SECRETKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
if ( crypto_hash_sha256 ( scuttler - > decrypt_key , dec_key_hashed , 64 ) < 0 ) {
g_set_error ( error , SSB_SCUTTLER_ERROR , SSB_SCUTTLER_ERROR_AUTH , " Failed to hash the decrypt_key " ) ;
return FALSE ;
}
memcpy ( scuttler - > nonce1 , remote_app_mac , 24 ) ;
memcpy ( scuttler - > nonce2 , remote_app_mac , 24 ) ;
memcpy ( scuttler - > rx_nonce , local_app_mac , 24 ) ;
scuttler - > rx_buf_pos = 0 ;
scuttler - > rx_buf_len = 0 ;
scuttler - > noauth = FALSE ;
scuttler - > wrote_goodbye = FALSE ;
return TRUE ;
}
static gboolean
ssb_scuttler_connect ( SsbScuttler * scuttler , GError * * error )
{
GInetAddress * address ;
GSocketAddress * destination ;
GError * err = NULL ;
scuttler - > socket_client = g_socket_client_new ( ) ;
// TODO: Implement the UNIX socket version, too! Also, read this stuff from the
// config/command line!
address = g_inet_address_new_from_string ( " 127.0.0.1 " ) ;
destination = g_inet_socket_address_new ( address , 8008 ) ;
g_object_unref ( address ) ;
scuttler - > connection = g_socket_client_connect ( scuttler - > socket_client ,
G_SOCKET_CONNECTABLE ( destination ) ,
NULL ,
& err ) ;
g_object_unref ( destination ) ;
// TODO: This is only required if noauth is not set
if ( ! ssb_scuttler_shs_connect ( scuttler , & err ) ) {
g_propagate_error ( error , err ) ;
return FALSE ;
}
return TRUE ;
}
static void
ssb_scuttler_dispose ( GObject * gobject )
{
SsbScuttler * scuttler = SSB_SCUTTLER ( gobject ) ;
GError * err = NULL ;
if ( scuttler - > connection & & ! g_io_stream_is_closed ( G_IO_STREAM ( scuttler - > connection ) ) ) {
g_io_stream_close ( G_IO_STREAM ( scuttler - > connection ) , NULL , & err ) ;
scuttler - > connection = NULL ;
}
g_clear_pointer ( & ( scuttler - > ssb_dir ) , g_free ) ;
g_clear_pointer ( & ( scuttler - > app_key ) , g_free ) ;
g_clear_pointer ( & ( scuttler - > private_key ) , g_free ) ;
}
static void
ssb_scuttler_finalize ( GObject * gobject )
{
SsbScuttler * scuttler = SSB_SCUTTLER ( gobject ) ;
g_clear_pointer ( & ( scuttler - > socket_client ) , g_object_unref ) ;
g_clear_pointer ( & ( scuttler - > ssb_dir ) , g_free ) ;
g_clear_pointer ( & ( scuttler - > encrypt_key ) , g_free ) ;
}
static void
ssb_scuttler_class_init ( SsbScuttlerClass * klass )
{
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
gobject_class - > dispose = ssb_scuttler_dispose ;
gobject_class - > finalize = ssb_scuttler_finalize ;
}
static void
ssb_scuttler_init ( SsbScuttler * scuttler )
{
scuttler - > initialised = FALSE ;
scuttler - > ssb_dir = NULL ;
scuttler - > socket_client = NULL ;
scuttler - > connection = NULL ;
scuttler - > app_key = NULL ;
scuttler - > private_key = NULL ;
scuttler - > encrypt_key = NULL ;
}
gpointer
scuttle ( gchar * ssb_dir )
{
gchar * config_file = g_strdup_printf ( " %s/config " , ssb_dir ) ;
g_print ( " Read config file %s \n " , config_file ) ;
g_free ( config_file ) ;
GMainContext * scuttle_context ;
GSource * second_hook ;
GError * err = NULL ;
g_pr int( " Starting scuttle \n " ) ;
if ( sodium_ ini t( ) < 0 ) {
g_critical ( " Can not initialise sodium " ) ;
while ( do_scuttling ) {
g_usleep ( G_USEC_PER_SEC ) ;
g_print ( " Scuttle… \n " ) ;
return NULL ;
}
g_print ( " Scuttling stopped \n " ) ;
// Since scuttler is a singleton global to this file, we don’ t need the return value of this
// function now.
if ( G_UNLIKELY ( ! ensure_scuttler ( ssb_dir ) ) ) {
g_critical ( " Can not reinitialise scuttler with a new SSB directory. " ) ;
return NULL ;
}
g_object_ref_sink ( singleton ) ;
scuttle_context = g_main_context_new ( ) ;
scuttle_loop = g_main_loop_new ( scuttle_context , FALSE ) ;
// TODO: This is for debugging purposes only, let’ s remove it as soon as the scuttler works
second_hook = g_timeout_source_new_seconds ( 1 ) ;
g_source_set_callback ( second_hook ,
G_SOURCE_FUNC ( second_hook_cb ) ,
g_main_loop_ref ( scuttle_loop ) ,
( GDestroyNotify ) g_main_loop_unref ) ;
g_source_attach ( second_hook , scuttle_context ) ;
// Set scuttle_context as the default context for this thread
g_main_context_push_thread_default ( scuttle_context ) ;
if ( ! ssb_scuttler_connect ( singleton , & err ) )
{
g_critical ( " Could not connect: %s " , err - > message ) ;
return NULL ;
}
g_debug ( " Starting scuttle " ) ;
g_main_loop_run ( scuttle_loop ) ;
g_main_context_pop_thread_default ( scuttle_context ) ;
g_main_loop_unref ( scuttle_loop ) ;
g_object_unref ( singleton ) ;
g_debug ( " Scuttling stopped " ) ;
scuttle_loop = NULL ;
return NULL ;
}
void
stop_scuttling ( void )
{
if ( scuttle_loop ) {
g_main_loop_quit ( scuttle_loop ) ;
}
}