/// <summary> /// Apply the configuration set in the constructor to the JObject set in the constructor. /// </summary> /// <see cref="Anonymizer(AnonymizerConfiguration)" /> /// <returns>A modified JObject with the configuration applied.</returns> public T ApplyOperations <T>(BusinessObject bo) { if (bo == null) { throw new ArgumentNullException(nameof(bo)); } var mapping = _configuration.Operations; var result = bo.DeepClone(); foreach (var dataCategory in mapping.Keys) { var approach = mapping[dataCategory]; var affectedProps = bo.GetType().GetProperties() .Where(p => p.GetCustomAttributes(typeof(DataCategoryAttribute), false).Length > 0) .OrderBy(ap => ap.GetCustomAttribute <JsonPropertyAttribute>()?.Order) .ToArray(); foreach (var affectedProp in affectedProps) { if (!affectedProp.IsAnonymizerRelevant(approach, dataCategory)) { continue; } switch (approach) { case AnonymizerApproach.HASH: try { var affectedFieldValue = affectedProp.GetValue(result); HashObject(ref affectedFieldValue, dataCategory); affectedProp.SetValue(result, affectedFieldValue); } catch (RuntimeBinderException e) { _logger.LogWarning( $"Catched RuntimeBinderException in Object {bo.GetBoTyp()}. Probably due to trying to get the type of a null object BO: {e.Message}"); } break; case AnonymizerApproach.DELETE: /* We'd like to set the value to null, but the business object might not allow * it resulting in a JsonSerializationException. That's why we first check, * whether the field is actually required. If it has to be non-null we set the * annotated default value, otherwise we can safely set null. */ var isRequired = false; Attribute defaultValueAttribute = null; var jsonPropertyAttribute = affectedProp.GetCustomAttributes() .FirstOrDefault(a => a is JsonPropertyAttribute); if (jsonPropertyAttribute != null) { var jpa = (JsonPropertyAttribute)jsonPropertyAttribute; if (jpa.Required == Required.Always) { isRequired = true; defaultValueAttribute = affectedProp.GetCustomAttributes() .FirstOrDefault(a => a.GetType() == typeof(DefaultValueAttribute)); } } if (isRequired && defaultValueAttribute != null) { var dva = (DefaultValueAttribute)defaultValueAttribute; affectedProp.SetValue(result, dva.Value); } else if (bo.GetType().IsSubclassOf(typeof(BusinessObject))) { // e.g. 1*Energiemenge (mappedObject)---> n*Verbrauch (boSubObject) var boSubObject = affectedProp.GetValue(bo); if (boSubObject != null) { try { if (boSubObject.GetType().IsGenericType&& boSubObject.GetType().GetGenericTypeDefinition() == typeof(List <>)) { var listElementType = boSubObject.GetType().GetGenericArguments()[0]; var listType = typeof(List <>).MakeGenericType(listElementType); var newEmptyList = Activator.CreateInstance(listType); boSubObject = newEmptyList; } else { boSubObject = null; } } catch (RuntimeBinderException e) { _logger.LogError($"Couldn't null BO field!: {e.Message}"); } affectedProp.SetValue(result, boSubObject); } } else { // strings, integers, elementary affectedProp.SetValue(result, null); } break; case AnonymizerApproach.ENCRYPT: if (PublicKeyX509 == null) { throw new ArgumentNullException(nameof(PublicKeyX509), "To use the encryption feature you have to provide a public X509 certificate using the SetPublicKey method."); } using (var xasyncenc = new X509AsymmetricEncrypter(PublicKeyX509)) { if (affectedProp.GetValue(bo) is string) { if (affectedProp.GetValue(bo) != null) { affectedProp.SetValue(result, xasyncenc.Encrypt(affectedProp.GetValue(bo).ToString())); } } else if (affectedProp.GetValue(bo).GetType().IsSubclassOf(typeof(COM.COM))) { var comObject = affectedProp.GetValue(bo); dynamic comFields = comObject.GetType().GetProperties(); foreach (var comField in comFields) { try { comField.SetValue(comObject, xasyncenc.Encrypt(comField.GetValue(comObject)).ToString()); } catch (ArgumentException e) { // das sollte passieren, wenn das Argument kein String is und deswegen das encrypten kein sinn macht _logger.LogError($"Couldn't encrypt COM field!: {e.Message}"); } } catch (Exception f) { // das sollte passieren, wenn das Argument ein enum _logger.LogError($"Couldn't encrypt COM field!: {f.Message}"); } affectedProp.SetValue(result, comObject); }
/// <summary> /// Apply the configuration set in the constructor to the JObject set in the constructor. /// </summary> /// <see cref="Anonymizer(AnonymizerConfiguration)"/> /// <returns>A modified JObject with the configuration applied.</returns> public T ApplyOperations <T>(BusinessObject bo) { if (bo == null) { throw new ArgumentNullException(nameof(bo)); } Dictionary <DataCategory, AnonymizerApproach> mapping = configuration.operations; BusinessObject result = bo.DeepClone <BusinessObject>(); foreach (DataCategory dataCategory in mapping.Keys) { AnonymizerApproach approach = mapping[dataCategory]; PropertyInfo[] affectedProps = bo.GetType().GetProperties() .Where(p => p.GetCustomAttributes(typeof(DataCategoryAttribute), false).Length > 0) .OrderBy(ap => ap.GetCustomAttribute <JsonPropertyAttribute>()?.Order) .ToArray <PropertyInfo>(); foreach (PropertyInfo affectedProp in affectedProps) { if (!affectedProp.IsAnonymizerRelevant(approach, dataCategory)) { continue; } switch (approach) { case AnonymizerApproach.HASH: try { object affectedFieldValue = affectedProp.GetValue(result); HashObject(ref affectedFieldValue, dataCategory); affectedProp.SetValue(result, affectedFieldValue); } catch (RuntimeBinderException e) { _logger.LogWarning($"Catched RuntimeBinderException in Object {bo.GetBoTyp()}. Probably due to trying to get the type of a null object BO: {e.Message}"); } break; case AnonymizerApproach.DELETE: /* We'd like to set the value to null, but the business object might not allow * it resulting in a JsonSerializationException. That's why we first check, * whether the field is actually required. If it has to be non-null we set the * annotated default value, otherwise we can safely set null. */ bool isRequired = false; Attribute defaultValueAttribute = null; Attribute jsonPropertyAttribute = affectedProp.GetCustomAttributes().Where(a => a.GetType() == typeof(JsonPropertyAttribute)).FirstOrDefault(); if (jsonPropertyAttribute != null) { JsonPropertyAttribute jpa = (JsonPropertyAttribute)jsonPropertyAttribute; if (jpa.Required == Required.Always) { isRequired = true; defaultValueAttribute = affectedProp.GetCustomAttributes().Where(a => a.GetType() == typeof(DefaultValueAttribute)).FirstOrDefault(); } } if (isRequired && defaultValueAttribute != null) { DefaultValueAttribute dva = (DefaultValueAttribute)defaultValueAttribute; affectedProp.SetValue(result, dva.Value); } else if (bo.GetType().IsSubclassOf(typeof(BO4E.BO.BusinessObject))) { // e.g. 1*Energiemenge (mappedObject)---> n*Verbrauch (boSubObject) var boSubObject = affectedProp.GetValue(bo); if (boSubObject != null) { try { if (boSubObject.GetType().IsGenericType&& boSubObject.GetType().GetGenericTypeDefinition() == typeof(List <>)) { Type listElementType = boSubObject.GetType().GetGenericArguments()[0]; Type listType = typeof(List <>).MakeGenericType(listElementType); object newEmptyList = Activator.CreateInstance(listType); boSubObject = newEmptyList; } else { boSubObject = null; } } catch (RuntimeBinderException e) { _logger.LogError($"Couldn't null BO field!: {e.Message}"); } affectedProp.SetValue(result, boSubObject); } } else { // strings, integers, elementary affectedProp.SetValue(result, null); } break; case AnonymizerApproach.ENCRYPT: if (this.publicKeyX509 == null) { throw new ArgumentNullException("To use the encryption feature you have to provide a public X509 certificate using the SetPublicKey method."); } using (X509AsymmetricEncrypter xasyncenc = new X509AsymmetricEncrypter(this.publicKeyX509)) { if (affectedProp.GetValue(bo).GetType() == typeof(string)) { if (affectedProp.GetValue(bo) != null) { affectedProp.SetValue(result, xasyncenc.Encrypt(affectedProp.GetValue(bo).ToString())); } } else if (affectedProp.GetValue(bo).GetType().IsSubclassOf(typeof(BO4E.COM.COM))) { var comObject = affectedProp.GetValue(bo); dynamic comFields = comObject.GetType().GetProperties(); foreach (dynamic comField in comFields) { try { comField.SetValue(comObject, xasyncenc.Encrypt(comField.GetValue(comObject)).ToString()); } catch (ArgumentException e) { // das sollte passieren, wenn das Argument kein String is und deswegen das encrypten kein sinn macht _logger.LogError($"Couldn't encrypt COM field!: {e.Message}"); } catch (Exception f) { // das sollte passieren, wenn das Argument ein enum _logger.LogError($"Couldn't encrypt COM field!: {f.Message}"); } } affectedProp.SetValue(result, comObject); } else if (affectedProp.PropertyType.IsSubclassOf(typeof(BO4E.BO.BusinessObject))) { affectedProp.SetValue(result, xasyncenc.Encrypt((BusinessObject)affectedProp.GetValue(bo))); } else if (affectedProp.PropertyType.ToString().StartsWith("BO4E.ENUM")) // todo: check for namespace instead of strinyfied comparison { //affectedField.SetValue(mappedObject, Sha256HashEnum(affectedField.GetValue(mappedObject).ToString())); _logger.LogWarning($"Encrypting {affectedProp.PropertyType} is not supported, since the result would not be a valid ENUM value."); //throw new NotSupportedException($"Hashing {affectedField.FieldType} is not supported, since the result would not be a valid ENUM value."); } else { throw new NotImplementedException($"Encrypting {affectedProp.PropertyType} is not implemented yet."); } } break; case AnonymizerApproach.DECRYPT: if (this.privateKey == null) { throw new ArgumentNullException("To use the decryption feature you have to provide a private key using the SetPrivateKey method."); } using (X509AsymmetricEncrypter xasydec = new X509AsymmetricEncrypter(this.privateKey)) { affectedProp.SetValue(result, xasydec.Decrypt(affectedProp.GetValue(bo).ToString())); } continue; case AnonymizerApproach.KEEP: // do nothing continue; default: continue; } } } if (typeof(T) == typeof(JObject)) { return((T)(object)JObject.FromObject(result)); } return((T)(object)result); }