Change marshal API to return output directly.
Avoids an ambiguity between return type and out value (eg. true but NULL), and improves Swift API access.
This commit is contained in:
parent
f0acd1fed1
commit
6d36f17e57
@ -806,9 +806,9 @@ void cli_save(Arguments *args, Operation *operation) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *buf = NULL;
|
|
||||||
MPMarshalError marshalError = { .type = MPMarshalSuccess };
|
MPMarshalError marshalError = { .type = MPMarshalSuccess };
|
||||||
if (!mpw_marshal_write( &buf, operation->sitesFormat, operation->user, &marshalError ) || marshalError.type != MPMarshalSuccess || !buf)
|
const char *buf = mpw_marshal_write( operation->sitesFormat, operation->user, &marshalError );
|
||||||
|
if (!buf || marshalError.type != MPMarshalSuccess)
|
||||||
wrn( "Couldn't encode updated configuration file:\n %s: %s", operation->sitesPath, marshalError.description );
|
wrn( "Couldn't encode updated configuration file:\n %s: %s", operation->sitesPath, marshalError.description );
|
||||||
|
|
||||||
else if (fwrite( buf, sizeof( char ), strlen( buf ), sitesFile ) != strlen( buf ))
|
else if (fwrite( buf, sizeof( char ), strlen( buf ), sitesFile ) != strlen( buf ))
|
||||||
|
@ -134,45 +134,47 @@ bool mpw_marshal_free(
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mpw_marshal_write_flat(
|
static const char *mpw_marshal_write_flat(
|
||||||
char **out, const MPMarshalledUser *user, MPMarshalError *error) {
|
const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->fullName || !strlen( user->fullName )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpw_string_pushf( out, "# Master Password site export\n" );
|
char *out = NULL;
|
||||||
|
mpw_string_pushf( &out, "# Master Password site export\n" );
|
||||||
if (user->redacted)
|
if (user->redacted)
|
||||||
mpw_string_pushf( out, "# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n" );
|
mpw_string_pushf( &out,
|
||||||
|
"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n" );
|
||||||
else
|
else
|
||||||
mpw_string_pushf( out, "# Export of site names and passwords in clear-text.\n" );
|
mpw_string_pushf( &out, "# Export of site names and passwords in clear-text.\n" );
|
||||||
mpw_string_pushf( out, "# \n" );
|
mpw_string_pushf( &out, "# \n" );
|
||||||
mpw_string_pushf( out, "##\n" );
|
mpw_string_pushf( &out, "##\n" );
|
||||||
mpw_string_pushf( out, "# Format: %d\n", 1 );
|
mpw_string_pushf( &out, "# Format: %d\n", 1 );
|
||||||
|
|
||||||
char dateString[21];
|
char dateString[21];
|
||||||
time_t now = time( NULL );
|
time_t now = time( NULL );
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) ))
|
||||||
mpw_string_pushf( out, "# Date: %s\n", dateString );
|
mpw_string_pushf( &out, "# Date: %s\n", dateString );
|
||||||
mpw_string_pushf( out, "# User Name: %s\n", user->fullName );
|
mpw_string_pushf( &out, "# User Name: %s\n", user->fullName );
|
||||||
mpw_string_pushf( out, "# Full Name: %s\n", user->fullName );
|
mpw_string_pushf( &out, "# Full Name: %s\n", user->fullName );
|
||||||
mpw_string_pushf( out, "# Avatar: %u\n", user->avatar );
|
mpw_string_pushf( &out, "# Avatar: %u\n", user->avatar );
|
||||||
mpw_string_pushf( out, "# Identicon: %s\n", mpw_identicon_encode( user->identicon ) );
|
mpw_string_pushf( &out, "# Identicon: %s\n", mpw_identicon_encode( user->identicon ) );
|
||||||
mpw_string_pushf( out, "# Key ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
mpw_string_pushf( &out, "# Key ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
mpw_string_pushf( out, "# Algorithm: %d\n", user->algorithm );
|
mpw_string_pushf( &out, "# Algorithm: %d\n", user->algorithm );
|
||||||
mpw_string_pushf( out, "# Default Type: %d\n", user->defaultType );
|
mpw_string_pushf( &out, "# Default Type: %d\n", user->defaultType );
|
||||||
mpw_string_pushf( out, "# Passwords: %s\n", user->redacted? "PROTECTED": "VISIBLE" );
|
mpw_string_pushf( &out, "# Passwords: %s\n", user->redacted? "PROTECTED": "VISIBLE" );
|
||||||
mpw_string_pushf( out, "##\n" );
|
mpw_string_pushf( &out, "##\n" );
|
||||||
mpw_string_pushf( out, "#\n" );
|
mpw_string_pushf( &out, "#\n" );
|
||||||
mpw_string_pushf( out, "# Last Times Password Login\t Site\tSite\n" );
|
mpw_string_pushf( &out, "# Last Times Password Login\t Site\tSite\n" );
|
||||||
mpw_string_pushf( out, "# used used type name\t name\tpassword\n" );
|
mpw_string_pushf( &out, "# used used type name\t name\tpassword\n" );
|
||||||
|
|
||||||
// Sites.
|
// Sites.
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
@ -186,7 +188,8 @@ static bool mpw_marshal_write_flat(
|
|||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) {
|
if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
mpw_free_string( &out );
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
resultState = mpw_site_result( masterKey, site->siteName, site->counter,
|
resultState = mpw_site_result( masterKey, site->siteName, site->counter,
|
||||||
@ -203,7 +206,7 @@ static bool mpw_marshal_write_flat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||||
mpw_string_pushf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n",
|
mpw_string_pushf( &out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n",
|
||||||
dateString, (long)site->uses, (long)site->resultType, (long)site->algorithm, (long)site->counter,
|
dateString, (long)site->uses, (long)site->resultType, (long)site->algorithm, (long)site->counter,
|
||||||
loginState? loginState: "", site->siteName, resultState? resultState: "" );
|
loginState? loginState: "", site->siteName, resultState? resultState: "" );
|
||||||
mpw_free_strings( &resultState, &loginState, NULL );
|
mpw_free_strings( &resultState, &loginState, NULL );
|
||||||
@ -211,23 +214,23 @@ static bool mpw_marshal_write_flat(
|
|||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
|
||||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return true;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
|
|
||||||
static bool mpw_marshal_write_json(
|
static const char *mpw_marshal_write_json(
|
||||||
char **out, const MPMarshalledUser *user, MPMarshalError *error) {
|
const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->fullName || !strlen( user->fullName )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section: "export"
|
// Section: "export"
|
||||||
@ -261,7 +264,7 @@ static bool mpw_marshal_write_json(
|
|||||||
json_object_object_add( json_file, "sites", json_sites );
|
json_object_object_add( json_file, "sites", json_sites );
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
MPMarshalledSite *site = &user->sites[s];
|
MPMarshalledSite *site = &user->sites[s];
|
||||||
if (!site->name || !strlen( site->name ))
|
if (!site->siteName || !strlen( site->siteName ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const char *resultState = NULL, *loginState = NULL;
|
const char *resultState = NULL, *loginState = NULL;
|
||||||
@ -271,12 +274,12 @@ static bool mpw_marshal_write_json(
|
|||||||
if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) {
|
if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) {
|
||||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
resultState = mpw_site_result( masterKey, site->name, site->counter,
|
resultState = mpw_site_result( masterKey, site->siteName, site->counter,
|
||||||
MPKeyPurposeAuthentication, NULL, site->resultType, site->resultState, site->algorithm );
|
MPKeyPurposeAuthentication, NULL, site->resultType, site->resultState, site->algorithm );
|
||||||
loginState = mpw_site_result( masterKey, site->name, MPCounterValueInitial,
|
loginState = mpw_site_result( masterKey, site->siteName, MPCounterValueInitial,
|
||||||
MPKeyPurposeIdentification, NULL, site->loginType, site->loginState, site->algorithm );
|
MPKeyPurposeIdentification, NULL, site->loginType, site->loginState, site->algorithm );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -288,7 +291,7 @@ static bool mpw_marshal_write_json(
|
|||||||
}
|
}
|
||||||
|
|
||||||
json_object *json_site = json_object_new_object();
|
json_object *json_site = json_object_new_object();
|
||||||
json_object_object_add( json_sites, site->name, json_site );
|
json_object_object_add( json_sites, site->siteName, json_site );
|
||||||
json_object_object_add( json_site, "type", json_object_new_int( (int32_t)site->resultType ) );
|
json_object_object_add( json_site, "type", json_object_new_int( (int32_t)site->resultType ) );
|
||||||
json_object_object_add( json_site, "counter", json_object_new_int( (int32_t)site->counter ) );
|
json_object_object_add( json_site, "counter", json_object_new_int( (int32_t)site->counter ) );
|
||||||
json_object_object_add( json_site, "algorithm", json_object_new_int( (int32_t)site->algorithm ) );
|
json_object_object_add( json_site, "algorithm", json_object_new_int( (int32_t)site->algorithm ) );
|
||||||
@ -316,7 +319,7 @@ static bool mpw_marshal_write_json(
|
|||||||
|
|
||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
const char *answerState = mpw_site_result( masterKey, site->name, MPCounterValueInitial,
|
const char *answerState = mpw_site_result( masterKey, site->siteName, MPCounterValueInitial,
|
||||||
MPKeyPurposeRecovery, question->keyword, question->type, question->state, site->algorithm );
|
MPKeyPurposeRecovery, question->keyword, question->type, question->state, site->algorithm );
|
||||||
json_object_object_add( json_site_question, "answer", json_object_new_string( answerState ) );
|
json_object_object_add( json_site_question, "answer", json_object_new_string( answerState ) );
|
||||||
}
|
}
|
||||||
@ -337,33 +340,37 @@ static bool mpw_marshal_write_json(
|
|||||||
mpw_free_strings( &resultState, &loginState, NULL );
|
mpw_free_strings( &resultState, &loginState, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
mpw_string_pushf( out, "%s\n", json_object_to_json_string_ext( json_file,
|
const char *out = mpw_strdup( json_object_to_json_string_ext( json_file,
|
||||||
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_NOSLASHESCAPE ) );
|
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_NOSLASHESCAPE ) );
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
|
||||||
|
if (out)
|
||||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return true;
|
else
|
||||||
|
*error = (MPMarshalError){ .type = MPMarshalErrorFormat, .description = "Couldn't encode JSON." };
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mpw_marshal_write(
|
const char *mpw_marshal_write(
|
||||||
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error) {
|
const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error) {
|
||||||
|
|
||||||
switch (outFormat) {
|
switch (outFormat) {
|
||||||
case MPMarshalFormatNone:
|
case MPMarshalFormatNone:
|
||||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||||
return false;
|
return NULL;
|
||||||
case MPMarshalFormatFlat:
|
case MPMarshalFormatFlat:
|
||||||
return mpw_marshal_write_flat( out, user, error );
|
return mpw_marshal_write_flat( user, error );
|
||||||
#if MPW_JSON
|
#if MPW_JSON
|
||||||
case MPMarshalFormatJSON:
|
case MPMarshalFormatJSON:
|
||||||
return mpw_marshal_write_json( out, user, error );
|
return mpw_marshal_write_json( user, error );
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,10 +920,10 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (siteResultState && strlen( siteResultState ))
|
if (siteResultState && strlen( siteResultState ))
|
||||||
site->resultState = mpw_site_state( masterKey, site->name, site->counter,
|
site->resultState = mpw_site_state( masterKey, site->siteName, site->counter,
|
||||||
MPKeyPurposeAuthentication, NULL, site->resultType, siteResultState, site->algorithm );
|
MPKeyPurposeAuthentication, NULL, site->resultType, siteResultState, site->algorithm );
|
||||||
if (siteLoginState && strlen( siteLoginState ))
|
if (siteLoginState && strlen( siteLoginState ))
|
||||||
site->loginState = mpw_site_state( masterKey, site->name, MPCounterValueInitial,
|
site->loginState = mpw_site_state( masterKey, site->siteName, MPCounterValueInitial,
|
||||||
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginState, site->algorithm );
|
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginState, site->algorithm );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -938,7 +945,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
|||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (answerState && strlen( answerState ))
|
if (answerState && strlen( answerState ))
|
||||||
question->state = mpw_site_state( masterKey, site->name, MPCounterValueInitial,
|
question->state = mpw_site_state( masterKey, site->siteName, MPCounterValueInitial,
|
||||||
MPKeyPurposeRecovery, question->keyword, question->type, answerState, site->algorithm );
|
MPKeyPurposeRecovery, question->keyword, question->type, answerState, site->algorithm );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -121,15 +121,16 @@ typedef struct MPMarshalInfo {
|
|||||||
|
|
||||||
//// Marshalling.
|
//// Marshalling.
|
||||||
|
|
||||||
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */
|
/** Write the user and all associated data out using the given marshalling format.
|
||||||
bool mpw_marshal_write(
|
* @return A string (allocated), or NULL if the format is unrecognized, does not support marshalling or a format error occurred. */
|
||||||
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error);
|
const char *mpw_marshal_write(
|
||||||
|
const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error);
|
||||||
/** Try to read metadata on the sites in the input buffer.
|
/** Try to read metadata on the sites in the input buffer.
|
||||||
* @return A metadata object (allocated), or NULL if the object could not be allocated. */
|
* @return A metadata object (allocated), or NULL if the object could not be allocated or a format error occurred. */
|
||||||
MPMarshalInfo *mpw_marshal_read_info(
|
MPMarshalInfo *mpw_marshal_read_info(
|
||||||
const char *in);
|
const char *in);
|
||||||
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format.
|
/** 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 an error occurred. */
|
* @return A user object (allocated), or NULL if the format provides no marshalling or a format error occurred. */
|
||||||
MPMarshalledUser *mpw_marshal_read(
|
MPMarshalledUser *mpw_marshal_read(
|
||||||
const char *in, const MPMarshalFormat inFormat, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error);
|
const char *in, const MPMarshalFormat inFormat, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error);
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
const size_t MPMasterKeySize = 64;
|
const size_t MPMasterKeySize = 64;
|
||||||
const size_t MPSiteKeySize = 256 / 8; // Size of HMAC-SHA-256
|
const size_t MPSiteKeySize = 256 / 8; // Size of HMAC-SHA-256
|
||||||
const MPIdenticon MPIdenticonUnset = (MPIdenticon){
|
const MPIdenticon MPIdenticonUnset = {
|
||||||
.leftArm = "",
|
.leftArm = "",
|
||||||
.body = "",
|
.body = "",
|
||||||
.rightArm = "",
|
.rightArm = "",
|
||||||
|
Loading…
Reference in New Issue
Block a user