public void GivenAGeneralizeSetting_WhenCreate_SettingPropertiesShouldBeParsedCorrectly(Dictionary <string, object> config, string expectedCases, string expectedOtherValues)
        {
            var generalizeSetting = GeneralizeSetting.CreateFromRuleSettings(config);

            Assert.Equal(expectedCases, generalizeSetting.Cases.ToString());
            Assert.Equal(expectedOtherValues, generalizeSetting.OtherValues.ToString());
        }
        public ProcessResult Process(ElementNode node, ProcessContext context = null, Dictionary <string, object> settings = null)
        {
            EnsureArg.IsNotNull(node);
            EnsureArg.IsNotNull(context?.VisitedNodes);
            EnsureArg.IsNotNull(settings);

            var result = new ProcessResult();

            if (!ModelInfo.IsPrimitive(node.InstanceType))
            {
                throw new AnonymizerRuleNotApplicableException(
                          $"Generalization is not applicable on the node with type {node.InstanceType}. Only FHIR primitive nodes (ref: https://www.hl7.org/fhir/datatypes.html#primitive) are applicable.");
            }

            if (node.Value == null)
            {
                return(result);
            }

            var generalizeSetting = GeneralizeSetting.CreateFromRuleSettings(settings);

            foreach (var eachCase in generalizeSetting.Cases)
            {
                try
                {
                    if (node.Predicate(eachCase.Key))
                    {
                        node.Value = node.Scalar(eachCase.Value.ToString());
                        result.AddProcessRecord(AnonymizationOperations.Generalize, node);
                        return(result);
                    }
                }
                catch (Exception ex)
                {
                    throw new AnonymizerProcessingException($"Generalize failed when processing {eachCase}.", ex);
                }
            }

            if (generalizeSetting.OtherValues == GeneralizationOtherValuesOperation.Redact)
            {
                node.Value = null;
            }

            result.AddProcessRecord(AnonymizationOperations.Generalize, node);
            return(result);
        }
        public ProcessResult Process(ElementNode node, ProcessContext context = null,
                                     Dictionary <string, object> settings     = null)
        {
            EnsureArg.IsNotNull(node);
            EnsureArg.IsNotNull(context?.VisitedNodes);
            EnsureArg.IsNotNull(settings);

            var result = new ProcessResult();

            if (!ModelInfo.IsPrimitive(node.InstanceType) || node.Value == null)
            {
                return(result);
            }

            var generalizeSetting = GeneralizeSetting.CreateFromRuleSettings(settings);

            foreach (var eachCase in generalizeSetting.Cases)
            {
                try
                {
                    if (node.Predicate(eachCase.Key))
                    {
                        node.Value = node.Scalar(eachCase.Value);
                        result.AddProcessRecord(AnonymizationOperations.Generalize, node);
                        return(result);
                    }
                }
                catch (InvalidOperationException ex)
                {
                    throw new AnonymizerConfigurationErrorsException(
                              $"Invalid cases expression '{eachCase}': {ex.Message}", ex);
                }
            }

            if (generalizeSetting.OtherValues == GeneralizationOtherValuesOperation.Redact)
            {
                node.Value = null;
            }

            result.AddProcessRecord(AnonymizationOperations.Generalize, node);
            return(result);
        }
        public void Validate(AnonymizerConfiguration config)
        {
            if (string.IsNullOrEmpty(config.FhirVersion))
            {
                _logger.LogWarning($"Version is not specified in configuration file.");
            }
            else if (!string.Equals(Constants.SupportedVersion, config.FhirVersion, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new AnonymizerConfigurationErrorsException($"Configuration of fhirVersion {config.FhirVersion} is not supported. Expected fhirVersion: {Constants.SupportedVersion}");
            }

            if (config.FhirPathRules == null)
            {
                throw new AnonymizerConfigurationErrorsException("The configuration is invalid, please specify any fhirPathRules");
            }

            FhirPathCompiler compiler = new FhirPathCompiler();
            var supportedMethods      = Enum.GetNames(typeof(AnonymizerMethod)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);

            foreach (var rule in config.FhirPathRules)
            {
                if (!rule.ContainsKey(Constants.PathKey) || !rule.ContainsKey(Constants.MethodKey))
                {
                    throw new AnonymizerConfigurationErrorsException("Missing path or method in Fhir path rule config.");
                }

                // Grammar check on FHIR path
                try
                {
                    compiler.Compile(rule[Constants.PathKey].ToString());
                }
                catch (Exception ex)
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid FHIR path {rule[Constants.PathKey]}", ex);
                }

                // Method validate
                string method = rule[Constants.MethodKey].ToString();
                if (!supportedMethods.Contains(method))
                {
                    throw new AnonymizerConfigurationErrorsException($"Anonymization method {method} not supported.");
                }

                // Should provide replacement value for substitute rule
                if (string.Equals(method, AnonymizerMethod.Substitute.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    SubstituteSetting.ValidateRuleSettings(rule);
                }

                if (string.Equals(method, AnonymizerMethod.Perturb.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    PerturbSetting.ValidateRuleSettings(rule);
                }
                if (string.Equals(method, AnonymizerMethod.Generalize.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    GeneralizeSetting.ValidateRuleSettings(rule);
                }
            }

            // Check AES key size is valid (16, 24 or 32 bytes).
            if (!string.IsNullOrEmpty(config.ParameterConfiguration?.EncryptKey))
            {
                using Aes aes = Aes.Create();
                var encryptKeySize = Encoding.UTF8.GetByteCount(config.ParameterConfiguration.EncryptKey) * 8;
                if (!IsValidKeySize(encryptKeySize, aes.LegalKeySizes))
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid encrypt key size : {encryptKeySize} bits! Please provide key sizes of 128, 192 or 256 bits.");
                }
            }
        }
 public void GivenAInvalidGeneralizeSetting_WhenValidate_ExceptionShouldBeThrown(Dictionary <string, object> config)
 {
     Assert.Throws <AnonymizerConfigurationErrorsException>(() => GeneralizeSetting.ValidateRuleSettings(config));
 }