2
0

Refactor in preparation of reading ext data prior to auth.

This commit is contained in:
Maarten Billemont 2019-09-30 13:08:04 -04:00
parent a2b1f22b53
commit 7fd0172815
6 changed files with 180 additions and 174 deletions

View File

@ -565,7 +565,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
saveInContext:(NSManagedObjectContext *)context {
// Read metadata for the import file.
MPMarshalInfo *info = mpw_marshal_read_info( importData.UTF8String );
MPMarshalledInfo *info = mpw_marshal_read_info( importData.UTF8String );
if (info->format == MPMarshalFormatNone)
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
@"type" : @(MPMarshalErrorFormat),

View File

@ -489,7 +489,7 @@ void cli_user(Arguments *args, Operation *operation) {
mpw_free_string( &operation->sitesPath );
mpw_marshal_file_free( &operation->file );
operation->file = mpw_marshal_file( NULL, mpw_marshal_user(
operation->fullName, cli_masterKeyProvider_op( operation ), MPAlgorithmVersionCurrent ), NULL, NULL );
operation->fullName, cli_masterKeyProvider_op( operation ), MPAlgorithmVersionCurrent ), NULL );
}
else {

View File

@ -21,6 +21,7 @@
MP_LIBS_BEGIN
#include <string.h>
#include <math.h>
MP_LIBS_END
char *mpw_get_token(const char **in, const char *eol, const char *delim) {
@ -57,6 +58,22 @@ time_t mpw_timegm(const char *time) {
return ERR;
}
bool mpw_update_master_key(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, const MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword) {
if (masterKey && (!*masterKey || *masterKeyAlgorithm != targetKeyAlgorithm)) {
mpw_free( masterKey, MPMasterKeySize );
*masterKeyAlgorithm = targetKeyAlgorithm;
*masterKey = mpw_master_key( fullName, masterPassword, *masterKeyAlgorithm );
if (!*masterKey) {
err( "Couldn't derive master key for user %s, algorithm %d.", fullName, *masterKeyAlgorithm );
return false;
}
}
return true;
}
#if MPW_JSON
json_object *mpw_get_json_object(
@ -105,20 +122,110 @@ bool mpw_get_json_boolean(
return json_object_get_boolean( json_value ) == true;
}
#endif
void mpw_set_json_data(
MPMarshalledData *data, json_object *obj) {
bool mpw_update_master_key(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, const MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword) {
if (!data)
return;
if (masterKey && (!*masterKey || *masterKeyAlgorithm != targetKeyAlgorithm)) {
mpw_free( masterKey, MPMasterKeySize );
*masterKeyAlgorithm = targetKeyAlgorithm;
*masterKey = mpw_master_key( fullName, masterPassword, *masterKeyAlgorithm );
if (!*masterKey) {
err( "Couldn't derive master key for user %s, algorithm %d.", fullName, *masterKeyAlgorithm );
return false;
json_type type = json_object_get_type( obj );
data->is_null = type == json_type_null;
data->is_bool = type == json_type_boolean;
if (type == json_type_boolean)
data->num_value = json_object_get_boolean( obj );
else if (type == json_type_double)
data->num_value = json_object_get_double( obj );
else if (type == json_type_int)
data->num_value = json_object_get_int64( obj );
else
data->num_value = NAN;
const char *str = NULL;
if (type == json_type_string || !isnan( data->num_value ))
str = json_object_get_string( obj );
if (!str || !data->str_value || strcmp( str, data->str_value ) != OK) {
mpw_free_string( &data->str_value );
data->str_value = mpw_strdup( str );
}
// Clean up children
MPMarshalledData *newChildren = NULL;
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->obj_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->obj_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 )) {
--newChildrenCount;
continue;
}
child->arr_index = newChildrenCount - 1;
newChildren[child->arr_index] = *child;
}
}
}
if (newChildren) {
mpw_free( &data->children, sizeof( MPMarshalledData ) * data->children_count );
data->children = newChildren;
data->children_count = newChildrenCount;
}
// Object
if (type == json_type_object) {
json_object_iter entry;
json_object_object_foreachC( obj, entry ) {
MPMarshalledData *child = NULL;
// Find existing child.
for (size_t c = 0; c < data->children_count; ++c)
if (data->children[c].obj_key == entry.key ||
(data->children[c].obj_key && entry.key && strcmp( data->children[c].obj_key, entry.key ) == OK)) {
child = &data->children[c];
break;
}
// Create new child.
if (!child) {
if (!mpw_realloc( &data->children, NULL, sizeof( MPMarshalledData ) * ++data->children_count )) {
--data->children_count;
continue;
}
*(child = &data->children[data->children_count - 1]) = (MPMarshalledData){ .obj_key = mpw_strdup( entry.key ) };
}
mpw_set_json_data( child, entry.val );
}
}
return true;
// Array
if (type == json_type_array) {
for (size_t index = 0; index < json_object_array_length( obj ); ++index) {
MPMarshalledData *child = NULL;
if (index < data->children_count)
child = &data->children[index];
else {
if (!mpw_realloc( &data->children, NULL, sizeof( MPMarshalledData ) * ++data->children_count )) {
--data->children_count;
continue;
}
*(child = &data->children[data->children_count - 1]) = (MPMarshalledData){ .arr_index = index };
}
mpw_set_json_data( child, json_object_array_get_idx( obj, index ) );
}
}
}
#endif

View File

@ -20,6 +20,7 @@
#define _MPW_MARSHAL_UTIL_H
#include "mpw-algorithm.h"
#include "mpw-marshal.h"
MP_LIBS_BEGIN
#include <time.h>
@ -40,6 +41,17 @@ char *mpw_get_token(
time_t mpw_timegm(
const char *time);
/// mpw.
/** Calculate a master key if the target master key algorithm is different from the given master key algorithm.
* @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, const MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword);
/// JSON parsing.
#if MPW_JSON
@ -64,15 +76,11 @@ int64_t mpw_get_json_int(
* @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, const bool defaultValue);
/** Translate a JSON object tree into a source-agnostic data object.
* @param data A Master Password data object or NULL.
* @param obj A JSON object tree or NULL. */
void mpw_set_json_data(
MPMarshalledData *data, json_object *obj);
#endif
/// mpw.
/** Calculate a master key if the target master key algorithm is different from the given master key algorithm.
* @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, const MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword);
#endif // _MPW_MARSHAL_UTIL_H

View File

@ -106,7 +106,7 @@ MPMarshalledQuestion *mpw_marshal_question(
}
MPMarshalledFile *mpw_marshal_file(
MPMarshalledFile *file, MPMarshalledUser *user, MPMarshalledData *data, MPMarshalInfo *info) {
MPMarshalledFile *file, MPMarshalledUser *user, MPMarshalledData *data, MPMarshalledInfo *info) {
if (!file) {
if (!(file = malloc( sizeof( MPMarshalledFile ) )))
@ -132,13 +132,13 @@ MPMarshalledFile *mpw_marshal_file(
}
void mpw_marshal_info_free(
MPMarshalInfo **info) {
MPMarshalledInfo **info) {
if (!info || !*info)
return;
mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
mpw_free( info, sizeof( MPMarshalInfo ) );
mpw_free( info, sizeof( MPMarshalledInfo ) );
}
void mpw_marshal_user_free(
@ -171,7 +171,7 @@ void mpw_marshal_data_free(
return;
mpw_marshal_data_set_null( *data, NULL );
mpw_free_string( &(*data)->key );
mpw_free_string( &(*data)->obj_key );
mpw_free( data, sizeof( MPMarshalledData ) );
}
@ -204,7 +204,7 @@ MPMarshalledData *mpw_marshal_data_vget(
child = NULL;
for (size_t c = 0; c < parent->children_count; ++c) {
const char *key = parent->children[c].key;
const char *key = parent->children[c].obj_key;
if (key && strcmp( node, key ) == OK) {
child = &parent->children[c];
break;
@ -216,7 +216,7 @@ MPMarshalledData *mpw_marshal_data_vget(
--parent->children_count;
break;
}
*(child = &parent->children[parent->children_count - 1]) = (MPMarshalledData){ .key = mpw_strdup( node ) };
*(child = &parent->children[parent->children_count - 1]) = (MPMarshalledData){ .obj_key = mpw_strdup( node ) };
mpw_marshal_data_set_null( child, NULL );
child->is_null = false;
}
@ -244,7 +244,7 @@ const MPMarshalledData *mpw_marshal_data_vfind(
child = NULL;
for (size_t c = 0; c < parent->children_count; ++c) {
const char *key = parent->children[c].key;
const char *key = parent->children[c].obj_key;
if (key && strcmp( node, key ) == OK) {
child = &parent->children[c];
break;
@ -297,7 +297,7 @@ bool mpw_marshal_data_vset_null(
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_string( &child->children[c].obj_key );
}
mpw_free( &child->children, sizeof( MPMarshalledData ) * child->children_count );
child->children_count = 0;
@ -447,7 +447,7 @@ bool mpw_marshal_data_set_str(
}
static const char *mpw_marshal_write_flat(
const MPMarshalledFile *file, MPMarshalError *error) {
MPMarshalledFile *file, MPMarshalError *error) {
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
MPMarshalledUser *user = file->user;
@ -557,14 +557,14 @@ static json_object *mpw_get_json_data(
for (size_t c = 0; c < data->children_count; ++c) {
MPMarshalledData *child = &data->children[c];
if (!obj) {
if (child->key)
if (child->obj_key)
obj = json_object_new_object();
else
obj = json_object_new_array();
}
if (child->key)
json_object_object_add( obj, child->key, mpw_get_json_data( child ) );
if (child->obj_key)
json_object_object_add( obj, child->obj_key, mpw_get_json_data( child ) );
else
json_object_array_add( obj, mpw_get_json_data( child ) );
}
@ -573,7 +573,7 @@ static json_object *mpw_get_json_data(
}
static const char *mpw_marshal_write_json(
const MPMarshalledFile *file, MPMarshalError *error) {
MPMarshalledFile *file, MPMarshalError *error) {
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
MPMarshalledUser *user = file->user;
@ -694,6 +694,9 @@ static const char *mpw_marshal_write_json(
mpw_free_strings( &resultState, &loginState, NULL );
}
if (!file->data)
file->data = mpw_marshal_data_new();
mpw_set_json_data( file->data, 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_object_put( json_file );
@ -716,7 +719,7 @@ const char *mpw_marshal_write(
*error = (MPMarshalError){ .type = MPMarshalErrorMissing, "No file to marshal." };
return NULL;
}
if (file->data && file->data->key) {
if (file->data && file->data->obj_key) {
*error = (MPMarshalError){ .type = MPMarshalErrorInternal, "Illegal file data." };
ftl( "Unexpected non-root file data." );
return NULL;
@ -745,7 +748,7 @@ const char *mpw_marshal_write(
}
static void mpw_marshal_read_flat_info(
const char *in, MPMarshalInfo *info) {
const char *in, MPMarshalledInfo *info) {
info->algorithm = MPAlgorithmVersionCurrent;
@ -1082,6 +1085,7 @@ static MPMarshalledFile *mpw_marshal_read_flat(
mpw_free_strings( &fullName, &keyID, NULL );
mpw_free( &masterKey, MPMasterKeySize );
// TODO: serialize data structure for this file.
MPMarshalledFile *file = mpw_marshal_file( NULL, user, NULL, NULL );
if (!file) {
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new marshal file." };
@ -1095,114 +1099,8 @@ static MPMarshalledFile *mpw_marshal_read_flat(
#if MPW_JSON
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;
if (type == json_type_boolean)
data->num_value = json_object_get_boolean( obj );
else if (type == json_type_double)
data->num_value = json_object_get_double( obj );
else if (type == json_type_int)
data->num_value = json_object_get_int64( obj );
else
data->num_value = NAN;
const char *str = NULL;
if (type == json_type_string || !isnan( data->num_value ))
str = json_object_get_string( obj );
if (!str || !data->str_value || strcmp( str, data->str_value ) != OK) {
mpw_free_string( &data->str_value );
data->str_value = mpw_strdup( str );
}
// Clean up children
MPMarshalledData *newChildren = NULL;
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)) {
// 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 )) {
--newChildrenCount;
continue;
}
child->index = newChildrenCount - 1;
newChildren[child->index] = *child;
}
}
}
if (newChildren) {
mpw_free( &data->children, sizeof( MPMarshalledData ) * data->children_count );
data->children = newChildren;
data->children_count = newChildrenCount;
}
// Object
if (type == json_type_object) {
json_object_iter entry;
json_object_object_foreachC( obj, entry ) {
MPMarshalledData *child = NULL;
// 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)) {
child = &data->children[c];
break;
}
// Create new child.
if (!child) {
if (!mpw_realloc( &data->children, NULL, sizeof( MPMarshalledData ) * ++data->children_count )) {
--data->children_count;
continue;
}
*(child = &data->children[data->children_count - 1]) = (MPMarshalledData){ .key = mpw_strdup( entry.key ) };
}
mpw_set_json_data( child, entry.val );
}
}
// Array
if (type == json_type_array) {
for (size_t index = 0; index < json_object_array_length( obj ); ++index) {
MPMarshalledData *child = NULL;
if (index < data->children_count)
child = &data->children[index];
else {
if (!mpw_realloc( &data->children, NULL, sizeof( MPMarshalledData ) * ++data->children_count )) {
--data->children_count;
continue;
}
*(child = &data->children[data->children_count - 1]) = (MPMarshalledData){ .index = index };
}
mpw_set_json_data( child, json_object_array_get_idx( obj, index ) );
}
}
}
static void mpw_marshal_read_json_info(
const char *in, MPMarshalInfo *info) {
const char *in, MPMarshalledInfo *info) {
// Parse JSON.
enum json_tokener_error json_error = json_tokener_success;
@ -1457,14 +1355,14 @@ static MPMarshalledFile *mpw_marshal_read_json(
#endif
MPMarshalInfo *mpw_marshal_read_info(
MPMarshalledInfo *mpw_marshal_read_info(
const char *in) {
MPMarshalInfo *info = malloc( sizeof( MPMarshalInfo ) );
MPMarshalledInfo *info = malloc( sizeof( MPMarshalledInfo ) );
if (!info)
return NULL;
*info = (MPMarshalInfo){ .format = MPMarshalFormatNone, .identicon = MPIdenticonUnset };
*info = (MPMarshalledInfo){ .format = MPMarshalFormatNone, .identicon = MPIdenticonUnset };
if (in && strlen( in )) {
if (in[0] == '#') {
info->format = MPMarshalFormatFlat;
@ -1489,7 +1387,7 @@ MPMarshalInfo *mpw_marshal_read_info(
MPMarshalledFile *mpw_marshal_read(
const char *in, const MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) {
MPMarshalInfo *info = mpw_marshal_read_info( in );
MPMarshalledInfo *info = mpw_marshal_read_info( in );
if (!info)
return NULL;

View File

@ -69,7 +69,20 @@ typedef struct MPMarshalError {
const char *message;
} MPMarshalError;
typedef struct MPMarshalInfo {
typedef struct MPMarshalledData {
const char *obj_key;
size_t arr_index;
bool is_null;
bool is_bool;
const char *str_value;
double num_value;
size_t children_count;
struct MPMarshalledData *children;
} MPMarshalledData;
typedef struct MPMarshalledInfo {
MPMarshalFormat format;
time_t exportDate;
bool redacted;
@ -80,7 +93,7 @@ typedef struct MPMarshalInfo {
MPIdenticon identicon;
const char *keyID;
time_t lastUsed;
} MPMarshalInfo;
} MPMarshalledInfo;
typedef struct MPMarshalledQuestion {
const char *keyword;
@ -123,28 +136,8 @@ typedef struct MPMarshalledUser {
MPMarshalledSite *sites;
} MPMarshalledUser;
typedef struct MPMarshalledData {
// If data is held in a parent object.
const char *key;
// If data is held in a parent array.
size_t index;
// If data is a null.
bool is_null;
// If data is a boolean.
bool is_bool;
// If data is a string.
const char *str_value;
// If data is a number.
double num_value;
// If data is an object or array.
size_t children_count;
struct MPMarshalledData *children;
} MPMarshalledData;
typedef struct MPMarshalledFile {
MPMarshalInfo *info;
MPMarshalledInfo *info;
MPMarshalledUser *user;
MPMarshalledData *data;
} MPMarshalledFile;
@ -157,7 +150,7 @@ const char *mpw_marshal_write(
const MPMarshalFormat outFormat, MPMarshalledFile *file, MPMarshalError *error);
/** Best effort parse of metadata on the sites in the input buffer. Fields that could not be parsed remain at their type's initial value.
* @return A metadata object (allocated); NULL if the object could not be allocated or the format was not understood. */
MPMarshalInfo *mpw_marshal_read_info(
MPMarshalledInfo *mpw_marshal_read_info(
const char *in);
/** 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. */
@ -182,13 +175,13 @@ MPMarshalledQuestion *mpw_marshal_question(
/** Create or update a marshal file descriptor.
* @return The given file or new (allocated) if file is NULL; or NULL if the user is missing or the file couldn't be allocated. */
MPMarshalledFile *mpw_marshal_file(
MPMarshalledFile *const file, MPMarshalledUser *user, MPMarshalledData *data, MPMarshalInfo *info);
MPMarshalledFile *const file, MPMarshalledUser *user, MPMarshalledData *data, MPMarshalledInfo *info);
//// Disposing.
/** Free the given user object and all associated data. */
void mpw_marshal_info_free(
MPMarshalInfo **info);
MPMarshalledInfo **info);
void mpw_marshal_user_free(
MPMarshalledUser **user);
void mpw_marshal_data_free(