Allow marshalling without masterKey and record keyID in user.
This commit is contained in:
parent
1b90b3deea
commit
2fdd9d2ca1
@ -526,23 +526,24 @@ void cli_user(Arguments *args, Operation *operation) {
|
||||
|
||||
// Incorrect master password.
|
||||
if (marshalError.type == MPMarshalErrorMasterPassword) {
|
||||
ftl( "Incorrect master password according to configuration:\n %s: %s", operation->sitesPath, marshalError.description );
|
||||
ftl( "Incorrect master password according to configuration:\n %s: %s", operation->sitesPath, marshalError.message );
|
||||
cli_free( args, operation );
|
||||
exit( EX_DATAERR );
|
||||
}
|
||||
|
||||
// Any other parse error.
|
||||
if (!operation->user || marshalError.type != MPMarshalSuccess) {
|
||||
err( "Couldn't parse configuration file:\n %s: %s", operation->sitesPath, marshalError.description );
|
||||
err( "Couldn't parse configuration file:\n %s: %s", operation->sitesPath, marshalError.message );
|
||||
cli_free( args, operation );
|
||||
exit( EX_DATAERR );
|
||||
}
|
||||
}
|
||||
|
||||
// If no user from mpsites, create a new one.
|
||||
if (!operation->user)
|
||||
if (!operation->user) {
|
||||
operation->user = mpw_marshal_user(
|
||||
operation->fullName, cli_masterKeyProvider_op( operation ), MPAlgorithmVersionCurrent );
|
||||
}
|
||||
}
|
||||
|
||||
void cli_site(Arguments *args, Operation *operation) {
|
||||
@ -726,6 +727,14 @@ void cli_mpw(Arguments *args, Operation *operation) {
|
||||
cli_free( args, operation );
|
||||
exit( EX_SOFTWARE );
|
||||
}
|
||||
MPKeyID keyID = mpw_id_buf( masterKey, MPMasterKeySize );
|
||||
if (!operation->user->keyID)
|
||||
operation->user->keyID = mpw_strdup( keyID );
|
||||
else if (!mpw_id_buf_equals( keyID, operation->user->keyID )) {
|
||||
ftl( "Master key mismatch." );
|
||||
cli_free( args, operation );
|
||||
exit( EX_SOFTWARE );
|
||||
}
|
||||
|
||||
// Update state from resultParam if stateful.
|
||||
if (operation->resultParam && operation->resultType & MPResultTypeClassStateful) {
|
||||
@ -811,7 +820,7 @@ void cli_save(Arguments *args, Operation *operation) {
|
||||
MPMarshalError marshalError = { .type = MPMarshalSuccess };
|
||||
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.message );
|
||||
|
||||
else if (fwrite( buf, sizeof( char ), strlen( buf ), sitesFile ) != strlen( buf ))
|
||||
wrn( "Error while writing updated configuration file:\n %s: %d", operation->sitesPath, ferror( sitesFile ) );
|
||||
|
@ -42,6 +42,7 @@ MPMarshalledUser *mpw_marshal_user(
|
||||
.avatar = 0,
|
||||
.fullName = mpw_strdup( fullName ),
|
||||
.identicon = MPIdenticonUnset,
|
||||
.keyID = NULL,
|
||||
.defaultType = MPResultTypeDefault,
|
||||
.lastUsed = 0,
|
||||
|
||||
@ -118,6 +119,7 @@ bool mpw_marshal_free(
|
||||
|
||||
bool success = true;
|
||||
success &= mpw_free_strings( &(*user)->fullName, NULL );
|
||||
success &= mpw_free_strings( &(*user)->keyID, NULL );
|
||||
|
||||
for (size_t s = 0; s < (*user)->sites_count; ++s) {
|
||||
MPMarshalledSite *site = &(*user)->sites[s];
|
||||
@ -147,10 +149,6 @@ static const char *mpw_marshal_write_flat(
|
||||
MPMasterKey masterKey = NULL;
|
||||
if (user->masterKeyProvider)
|
||||
masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
||||
if (!masterKey) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *out = NULL;
|
||||
mpw_string_pushf( &out, "# Master Password site export\n" );
|
||||
@ -170,9 +168,12 @@ static const char *mpw_marshal_write_flat(
|
||||
mpw_string_pushf( &out, "# User Name: %s\n", user->fullName );
|
||||
mpw_string_pushf( &out, "# Full Name: %s\n", user->fullName );
|
||||
mpw_string_pushf( &out, "# Avatar: %u\n", user->avatar );
|
||||
if (user->identicon.color != MPIdenticonColorUnset)
|
||||
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 ) );
|
||||
if (user->keyID)
|
||||
mpw_string_pushf( &out, "# Key ID: %s\n", user->keyID );
|
||||
mpw_string_pushf( &out, "# Algorithm: %d\n", user->algorithm );
|
||||
if (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, "##\n" );
|
||||
@ -234,10 +235,6 @@ static const char *mpw_marshal_write_json(
|
||||
MPMasterKey masterKey = NULL;
|
||||
if (user->masterKeyProvider)
|
||||
masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
|
||||
if (!masterKey) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Section: "export"
|
||||
json_object *json_file = json_object_new_object();
|
||||
@ -257,12 +254,14 @@ static const char *mpw_marshal_write_json(
|
||||
json_object_object_add( json_user, "avatar", json_object_new_int( (int32_t)user->avatar ) );
|
||||
json_object_object_add( json_user, "full_name", json_object_new_string( user->fullName ) );
|
||||
|
||||
if (user->identicon.color != MPIdenticonColorUnset)
|
||||
json_object_object_add( json_user, "identicon", json_object_new_string( mpw_identicon_encode( user->identicon ) ) );
|
||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &user->lastUsed ) ))
|
||||
json_object_object_add( json_user, "last_used", json_object_new_string( dateString ) );
|
||||
json_object_object_add( json_user, "key_id", json_object_new_string( mpw_id_buf( masterKey, MPMasterKeySize ) ) );
|
||||
|
||||
if (user->keyID)
|
||||
json_object_object_add( json_user, "key_id", json_object_new_string( user->keyID ) );
|
||||
json_object_object_add( json_user, "algorithm", json_object_new_int( (int32_t)user->algorithm ) );
|
||||
if (user->defaultType)
|
||||
json_object_object_add( json_user, "default_type", json_object_new_int( (int32_t)user->defaultType ) );
|
||||
|
||||
// Section "sites"
|
||||
@ -354,7 +353,7 @@ static const char *mpw_marshal_write_json(
|
||||
if (out)
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
else
|
||||
*error = (MPMarshalError){ .type = MPMarshalErrorFormat, .description = "Couldn't encode JSON." };
|
||||
*error = (MPMarshalError){ .type = MPMarshalErrorFormat, .message = "Couldn't encode JSON." };
|
||||
|
||||
return out;
|
||||
}
|
||||
@ -437,7 +436,7 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||
if (!in || !strlen( in )) {
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "No input data." );
|
||||
error->message = mpw_str( "No input data." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -478,23 +477,27 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
mpw_marshal_free( &user );
|
||||
return NULL;
|
||||
}
|
||||
if (masterKey && keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
|
||||
if (keyID && masterKey && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master key doesn't match key ID." };
|
||||
mpw_free_strings( &fullName, &keyID, NULL );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
return NULL;
|
||||
}
|
||||
if (!user && !(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) {
|
||||
|
||||
mpw_marshal_free( &user );
|
||||
if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||
mpw_free_strings( &fullName, &keyID, NULL );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user->redacted = importRedacted;
|
||||
user->avatar = avatar;
|
||||
user->identicon = identicon;
|
||||
user->keyID = mpw_strdup( keyID );
|
||||
user->defaultType = defaultType;
|
||||
user->lastUsed = exportDate;
|
||||
continue;
|
||||
@ -505,7 +508,7 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
if (!headerName || !headerValue) {
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
error->message = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
mpw_free_strings( &headerName, &headerValue, NULL );
|
||||
mpw_free_strings( &fullName, &keyID, NULL );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
@ -697,7 +700,7 @@ static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
}
|
||||
else {
|
||||
error->type = MPMarshalErrorMissing;
|
||||
error->description = mpw_str(
|
||||
error->message = mpw_str(
|
||||
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
|
||||
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginState, siteName );
|
||||
mpw_free_strings( &str_lastUsed, &str_uses, &str_type, &str_algorithm, &str_counter, NULL );
|
||||
@ -753,7 +756,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||
if (!in || !strlen( in )) {
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "No input data." );
|
||||
error->message = mpw_str( "No input data." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -766,16 +769,10 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse import data.
|
||||
MPMasterKey masterKey = NULL;
|
||||
MPMarshalledUser *user = NULL;
|
||||
|
||||
// Section: "export"
|
||||
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
|
||||
if (fileFormat < 1) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
@ -785,8 +782,6 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
int64_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
@ -795,8 +790,6 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
const char *fullName = mpw_get_json_string( json_file, "user.full_name", NULL );
|
||||
if (!fullName || !strlen( fullName )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
@ -805,8 +798,6 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
|
||||
if (!mpw_type_short_name( defaultType )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
@ -814,25 +805,25 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
time_t lastUsed = mpw_timegm( str_lastUsed );
|
||||
if (!lastUsed) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MPMasterKey masterKey = NULL;
|
||||
if (masterKeyProvider && !(masterKey = masterKeyProvider( algorithm, fullName ))) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
if (masterKey && keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
|
||||
if (keyID && masterKey && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master key doesn't match key ID." };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
mpw_marshal_free( &user );
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MPMarshalledUser *user = NULL;
|
||||
if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
@ -840,9 +831,11 @@ static MPMarshalledUser *mpw_marshal_read_json(
|
||||
json_object_put( json_file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user->redacted = fileRedacted;
|
||||
user->avatar = avatar;
|
||||
user->identicon = identicon;
|
||||
user->keyID = mpw_strdup( keyID );
|
||||
user->defaultType = defaultType;
|
||||
user->lastUsed = lastUsed;
|
||||
|
||||
|
@ -65,7 +65,7 @@ typedef MPMasterKey (*MPMasterKeyProvider)(MPAlgorithmVersion algorithm, const c
|
||||
|
||||
typedef struct MPMarshalError {
|
||||
MPMarshalErrorType type;
|
||||
const char *description;
|
||||
const char *message;
|
||||
} MPMarshalError;
|
||||
|
||||
typedef struct MPMarshalledQuestion {
|
||||
@ -101,6 +101,7 @@ typedef struct MPMarshalledUser {
|
||||
unsigned int avatar;
|
||||
const char *fullName;
|
||||
MPIdenticon identicon;
|
||||
const char *keyID;
|
||||
MPResultType defaultType;
|
||||
time_t lastUsed;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user