diff --git a/platform-independent/c/core/src/mpw-marshal-util.c b/platform-independent/c/core/src/mpw-marshal-util.c index 296e2ea2..f4aba58d 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.c +++ b/platform-independent/c/core/src/mpw-marshal-util.c @@ -31,7 +31,7 @@ char *mpw_get_token(const char **in, const char *eol, const char *delim) { // Find characters up to the first delim. size_t len = strcspn( *in, delim ); - char *token = len && len <= (size_t)(eol - *in)? mpw_strndup( *in, len ): NULL; + char *token = len <= (size_t)(eol - *in)? mpw_strndup( *in, len ): NULL; // Advance past the delimitor. *in = min( eol, *in + len + 1 ); diff --git a/platform-independent/c/core/src/mpw-marshal.c b/platform-independent/c/core/src/mpw-marshal.c index 458c32c1..401d6048 100644 --- a/platform-independent/c/core/src/mpw-marshal.c +++ b/platform-independent/c/core/src/mpw-marshal.c @@ -552,12 +552,12 @@ static const char *mpw_marshal_write_flat( mpw_string_pushf( &out, "##\n" ); mpw_string_pushf( &out, "# Format: %d\n", 1 ); - mpw_string_pushf( &out, "# Date: %s\n", mpw_marshal_data_get_str( data, "export", "date", NULL ) ); - mpw_string_pushf( &out, "# User Name: %s\n", mpw_marshal_data_get_str( data, "user", "full_name", NULL ) ); - mpw_string_pushf( &out, "# Full Name: %s\n", mpw_marshal_data_get_str( data, "user", "full_name", NULL ) ); + mpw_string_pushf( &out, "# Date: %s\n", mpw_default( "", mpw_marshal_data_get_str( data, "export", "date", NULL ) ) ); + mpw_string_pushf( &out, "# User Name: %s\n", mpw_default( "", mpw_marshal_data_get_str( data, "user", "full_name", NULL ) ) ); + mpw_string_pushf( &out, "# Full Name: %s\n", mpw_default( "", mpw_marshal_data_get_str( data, "user", "full_name", NULL ) ) ); mpw_string_pushf( &out, "# Avatar: %u\n", (unsigned int)mpw_marshal_data_get_num( data, "user", "avatar", NULL ) ); - mpw_string_pushf( &out, "# Identicon: %s\n", mpw_marshal_data_get_str( data, "user", "identicon", NULL ) ); - mpw_string_pushf( &out, "# Key ID: %s\n", mpw_marshal_data_get_str( data, "user", "key_id", NULL ) ); + mpw_string_pushf( &out, "# Identicon: %s\n", mpw_default( "", mpw_marshal_data_get_str( data, "user", "identicon", NULL ) ) ); + mpw_string_pushf( &out, "# Key ID: %s\n", mpw_default( "", mpw_marshal_data_get_str( data, "user", "key_id", NULL ) ) ); mpw_string_pushf( &out, "# Algorithm: %d\n", (MPAlgorithmVersion)mpw_marshal_data_get_num( data, "user", "algorithm", NULL ) ); mpw_string_pushf( &out, "# Default Type: %d\n", (MPResultType)mpw_marshal_data_get_num( data, "user", "default_type", NULL ) ); mpw_string_pushf( &out, "# Passwords: %s\n", mpw_marshal_data_get_bool( data, "export", "redacted", NULL )? "PROTECTED": "VISIBLE" ); @@ -571,15 +571,15 @@ static const char *mpw_marshal_write_flat( for (size_t s = 0; s < (sites? sites->children_count: 0); ++s) { const MPMarshalledData *site = &sites->children[s]; mpw_string_pushf( &out, "%s %8ld %8s %25s\t%25s\t%s\n", - mpw_default( (char *)"", mpw_marshal_data_get_str( site, "last_used", NULL ) ), + mpw_default( "", mpw_marshal_data_get_str( site, "last_used", NULL ) ), (long)mpw_marshal_data_get_num( site, "uses", NULL ), mpw_str( "%lu:%lu:%lu", (long)mpw_marshal_data_get_num( site, "type", NULL ), (long)mpw_marshal_data_get_num( site, "algorithm", NULL ), (long)mpw_marshal_data_get_num( site, "counter", NULL ) ), - mpw_default( (char *)"", mpw_marshal_data_get_str( site, "login_name", NULL ) ), + mpw_default( "", mpw_marshal_data_get_str( site, "login_name", NULL ) ), site->obj_key, - mpw_default( (char *)"", mpw_marshal_data_get_str( site, "password", NULL ) ) ); + mpw_default( "", mpw_marshal_data_get_str( site, "password", NULL ) ) ); } if (!out) @@ -878,13 +878,15 @@ static void mpw_marshal_read_flat( } // Header + const char *line = positionInLine; const char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); const char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); if (!headerName || !headerValue) { file->error = (MPMarshalError){ MPMarshalErrorStructure, - mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) ) + mpw_str( "Invalid header: %s", mpw_strndup( line, (size_t)(endOfLine - line) ) ) }; + mpw_free_strings( &headerName, &headerValue, NULL ); continue; } @@ -956,7 +958,7 @@ static void mpw_marshal_read_flat( str_counter = mpw_strdup( strtok( NULL, "" ) ); mpw_free_string( &typeAndVersionAndCounter ); } - siteLoginState = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); + siteLoginState = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); // TODO: Needs to be encoded if redacted? siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); siteResultState = mpw_get_token( &positionInLine, endOfLine, "\n" ); break; @@ -999,9 +1001,9 @@ static void mpw_marshal_read_flat( mpw_marshal_data_set_num( siteCounter, file->data, "sites", siteName, "counter", NULL ); mpw_marshal_data_set_num( siteAlgorithm, file->data, "sites", siteName, "algorithm", NULL ); mpw_marshal_data_set_num( siteType, file->data, "sites", siteName, "type", NULL ); - mpw_marshal_data_set_str( siteResultState, file->data, "sites", siteName, "password", NULL ); + mpw_marshal_data_set_str( siteResultState && strlen( siteResultState )? siteResultState: NULL, file->data, "sites", siteName, "password", NULL ); mpw_marshal_data_set_num( MPResultTypeDefault, file->data, "sites", siteName, "login_type", NULL ); - mpw_marshal_data_set_str( siteLoginState, file->data, "sites", siteName, "login_name", NULL ); + mpw_marshal_data_set_str( siteLoginState && strlen( siteLoginState )? siteLoginState: NULL, file->data, "sites", siteName, "login_name", NULL ); mpw_marshal_data_set_num( atoi( str_uses ), file->data, "sites", siteName, "uses", NULL ); if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &siteLastUsed ) )) mpw_marshal_data_set_str( dateString, file->data, "sites", siteName, "last_used", NULL ); diff --git a/platform-independent/c/core/src/mpw-marshal.h b/platform-independent/c/core/src/mpw-marshal.h index b9c66e93..d3a23b89 100644 --- a/platform-independent/c/core/src/mpw-marshal.h +++ b/platform-independent/c/core/src/mpw-marshal.h @@ -28,9 +28,6 @@ MP_LIBS_END //// Types. -#define mpw_default(__default, __value) ({ __typeof__ (__default) _v = (__typeof__ (__default))(__value); _v = _v? _v: __default; }) -#define mpw_default_n(__default, __num) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: __default; }) - typedef mpw_enum( unsigned int, MPMarshalFormat ) { /** Do not marshal. */ MPMarshalFormatNone, @@ -77,58 +74,92 @@ MPMasterKeyProvider mpw_masterKeyProvider_str(const char *masterPassword); void mpw_masterKeyProvider_free(void); typedef struct MPMarshalError { + /** The status of the most recent processing operation. */ MPMarshalErrorType type; + /** An explanation of the situation that caused the current status type. */ const char *message; } MPMarshalError; typedef struct MPMarshalledData { + /** If the parent is an object, this holds the key by which this data value is referenced. */ const char *obj_key; + /** If the parent is an array, this holds the index at which this data value is referenced. */ size_t arr_index; + /** Whether this data value represents a null value (true). */ bool is_null; + /** Whether this data value represents a boolean value (true). */ bool is_bool; + /** The textual value of this data if it holds a string. */ const char *str_value; + /** The numerical value of this data if it holds a number or a boolean. */ double num_value; + /** Amount of data values references under this value if it represents an object or an array. */ size_t children_count; + /** Array of data values referenced under this value. */ struct MPMarshalledData *children; } MPMarshalledData; typedef struct MPMarshalledInfo { + /** The data format used for serializing the file and user data into a byte stream. */ MPMarshalFormat format; + /** Date of when the file was previously serialized. */ time_t exportDate; + /** Whether secrets and state should be visible in clear-text (false) when serialized. */ bool redacted; + /** Algorithm version to use for user operations (eg. key ID operations). */ MPAlgorithmVersion algorithm; + /** A number identifying the avatar to display for the user in this file. */ unsigned int avatar; + /** Unique name for this file's user, preferably the user's full legal name. */ const char *fullName; + /** User metadata: The identicon that was generated to represent this file's user identity. */ MPIdenticon identicon; + /** A unique identifier (hex) for the user's master key, primarily for authentication/verification. */ const char *keyID; + /** User metadata: Date of the most recent action taken by this user. */ time_t lastUsed; } MPMarshalledInfo; typedef struct MPMarshalledQuestion { + /** Unique name for the security question, preferably a single key word from the question sentence. */ const char *keyword; + /** The result type to use for generating an answer. */ MPResultType type; + /** State data (base64), if any, necessary for generating the question's answer. */ const char *state; } MPMarshalledQuestion; typedef struct MPMarshalledSite { + /** Unique name for this site. */ const char *siteName; + /** Algorithm version to use for all site operations (eg. result, login, question operations). */ MPAlgorithmVersion algorithm; - MPCounterValue counter; + /** The counter value of the site result to generate. */ + MPCounterValue counter; + /** The result type to use for generating a site result. */ MPResultType resultType; + /** State data (base64), if any, necessary for generating the site result. */ const char *resultState; + /** The result type to use for generating a site login. */ MPResultType loginType; + /** State data (base64), if any, necessary for generating the site login. */ const char *loginState; + /** Site metadata: URL location where the site can be accessed. */ const char *url; + /** Site metadata: Amount of times an action has been taken for this site. */ unsigned int uses; + /** Site metadata: Date of the most recent action taken on this site. */ time_t lastUsed; + /** Amount of security questions associated with this site. */ size_t questions_count; + /** Array of security questions associated with this site. */ MPMarshalledQuestion *questions; } MPMarshalledSite; @@ -136,21 +167,33 @@ typedef struct MPMarshalledUser { MPMasterKeyProvider masterKeyProvider; bool redacted; + /** A number identifying the avatar to display for this user. */ unsigned int avatar; + /** Unique name for this user, preferably the user's full legal name. */ const char *fullName; + /** User metadata: The identicon that was generated to represent this user's identity. */ MPIdenticon identicon; + /** Algorithm version to use for user operations (eg. key ID operations). */ MPAlgorithmVersion algorithm; + /** A unique identifier (hex) for the user's master key, primarily for authentication/verification. */ const char *keyID; + /** The initial result type to use for new sites created by the user. */ MPResultType defaultType; + /** User metadata: Date of the most recent action taken by this user. */ time_t lastUsed; + /** Amount of sites associated to this user. */ size_t sites_count; + /** Array of sites associated to this user. */ MPMarshalledSite *sites; } MPMarshalledUser; typedef struct MPMarshalledFile { + /** Metadata from the file that holds user data, available without the need for user authentication. */ MPMarshalledInfo *info; + /** All data in the file, including extensions and other data present, even if not used by this library. */ MPMarshalledData *data; + /** Status of parsing the file and any errors that might have occurred during the process. */ MPMarshalError error; } MPMarshalledFile; diff --git a/platform-independent/c/core/src/mpw-util.h b/platform-independent/c/core/src/mpw-util.h index fd93a0a8..180c4dad 100644 --- a/platform-independent/c/core/src/mpw-util.h +++ b/platform-independent/c/core/src/mpw-util.h @@ -83,6 +83,9 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct #define ftl(format, ...) MPW_LOG( LogLevelFatal, __FILE__, __LINE__, __func__, format, ##__VA_ARGS__ ) #endif + +//// Utilities + #ifndef min #define min(a, b) ({ \ __typeof__ (a) _a = (a); \ @@ -108,6 +111,10 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct #define stringify_def(s) stringify(s) #endif +#define mpw_default(__default, __value) ({ __typeof__ (__value) _v = __value; _v? _v: __default; }) +#define mpw_default_n(__default, __num) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: __default; }) + + //// Buffers and memory. /** Write a number to a byte buffer using mpw's endianness (big/network endian). */