From 4c6d7ac36c0d87e9919cea350742a6bb67659bec Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Sun, 28 Jul 2019 12:35:36 -0400 Subject: [PATCH] Marshal data API & fixes. --- platform-independent/c/cli/src/mpw-cli.c | 8 +- .../c/core/src/mpw-algorithm.c | 16 +- .../c/core/src/mpw-algorithm.h | 16 +- .../c/core/src/mpw-marshal-util.c | 10 +- .../c/core/src/mpw-marshal-util.h | 10 +- platform-independent/c/core/src/mpw-marshal.c | 381 ++++++++++++++---- platform-independent/c/core/src/mpw-marshal.h | 79 +++- platform-independent/c/core/src/mpw-types.c | 18 +- platform-independent/c/core/src/mpw-types.h | 18 +- platform-independent/c/core/src/mpw-util.c | 17 +- platform-independent/c/core/src/mpw-util.h | 18 +- 11 files changed, 447 insertions(+), 144 deletions(-) diff --git a/platform-independent/c/cli/src/mpw-cli.c b/platform-independent/c/cli/src/mpw-cli.c index 6472135f..80275d09 100644 --- a/platform-independent/c/cli/src/mpw-cli.c +++ b/platform-independent/c/cli/src/mpw-cli.c @@ -272,7 +272,7 @@ void cli_free(Arguments *args, Operation *operation) { mpw_free_strings( &operation->fullName, &operation->masterPassword, &operation->siteName, NULL ); mpw_free_strings( &operation->keyContext, &operation->resultState, &operation->resultParam, NULL ); mpw_free_strings( &operation->identicon, &operation->sitesPath, NULL ); - mpw_marshal_free( &operation->file ); + mpw_marshal_file_free( &operation->file ); operation->site = NULL; operation->question = NULL; cli_masterKeyProvider_free(); @@ -487,7 +487,7 @@ void cli_user(Arguments *args, Operation *operation) { if (!sitesFile) { // If no user from mpsites, create a new one. mpw_free_string( &operation->sitesPath ); - mpw_marshal_free( &operation->file ); + mpw_marshal_file_free( &operation->file ); operation->file = mpw_marshal_file( mpw_marshal_user( operation->fullName, cli_masterKeyProvider_op( operation ), MPAlgorithmVersionCurrent ), NULL ); } @@ -501,7 +501,7 @@ void cli_user(Arguments *args, Operation *operation) { // Parse file. MPMarshalError marshalError = { .type = MPMarshalSuccess }; - mpw_marshal_free( &operation->file ); + mpw_marshal_file_free( &operation->file ); operation->file = mpw_marshal_read( sitesInputData, cli_masterKeyProvider_op( operation ), &marshalError ); if (marshalError.type == MPMarshalErrorMasterPassword && operation->allowPasswordUpdate) { @@ -516,7 +516,7 @@ void cli_user(Arguments *args, Operation *operation) { importMasterPassword = mpw_getpass( "Old master password: " ); } - mpw_marshal_free( &operation->file ); + mpw_marshal_file_free( &operation->file ); operation->file = mpw_marshal_read( sitesInputData, cli_masterKeyProvider_str( importMasterPassword ), &marshalError ); if (operation->file && operation->file->user) diff --git a/platform-independent/c/core/src/mpw-algorithm.c b/platform-independent/c/core/src/mpw-algorithm.c index a214d8f8..19329c35 100644 --- a/platform-independent/c/core/src/mpw-algorithm.c +++ b/platform-independent/c/core/src/mpw-algorithm.c @@ -22,7 +22,7 @@ #include "mpw-algorithm_v2.c" #include "mpw-algorithm_v3.c" -MPMasterKey mpw_master_key(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { +const MPMasterKey mpw_master_key(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { if (fullName && !strlen( fullName )) fullName = NULL; @@ -56,8 +56,8 @@ MPMasterKey mpw_master_key(const char *fullName, const char *masterPassword, con } } -MPSiteKey mpw_site_key( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, +const MPSiteKey mpw_site_key( + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) { if (keyContext && !strlen( keyContext )) @@ -93,7 +93,7 @@ MPSiteKey mpw_site_key( } const char *mpw_site_result( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPResultType resultType, const char *resultParam, const MPAlgorithmVersion algorithmVersion) { @@ -171,7 +171,7 @@ const char *mpw_site_result( } const char *mpw_site_state( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPResultType resultType, const char *resultParam, const MPAlgorithmVersion algorithmVersion) { @@ -223,7 +223,7 @@ static const char *mpw_identicon_accessories[] = { "♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌" }; -MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) { +const MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) { const uint8_t *seed = NULL; if (fullName && strlen( fullName ) && masterPassword && strlen( masterPassword )) @@ -246,7 +246,7 @@ MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) { } const char *mpw_identicon_encode( - MPIdenticon identicon) { + const MPIdenticon identicon) { if (identicon.color == MPIdenticonColorUnset) return ""; @@ -255,7 +255,7 @@ const char *mpw_identicon_encode( identicon.color, identicon.leftArm, identicon.body, identicon.rightArm, identicon.accessory ); } -MPIdenticon mpw_identicon_encoded( +const MPIdenticon mpw_identicon_encoded( const char *encoding) { MPIdenticon identicon = MPIdenticonUnset; diff --git a/platform-independent/c/core/src/mpw-algorithm.h b/platform-independent/c/core/src/mpw-algorithm.h index 0a82b2d0..0d60cbd8 100644 --- a/platform-independent/c/core/src/mpw-algorithm.h +++ b/platform-independent/c/core/src/mpw-algorithm.h @@ -38,20 +38,20 @@ typedef mpw_enum( unsigned int, MPAlgorithmVersion ) { /** Derive the master key for a user based on their name and master password. * @return A buffer (allocated, MPMasterKeySize) or NULL if the fullName or masterPassword is missing, the algorithm is unknown, or an algorithm error occurred. */ -MPMasterKey mpw_master_key( +const MPMasterKey mpw_master_key( const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion); /** Derive the site key for a user's site from the given master key and site parameters. * @return A buffer (allocated, MPSiteKeySize) or NULL if the masterKey or siteName is missing, the algorithm is unknown, or an algorithm error occurred. */ -MPSiteKey mpw_site_key( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, +const MPSiteKey mpw_site_key( + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion); /** Generate a site result token from the given parameters. * @param resultParam A parameter for the resultType. For stateful result types, the output of mpw_site_state. * @return A string (allocated) or NULL if the masterKey or siteName is missing, the algorithm is unknown, or an algorithm error occurred. */ const char *mpw_site_result( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPResultType resultType, const char *resultParam, const MPAlgorithmVersion algorithmVersion); @@ -60,19 +60,19 @@ const char *mpw_site_result( * @param resultParam A parameter for the resultType. For stateful result types, the desired mpw_site_result. * @return A string (allocated) or NULL if the masterKey, siteName or resultParam is missing, the algorithm is unknown, or an algorithm error occurred. */ const char *mpw_site_state( - MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, + const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, const MPKeyPurpose keyPurpose, const char *keyContext, const MPResultType resultType, const char *resultParam, const MPAlgorithmVersion algorithmVersion); /** @return An identicon (static) that represents the user's identity. */ -MPIdenticon mpw_identicon( +const MPIdenticon mpw_identicon( const char *fullName, const char *masterPassword); /** @return An encoded representation (shared) of the given identicon or an empty string if the identicon is unset. */ const char *mpw_identicon_encode( - MPIdenticon identicon); + const MPIdenticon identicon); /** @return An identicon (static) decoded from the given encoded identicon representation or an identicon with empty fields if the identicon could not be parsed. */ -MPIdenticon mpw_identicon_encoded( +const MPIdenticon mpw_identicon_encoded( const char *encoding); #endif // _MPW_ALGORITHM_H diff --git a/platform-independent/c/core/src/mpw-marshal-util.c b/platform-independent/c/core/src/mpw-marshal-util.c index ce94e529..7d2d5cb9 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.c +++ b/platform-independent/c/core/src/mpw-marshal-util.c @@ -23,7 +23,7 @@ MP_LIBS_BEGIN #include MP_LIBS_END -char *mpw_get_token(const char **in, const char *eol, char *delim) { +char *mpw_get_token(const char **in, const char *eol, const char *delim) { // Skip leading spaces. for (; **in == ' '; ++*in); @@ -60,7 +60,7 @@ time_t mpw_timegm(const char *time) { #if MPW_JSON json_object *mpw_get_json_object( - json_object *obj, const char *key, bool create) { + json_object *obj, const char *key, const bool create) { if (!obj) return NULL; @@ -86,7 +86,7 @@ const char *mpw_get_json_string( } int64_t mpw_get_json_int( - json_object *obj, const char *key, int64_t defaultValue) { + json_object *obj, const char *key, const int64_t defaultValue) { json_object *json_value = mpw_get_json_object( obj, key, false ); if (!json_value) @@ -96,7 +96,7 @@ int64_t mpw_get_json_int( } bool mpw_get_json_boolean( - json_object *obj, const char *key, bool defaultValue) { + json_object *obj, const char *key, const bool defaultValue) { json_object *json_value = mpw_get_json_object( obj, key, false ); if (!json_value) @@ -107,7 +107,7 @@ bool mpw_get_json_boolean( #endif -bool mpw_update_master_key(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm, +bool mpw_update_master_key(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, const MPAlgorithmVersion targetKeyAlgorithm, const char *fullName, const char *masterPassword) { if (masterKey && (!*masterKey || *masterKeyAlgorithm != targetKeyAlgorithm)) { diff --git a/platform-independent/c/core/src/mpw-marshal-util.h b/platform-independent/c/core/src/mpw-marshal-util.h index 4f35d9d8..ba076927 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.h +++ b/platform-independent/c/core/src/mpw-marshal-util.h @@ -34,7 +34,7 @@ MP_LIBS_END * The input string reference is advanced beyond the token delimitor if one is found. * @return A string (allocated) containing the token or NULL if the delim wasn't found before eol. */ char *mpw_get_token( - const char **in, const char *eol, char *delim); + const char **in, const char *eol, const char *delim); /** Convert an RFC 3339 time string into epoch time. * @return ERR if the string could not be parsed. */ time_t mpw_timegm( @@ -48,7 +48,7 @@ time_t mpw_timegm( * @param create If true, create and insert new objects for any missing path components. * @return An object (shared) or a new object (shared) installed in the tree if the path's object path was not found. */ json_object *mpw_get_json_object( - json_object *obj, const char *key, bool create); + json_object *obj, const char *key, const bool create); /** Search for a string in a JSON object tree. * @param key A dot-delimited list of JSON object keys to walk toward the child object. * @return A string (shared) or defaultValue if one of the path's object keys was not found in the source object's tree. */ @@ -58,12 +58,12 @@ const char *mpw_get_json_string( * @param key A dot-delimited list of JSON object keys to walk toward the child object. * @return The integer value or defaultValue if one of the path's object keys was not found in the source object's tree. */ int64_t mpw_get_json_int( - json_object *obj, const char *key, int64_t defaultValue); + json_object *obj, const char *key, const int64_t defaultValue); /** Search for a boolean in a JSON object tree. * @param key A dot-delimited list of JSON object keys to walk toward the child object. * @return The boolean value or defaultValue if one of the path's object keys was not found in the source object's tree. */ bool mpw_get_json_boolean( - json_object *obj, const char *key, bool defaultValue); + json_object *obj, const char *key, const bool defaultValue); #endif /// mpw. @@ -72,7 +72,7 @@ bool mpw_get_json_boolean( * @param masterKey A buffer (allocated, MPMasterKeySize). * @return false if an error occurred during the derivation of the master key. */ bool mpw_update_master_key( - MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm, + MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, const MPAlgorithmVersion targetKeyAlgorithm, const char *fullName, const char *masterPassword); #endif // _MPW_MARSHAL_UTIL_H diff --git a/platform-independent/c/core/src/mpw-marshal.c b/platform-independent/c/core/src/mpw-marshal.c index e5551215..e6107d5c 100644 --- a/platform-independent/c/core/src/mpw-marshal.c +++ b/platform-independent/c/core/src/mpw-marshal.c @@ -120,75 +120,309 @@ MPMarshalledFile *mpw_marshal_file( return file; } -bool mpw_marshal_info_free( +void mpw_marshal_info_free( MPMarshalInfo **info) { if (!info || !*info) - return true; + return; - bool success = true; - success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL ); - success &= mpw_free( info, sizeof( MPMarshalInfo ) ); - - return success; + mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL ); + mpw_free( info, sizeof( MPMarshalInfo ) ); } -static bool mpw_marshal_user_free( +void mpw_marshal_user_free( MPMarshalledUser **user) { if (!user || !*user) - return true; + return; - bool success = mpw_free_strings( &(*user)->fullName, &(*user)->keyID, NULL ); + mpw_free_strings( &(*user)->fullName, &(*user)->keyID, NULL ); for (size_t s = 0; s < (*user)->sites_count; ++s) { MPMarshalledSite *site = &(*user)->sites[s]; - success &= mpw_free_strings( &site->siteName, &site->resultState, &site->loginState, &site->url, NULL ); + mpw_free_strings( &site->siteName, &site->resultState, &site->loginState, &site->url, NULL ); for (size_t q = 0; q < site->questions_count; ++q) { MPMarshalledQuestion *question = &site->questions[q]; - success &= mpw_free_strings( &question->keyword, &question->state, NULL ); + mpw_free_strings( &question->keyword, &question->state, NULL ); } - success &= mpw_free( &site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count ); + mpw_free( &site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count ); } - success &= mpw_free( &(*user)->sites, sizeof( MPMarshalledSite ) * (*user)->sites_count ); - success &= mpw_free( user, sizeof( MPMarshalledUser ) ); - - return success; + mpw_free( &(*user)->sites, sizeof( MPMarshalledSite ) * (*user)->sites_count ); + mpw_free( user, sizeof( MPMarshalledUser ) ); } -static bool mpw_marshal_data_null( - MPMarshalledData *data) { - - if (!data) - return true; - - bool success = mpw_free_strings( &data->key, &data->str_value, NULL ); - for (unsigned int c = 0; c < data->children_count; ++c) - success &= mpw_marshal_data_null( &data->children[c] ); - success &= mpw_free( &data->children, sizeof( MPMarshalledData ) * data->children_count ); - data->children_count = 0; - data->num_value = NAN; - data->is_bool = false; - data->is_null = true; - - return success; -} - -bool mpw_marshal_free( +void mpw_marshal_file_free( MPMarshalledFile **file) { if (!file || !*file) - return true; + return; - bool success = true; + mpw_marshal_info_free( &(*file)->info ); + mpw_marshal_user_free( &(*file)->user ); + if ((*file)->data) { + mpw_marshal_data_set_null( (*file)->data, NULL ); + mpw_free_string( &(*file)->data->key ); + mpw_free( &(*file)->data, sizeof( MPMarshalledData ) ); + } + mpw_free( file, sizeof( MPMarshalledFile ) ); +} - success &= mpw_marshal_info_free( &(*file)->info ); - success &= mpw_marshal_user_free( &(*file)->user ); - success &= mpw_marshal_data_null( (*file)->data ); - success &= mpw_free( &(*file)->data, sizeof( MPMarshalledData ) ); - success &= mpw_free( file, sizeof( MPMarshalledFile ) ); +MPMarshalledData *mpw_marshal_data_new() { + + MPMarshalledData *data = malloc( sizeof( MPMarshalledData ) ); + *data = (MPMarshalledData){}; + mpw_marshal_data_set_null( data, NULL ); + return data; +} + +MPMarshalledData *mpw_marshal_data_vget( + MPMarshalledData *data, va_list nodes) { + + MPMarshalledData *parent = data, *child; + for (const char *node; parent && (node = va_arg( nodes, const char * )); parent = child) { + child = NULL; + + for (size_t c = 0; c < parent->children_count; ++c) { + const char *key = parent->children[c].key; + if (key && strcmp( node, key ) == OK) { + child = &parent->children[c]; + break; + } + } + + if (!child) { + if (!mpw_realloc( &parent->children, NULL, sizeof( MPMarshalledData ) * ++parent->children_count )) { + --parent->children_count; + break; + } + *(child = &parent->children[parent->children_count - 1]) = (MPMarshalledData){ .key = mpw_strdup( node ) }; + mpw_marshal_data_set_null( child, NULL ); + child->is_null = false; + } + } + + return parent; +} + +MPMarshalledData *mpw_marshal_data_get( + MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + MPMarshalledData *child = mpw_marshal_data_vget( data, nodes ); + va_end( nodes ); + + return child; +} + +const MPMarshalledData *mpw_marshal_data_vfind( + const MPMarshalledData *data, va_list nodes) { + + const MPMarshalledData *parent = data, *child; + for (const char *node; parent && (node = va_arg( nodes, const char * )); parent = child) { + child = NULL; + + for (size_t c = 0; c < parent->children_count; ++c) { + const char *key = parent->children[c].key; + if (key && strcmp( node, key ) == OK) { + child = &parent->children[c]; + break; + } + } + + if (!child) + break; + } + + return parent; +} + +const MPMarshalledData *mpw_marshal_data_find( + const MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + const MPMarshalledData *child = mpw_marshal_data_vfind( data, nodes ); + va_end( nodes ); + + return child; +} + +bool mpw_marshal_data_vis_null( + const MPMarshalledData *data, va_list nodes) { + + const MPMarshalledData *child = mpw_marshal_data_vfind( data, nodes ); + return !child || child->is_null; +} + +bool mpw_marshal_data_is_null( + const MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool value = mpw_marshal_data_vis_null( data, nodes ); + va_end( nodes ); + + return value; +} + +bool mpw_marshal_data_vset_null( + MPMarshalledData *data, va_list nodes) { + + MPMarshalledData *child = mpw_marshal_data_vget( data, nodes ); + if (!child) + return false; + + mpw_free_string( &child->str_value ); + for (unsigned int c = 0; c < child->children_count; ++c) { + mpw_marshal_data_set_null( &child->children[c], NULL ); + mpw_free_string( &child->children[c].key ); + } + mpw_free( &child->children, sizeof( MPMarshalledData ) * child->children_count ); + child->children_count = 0; + child->num_value = NAN; + child->is_bool = false; + child->is_null = true; + return true; +} + +bool mpw_marshal_data_set_null( + MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool success = mpw_marshal_data_vset_null( data, nodes ); + va_end( nodes ); + + return success; +} + +bool mpw_marshal_data_vget_bool( + const MPMarshalledData *data, va_list nodes) { + + const MPMarshalledData *child = mpw_marshal_data_vfind( data, nodes ); + return child && child->is_bool && child->num_value != false; +} + +bool mpw_marshal_data_get_bool( + const MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool value = mpw_marshal_data_vget_bool( data, nodes ); + va_end( nodes ); + + return value; +} + +bool mpw_marshal_data_vset_bool( + const bool value, MPMarshalledData *data, va_list nodes) { + + MPMarshalledData *child = mpw_marshal_data_vget( data, nodes ); + if (!child || !mpw_marshal_data_set_null( child, NULL )) + return false; + + child->is_null = false; + child->is_bool = true; + child->num_value = value != false; + return true; +} + +bool mpw_marshal_data_set_bool( + const bool value, MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool success = mpw_marshal_data_vset_bool( value, data, nodes ); + va_end( nodes ); + + return success; +} + +double mpw_marshal_data_vget_num( + const MPMarshalledData *data, va_list nodes) { + + const MPMarshalledData *child = mpw_marshal_data_vfind( data, nodes ); + return child == NULL? NAN: child->num_value; +} + +double mpw_marshal_data_get_num( + const MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + double value = mpw_marshal_data_vget_num( data, nodes ); + va_end( nodes ); + + return value; +} + +bool mpw_marshal_data_vset_num( + const double value, MPMarshalledData *data, va_list nodes) { + + MPMarshalledData *child = mpw_marshal_data_vget( data, nodes ); + if (!child || !mpw_marshal_data_set_null( child, NULL )) + return false; + + child->is_null = false; + child->num_value = value; + child->str_value = mpw_strdup( mpw_str( "%g", value ) ); + return true; +} + +bool mpw_marshal_data_set_num( + const double value, MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool success = mpw_marshal_data_vset_num( value, data, nodes ); + va_end( nodes ); + + return success; +} + +const char *mpw_marshal_data_vget_str( + const MPMarshalledData *data, va_list nodes) { + + const MPMarshalledData *child = mpw_marshal_data_vfind( data, nodes ); + return child == NULL? NULL: mpw_strdup( child->str_value ); +} + +const char *mpw_marshal_data_get_str( + const MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + const char *value = mpw_marshal_data_vget_str( data, nodes ); + va_end( nodes ); + + return value; +} + +bool mpw_marshal_data_vset_str( + const char *value, MPMarshalledData *data, va_list nodes) { + + MPMarshalledData *child = mpw_marshal_data_vget( data, nodes ); + if (!child || !mpw_marshal_data_set_null( child, NULL )) + return false; + + if (value) { + child->is_null = false; + child->str_value = mpw_strdup( value ); + } + + return true; +} + +bool mpw_marshal_data_set_str( + const char *value, MPMarshalledData *data, ...) { + + va_list nodes; + va_start( nodes, data ); + bool success = mpw_marshal_data_vset_str( value, data, nodes ); + va_end( nodes ); return success; } @@ -285,20 +519,24 @@ static const char *mpw_marshal_write_flat( #if MPW_JSON static json_object *mpw_get_json_data( - MPMarshalledData *data) { + const MPMarshalledData *data) { if (!data || data->is_null) return NULL; if (data->is_bool) return json_object_new_boolean( data->num_value != false ); - if (!isnan( data->num_value )) - return json_object_new_double_s( data->num_value, data->str_value ); + if (!isnan( data->num_value )) { + if (data->str_value) + return json_object_new_double_s( data->num_value, data->str_value ); + else + return json_object_new_double( data->num_value ); + } if (data->str_value) return json_object_new_string( data->str_value ); json_object *obj = NULL; - for (size_t index = 0; index < data->children_count; ++index) { - MPMarshalledData *child = &data->children[index]; + for (size_t c = 0; c < data->children_count; ++c) { + MPMarshalledData *child = &data->children[c]; if (!obj) { if (child->key) obj = json_object_new_object(); @@ -505,8 +743,8 @@ static void mpw_marshal_read_flat_info( break; // Header - char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); - char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); + const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); + const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); if (!headerName || !headerValue) continue; @@ -605,8 +843,8 @@ static MPMarshalledFile *mpw_marshal_read_flat( } // Header - char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); - char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); + const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); + const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); if (!headerName || !headerValue) { error->type = MPMarshalErrorStructure; error->message = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) ); @@ -672,8 +910,8 @@ static MPMarshalledFile *mpw_marshal_read_flat( continue; // Site - char *siteName = NULL, *siteResultState = NULL, *siteLoginState = NULL; - char *str_lastUsed = NULL, *str_uses = NULL, *str_type = NULL, *str_algorithm = NULL, *str_counter = NULL; + const char *siteName = NULL, *siteResultState = NULL, *siteLoginState = NULL; + const char *str_lastUsed = NULL, *str_uses = NULL, *str_type = NULL, *str_algorithm = NULL, *str_counter = NULL; switch (format) { case 0: { str_lastUsed = mpw_get_token( &positionInLine, endOfLine, " \t\n" ); @@ -834,6 +1072,9 @@ static MPMarshalledFile *mpw_marshal_read_flat( static void mpw_set_json_data( MPMarshalledData *data, json_object *obj) { + if (!data) + return; + json_type type = json_object_get_type( obj ); data->is_null = type == json_type_null; data->is_bool = type == json_type_boolean; @@ -860,16 +1101,15 @@ static void mpw_set_json_data( size_t newChildrenCount = 0; for (size_t c = 0; c < data->children_count; ++c) { MPMarshalledData *child = &data->children[c]; - if ((type != json_type_object && type != json_type_array) || - (child->key && type != json_type_object) || (!isnan( child->index ) && type != json_type_array)) { - mpw_marshal_data_null( child ); - if (!newChildren) { - newChildren = malloc( sizeof( MPMarshalledData ) * newChildrenCount ); - if (newChildren) - memcpy( newChildren, data->children, sizeof( MPMarshalledData ) * newChildrenCount ); - } + if ((type != json_type_object && type != json_type_array) || (child->key && type != json_type_object)) { + // Not a valid child in this object, remove it. + mpw_marshal_data_set_null( child, NULL ); + mpw_free_string( &child->key ); + if (!newChildren) + newChildren = mpw_memdup( data->children, sizeof( MPMarshalledData ) * newChildrenCount ); } else { + // Valid child in this object, keep it. ++newChildrenCount; if (newChildren) { if (!mpw_realloc( &newChildren, NULL, sizeof( MPMarshalledData ) * newChildrenCount )) { @@ -896,7 +1136,7 @@ static void mpw_set_json_data( // Find existing child. for (size_t c = 0; c < data->children_count; ++c) if (data->children[c].key == entry.key || - (data->children[c].key && entry.key && strcmp( data->children[c].key, entry.key )) == OK) { + (data->children[c].key && entry.key && strcmp( data->children[c].key, entry.key ) == OK)) { child = &data->children[c]; break; } @@ -965,7 +1205,7 @@ static void mpw_marshal_read_json_info( } static MPMarshalledFile *mpw_marshal_read_json( - const char *in, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { + const char *in, const MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." }; if (!in || !strlen( in )) { @@ -1173,11 +1413,8 @@ static MPMarshalledFile *mpw_marshal_read_json( } mpw_free( &masterKey, MPMasterKeySize ); - MPMarshalledData *data = malloc( sizeof( MPMarshalledData ) ); - if (data) { - *data = (MPMarshalledData){}; - mpw_set_json_data( data, json_file ); - } + MPMarshalledData *data = mpw_marshal_data_new(); + mpw_set_json_data( data, json_file ); json_object_put( json_file ); MPMarshalledFile *file = mpw_marshal_file( user, data ); @@ -1223,7 +1460,7 @@ MPMarshalInfo *mpw_marshal_read_info( } MPMarshalledFile *mpw_marshal_read( - const char *in, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { + const char *in, const MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { MPMarshalInfo *info = mpw_marshal_read_info( in ); if (!info) @@ -1314,10 +1551,10 @@ const char **mpw_marshal_format_extensions( return NULL; case MPMarshalFormatFlat: return mpw_strings( count, - mpw_marshal_format_extension( format ), "mpsites.txt", "txt" ); + mpw_marshal_format_extension( format ), "mpsites.txt", "txt", NULL ); case MPMarshalFormatJSON: return mpw_strings( count, - mpw_marshal_format_extension( format ), "mpsites.json", "json" ); + mpw_marshal_format_extension( format ), "mpsites.json", "json", NULL ); default: { dbg( "Unknown format: %d", format ); return NULL; diff --git a/platform-independent/c/core/src/mpw-marshal.h b/platform-independent/c/core/src/mpw-marshal.h index 4c4d40d1..aad8342a 100644 --- a/platform-independent/c/core/src/mpw-marshal.h +++ b/platform-independent/c/core/src/mpw-marshal.h @@ -23,6 +23,7 @@ MP_LIBS_BEGIN #include +#include MP_LIBS_END //// Types. @@ -161,14 +162,14 @@ MPMarshalInfo *mpw_marshal_read_info( /** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. * @return A user object (allocated), or NULL if the format provides no marshalling or a format error occurred. */ MPMarshalledFile *mpw_marshal_read( - const char *in, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error); + const char *in, const MPMasterKeyProvider masterKeyProvider, MPMarshalError *error); -//// Utilities. +//// Creating. /** Create a new user object ready for marshalling. * @return A user object (allocated), or NULL if the fullName is missing or the marshalled user couldn't be allocated. */ MPMarshalledUser *mpw_marshal_user( - const char *fullName, MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion); + const char *fullName, const MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion); /** Create a new site attached to the given user object, ready for marshalling. * @return A site object (allocated), or NULL if the siteName is missing or the marshalled site couldn't be allocated. */ MPMarshalledSite *mpw_marshal_site( @@ -183,11 +184,77 @@ MPMarshalledQuestion *mpw_marshal_question( MPMarshalledFile *mpw_marshal_file( MPMarshalledUser *user, MPMarshalledData *data); +//// Disposing. + /** Free the given user object and all associated data. */ -bool mpw_marshal_info_free( +void mpw_marshal_info_free( MPMarshalInfo **info); -bool mpw_marshal_free( - MPMarshalledFile **user); +void mpw_marshal_user_free( + MPMarshalledUser **user); +void mpw_marshal_file_free( + MPMarshalledFile **file); + +//// Exploring. + +/** Create a null value. + * @return A new data value (allocated), initialized to a null value, or NULL if the value couldn't be allocated. */ +MPMarshalledData *mpw_marshal_data_new(void); +/** Get or create a value for the given path in the data store. + * @return The value at this path (shared), or NULL if the value didn't exist and couldn't be created. */ +MPMarshalledData *mpw_marshal_data_get( + MPMarshalledData *data, ...); +MPMarshalledData *mpw_marshal_data_vget( + MPMarshalledData *data, va_list nodes); +/** Look up the value at the given path in the data store. + * @return The value at this path (shared), or NULL if there is no value at this path. */ +const MPMarshalledData *mpw_marshal_data_find( + const MPMarshalledData *data, ...); +const MPMarshalledData *mpw_marshal_data_vfind( + const MPMarshalledData *data, va_list nodes); +/** Check if the data represents a NULL value. + * @return true if the value at this path is null or is missing, false if it is a non-null type. */ +bool mpw_marshal_data_is_null( + const MPMarshalledData *data, ...); +bool mpw_marshal_data_vis_null( + const MPMarshalledData *data, va_list nodes); +/** Set a null value at the given path in the data store. + * @return true if the object was successfully modified. */ +bool mpw_marshal_data_set_null( + MPMarshalledData *data, ...); +bool mpw_marshal_data_vset_null( + MPMarshalledData *data, va_list nodes); +/** Look up the boolean value at the given path in the data store. + * @return true if the value at this path is true, false if it is not or there is no boolean value at this path. */ +bool mpw_marshal_data_get_bool( + const MPMarshalledData *data, ...); +bool mpw_marshal_data_vget_bool( + const MPMarshalledData *data, va_list nodes); +/** Set a boolean value at the given path in the data store. + * @return true if the object was successfully modified. */ +bool mpw_marshal_data_set_bool( + const bool value, MPMarshalledData *data, ...); +bool mpw_marshal_data_vset_bool( + const bool value, MPMarshalledData *data, va_list nodes); +/** Look up the numeric value at the given path in the data store. + * @return A number or NAN if there is no numeric value at this path. */ +double mpw_marshal_data_get_num( + const MPMarshalledData *data, ...); +double mpw_marshal_data_vget_num( + const MPMarshalledData *data, va_list nodes); +bool mpw_marshal_data_set_num( + const double value, MPMarshalledData *data, ...); +bool mpw_marshal_data_vset_num( + const double value, MPMarshalledData *data, va_list nodes); +/** Look up the string value at the given path in the data store. + * @return The string value (allocated) or string representation of the number at this path; NULL if there is no such value at this path. */ +const char *mpw_marshal_data_get_str( + const MPMarshalledData *data, ...); +const char *mpw_marshal_data_vget_str( + const MPMarshalledData *data, va_list nodes); +bool mpw_marshal_data_set_str( + const char *value, MPMarshalledData *data, ...); +bool mpw_marshal_data_vset_str( + const char *value, MPMarshalledData *data, va_list nodes); //// Format. diff --git a/platform-independent/c/core/src/mpw-types.c b/platform-independent/c/core/src/mpw-types.c index 006d9491..3eaf4341 100644 --- a/platform-independent/c/core/src/mpw-types.c +++ b/platform-independent/c/core/src/mpw-types.c @@ -90,7 +90,7 @@ const MPResultType mpw_type_named(const char *typeName) { return (MPResultType)ERR; } -const char *mpw_type_abbreviation(MPResultType resultType) { +const char *mpw_type_abbreviation(const MPResultType resultType) { switch (resultType) { case MPResultTypeTemplateMaximum: @@ -122,7 +122,7 @@ const char *mpw_type_abbreviation(MPResultType resultType) { } } -const char *mpw_type_short_name(MPResultType resultType) { +const char *mpw_type_short_name(const MPResultType resultType) { switch (resultType) { case MPResultTypeTemplateMaximum: @@ -154,7 +154,7 @@ const char *mpw_type_short_name(MPResultType resultType) { } } -const char *mpw_type_long_name(MPResultType resultType) { +const char *mpw_type_long_name(const MPResultType resultType) { switch (resultType) { case MPResultTypeTemplateMaximum: @@ -186,7 +186,7 @@ const char *mpw_type_long_name(MPResultType resultType) { } } -const char **mpw_type_templates(MPResultType type, size_t *count) { +const char **mpw_type_templates(const MPResultType type, size_t *count) { if (!(type & MPResultTypeClassTemplate)) { dbg( "Not a generated type: %d", type ); @@ -231,7 +231,7 @@ const char **mpw_type_templates(MPResultType type, size_t *count) { } } -const char *mpw_type_template(MPResultType type, uint8_t templateIndex) { +const char *mpw_type_template(const MPResultType type, const uint8_t templateIndex) { size_t count = 0; const char **templates = mpw_type_templates( type, &count ); @@ -254,7 +254,7 @@ const MPKeyPurpose mpw_purpose_named(const char *purposeName) { return (MPKeyPurpose)ERR; } -const char *mpw_purpose_name(MPKeyPurpose purpose) { +const char *mpw_purpose_name(const MPKeyPurpose purpose) { switch (purpose) { case MPKeyPurposeAuthentication: @@ -270,7 +270,7 @@ const char *mpw_purpose_name(MPKeyPurpose purpose) { } } -const char *mpw_purpose_scope(MPKeyPurpose purpose) { +const char *mpw_purpose_scope(const MPKeyPurpose purpose) { switch (purpose) { case MPKeyPurposeAuthentication: @@ -286,7 +286,7 @@ const char *mpw_purpose_scope(MPKeyPurpose purpose) { } } -const char *mpw_class_characters(char characterClass) { +const char *mpw_class_characters(const char characterClass) { switch (characterClass) { case 'V': @@ -316,7 +316,7 @@ const char *mpw_class_characters(char characterClass) { } } -const char mpw_class_character(char characterClass, uint8_t seedByte) { +const char mpw_class_character(const char characterClass, const uint8_t seedByte) { const char *classCharacters = mpw_class_characters( characterClass ); if (!classCharacters || !strlen( classCharacters )) diff --git a/platform-independent/c/core/src/mpw-types.h b/platform-independent/c/core/src/mpw-types.h index b69588f7..3d71f060 100644 --- a/platform-independent/c/core/src/mpw-types.h +++ b/platform-independent/c/core/src/mpw-types.h @@ -152,11 +152,11 @@ const MPKeyPurpose mpw_purpose_named(const char *purposeName); /** * @return The standard name (static) for the given purpose or NULL if the purpose is not known. */ -const char *mpw_purpose_name(MPKeyPurpose purpose); +const char *mpw_purpose_name(const MPKeyPurpose purpose); /** * @return The scope identifier (static) to apply when encoding for the given purpose or NULL if the purpose is not known. */ -const char *mpw_purpose_scope(MPKeyPurpose purpose); +const char *mpw_purpose_scope(const MPKeyPurpose purpose); /** * @return The password type represented by the given name or ERR if the name does not represent a known type. @@ -165,34 +165,34 @@ const MPResultType mpw_type_named(const char *typeName); /** * @return The standard identifying name (static) for the given password type or NULL if the type is not known. */ -const char *mpw_type_abbreviation(MPResultType resultType); +const char *mpw_type_abbreviation(const MPResultType resultType); /** * @return The standard identifying name (static) for the given password type or NULL if the type is not known. */ -const char *mpw_type_short_name(MPResultType resultType); +const char *mpw_type_short_name(const MPResultType resultType); /** * @return The descriptive name (static) for the given password type or NULL if the type is not known. */ -const char *mpw_type_long_name(MPResultType resultType); +const char *mpw_type_long_name(const MPResultType resultType); /** * @return An array (allocated, count) of strings (static) that express the templates to use for the given type. * NULL if the type is not known or is not a MPResultTypeClassTemplate. */ -const char **mpw_type_templates(MPResultType type, size_t *count); +const char **mpw_type_templates(const MPResultType type, size_t *count); /** * @return A string (static) that contains the password encoding template of the given type for a seed that starts with the given byte. * NULL if the type is not known or is not a MPResultTypeClassTemplate. */ -const char *mpw_type_template(MPResultType type, uint8_t templateIndex); +const char *mpw_type_template(const MPResultType type, const uint8_t templateIndex); /** * @return An string (static) with all the characters in the given character class or NULL if the character class is not known. */ -const char *mpw_class_characters(char characterClass); +const char *mpw_class_characters(const char characterClass); /** * @return A character from given character class that encodes the given byte or NUL if the character class is not known or is empty. */ -const char mpw_class_character(char characterClass, uint8_t seedByte); +const char mpw_class_character(const char characterClass, const uint8_t seedByte); #endif // _MPW_TYPES_H diff --git a/platform-independent/c/core/src/mpw-util.c b/platform-independent/c/core/src/mpw-util.c index 40a8b48a..2812fcc7 100644 --- a/platform-independent/c/core/src/mpw-util.c +++ b/platform-independent/c/core/src/mpw-util.c @@ -175,7 +175,7 @@ bool __mpw_free(void **buffer, const size_t bufferSize) { bool __mpw_free_string(char **string) { - return *string && __mpw_free( (void **)string, strlen( *string ) ); + return string && *string && __mpw_free( (void **)string, strlen( *string ) ); } bool __mpw_free_strings(char **strings, ...) { @@ -193,7 +193,7 @@ bool __mpw_free_strings(char **strings, ...) { } uint8_t const *mpw_kdf_scrypt(const size_t keySize, const uint8_t *secret, const size_t secretSize, const uint8_t *salt, const size_t saltSize, - uint64_t N, uint32_t r, uint32_t p) { + const uint64_t N, const uint32_t r, const uint32_t p) { if (!secret || !salt || !secretSize || !saltSize) return NULL; @@ -367,7 +367,7 @@ const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor, } #endif -MPKeyID mpw_id_buf(const void *buf, size_t length) { +const MPKeyID mpw_id_buf(const void *buf, const size_t length) { if (!buf) return NULL; @@ -443,7 +443,7 @@ const char *mpw_vstr(const char *format, va_list args) { return str_str[str_str_i]; } -const char *mpw_hex(const void *buf, size_t length) { +const char *mpw_hex(const void *buf, const size_t length) { if (!buf || !length) return NULL; @@ -461,7 +461,7 @@ const char *mpw_hex(const void *buf, size_t length) { return mpw_hex_buf[mpw_hex_buf_i]; } -const char *mpw_hex_l(uint32_t number) { +const char *mpw_hex_l(const uint32_t number) { uint8_t buf[4 /* 32 / 8 */]; buf[0] = (uint8_t)((number >> 24) & UINT8_MAX); @@ -496,7 +496,7 @@ size_t mpw_utf8_strchars(const char *utf8String) { return strchars; } -void *mpw_memdup(const void *src, size_t len) { +void *mpw_memdup(const void *src, const size_t len) { if (!src) return NULL; @@ -517,7 +517,7 @@ char *mpw_strdup(const char *src) { return mpw_memdup( src, len + 1 ); } -char *mpw_strndup(const char *src, size_t max) { +char *mpw_strndup(const char *src, const size_t max) { if (!src) return NULL; @@ -525,8 +525,7 @@ char *mpw_strndup(const char *src, size_t max) { size_t len = 0; for (; len < max && src[len] != '\0'; ++len); - char *dst = malloc( len + 1 ); - memcpy( dst, src, len ); + char *dst = mpw_memdup( src, len + 1 ); dst[len] = '\0'; return dst; diff --git a/platform-independent/c/core/src/mpw-util.h b/platform-independent/c/core/src/mpw-util.h index e8bfe866..b687e480 100644 --- a/platform-independent/c/core/src/mpw-util.h +++ b/platform-independent/c/core/src/mpw-util.h @@ -122,7 +122,7 @@ bool mpw_string_push( bool mpw_string_pushf( char **string, const char *pushFormat, ...); -// These defines merely exist to force the void** cast (& do type-checking), since void** casts are not automatic. +// These defines merely exist to do type-checking, force the void** cast & drop any const qualifier. /** Reallocate the given buffer from the given size by adding the delta size. * On success, the buffer size pointer will be updated to the buffer's new size * and the buffer pointer may be updated to a new memory address. @@ -176,7 +176,7 @@ bool __mpw_free_string( bool __mpw_free_strings( char **strings, ...); void mpw_zero( - void *buffer, size_t bufferSize); + void *buffer, const size_t bufferSize); //// Cryptographic functions. @@ -184,7 +184,7 @@ void mpw_zero( * @return A buffer (allocated, keySize) containing the key or NULL if secret or salt is missing, key could not be allocated or the KDF failed. */ uint8_t const *mpw_kdf_scrypt( const size_t keySize, const uint8_t *secret, const size_t secretSize, const uint8_t *salt, const size_t saltSize, - uint64_t N, uint32_t r, uint32_t p); + const uint64_t N, const uint32_t r, const uint32_t p); /** Derive a subkey from the given key using the blake2b KDF. * @return A buffer (allocated, keySize) containing the key or NULL if the key or subkeySize is missing, the key sizes are out of bounds, the subkey could not be allocated or derived. */ uint8_t const *mpw_kdf_blake2b( @@ -217,11 +217,11 @@ const char *mpw_str(const char *format, ...); const char *mpw_vstr(const char *format, va_list args); /** Encode a buffer as a string of hexadecimal characters. * @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */ -const char *mpw_hex(const void *buf, size_t length); -const char *mpw_hex_l(uint32_t number); +const char *mpw_hex(const void *buf, const size_t length); +const char *mpw_hex_l(const uint32_t number); /** Encode a fingerprint for a buffer. * @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */ -MPKeyID mpw_id_buf(const void *buf, size_t length); +const MPKeyID mpw_id_buf(const void *buf, const size_t length); /** Compare two fingerprints for equality. * @return true if the buffers represent identical fingerprints or are both NULL. */ bool mpw_id_buf_equals(const char *id1, const char *id2); @@ -234,14 +234,14 @@ size_t mpw_utf8_charlen(const char *utf8String); size_t mpw_utf8_strchars(const char *utf8String); /** Drop-in for memdup(3). * @return A buffer (allocated, len) with len bytes copied from src or NULL if src is missing or the buffer could not be allocated. */ -void *mpw_memdup(const void *src, size_t len); +void *mpw_memdup(const void *src, const size_t len); /** Drop-in for POSIX strdup(3). * @return A string (allocated) copied from src or NULL if src is missing or the buffer could not be allocated. */ char *mpw_strdup(const char *src); /** Drop-in for POSIX strndup(3). * @return A string (allocated) with no more than max bytes copied from src or NULL if src is missing or the buffer could not be allocated. */ -char *mpw_strndup(const char *src, size_t max); +char *mpw_strndup(const char *src, const size_t max); /** Drop-in for POSIX strncasecmp(3). */ -int mpw_strncasecmp(const char *s1, const char *s2, size_t max); +int mpw_strncasecmp(const char *s1, const char *s2, const size_t max); #endif // _MPW_UTIL_H