public void SearchSkimmer_AllowFileNameRegexMatchesProperly()
        {
            string scanTargetExtension = Guid.NewGuid().ToString();

            SearchDefinition definition = null;

            AnalyzeContext context =
                CreateGuidMatchingSkimmer(
                    scanTargetExtension: scanTargetExtension,
                    ref definition,
                    out SearchSkimmer skimmer,
                    allowFileExtension: scanTargetExtension,
                    denyFileExtension: null);

            AnalysisApplicability applicability = skimmer.CanAnalyze(context, out string reasonIfNotApplicable);

            applicability.Should().Be(AnalysisApplicability.ApplicableToSpecifiedTarget);
            reasonIfNotApplicable.Should().BeNull();

            skimmer.Analyze(context);
            ValidateResultsAgainstDefinition(((TestLogger)context.Logger).Results, definition, skimmer);

            context.FileContents = null;
            ((TestLogger)context.Logger).Results.Clear();

            skimmer.Analyze(context);
            ValidateResultsAgainstDefinition(((TestLogger)context.Logger).Results, definition, skimmer);
        }
        private AnalyzeContext CreateGuidMatchingSkimmer(
            string scanTargetExtension,
            ref SearchDefinition definition,
            out SearchSkimmer skimmer,
            string allowFileExtension  = null,
            string denyFileExtension   = null,
            ValidatorsCache validators = null)
        {
            MatchExpression expression =
                CreateGuidDetectingMatchExpression(
                    denyFileExtension: denyFileExtension,
                    allowFileExtension: allowFileExtension);

            definition ??= CreateDefaultSearchDefinition(expression);

            var logger = new TestLogger();

            var context = new AnalyzeContext
            {
                TargetUri    = new Uri($"file:///c:/{definition.Name}.{definition.FileNameAllowRegex}.{scanTargetExtension}"),
                FileContents = definition.Id,
                Logger       = logger
            };

            var mockFileSystem = new Mock <IFileSystem>();

            mockFileSystem.Setup(x => x.FileReadAllText(context.TargetUri.LocalPath)).Returns(definition.Id);

            skimmer = CreateSkimmer(
                definition,
                validators: validators,
                fileSystem: mockFileSystem.Object);

            return(context);
        }
 private void ValidateResultsAgainstDefinition(IList <Result> results, SearchDefinition definition, SearchSkimmer skimmer)
 {
     results.Should().NotBeNull();
     results.Count.Should().Be(1);
     results[0].RuleId.Should().Be(definition.Id);
     results[0].Level.Should().Be(definition.Level);
     results[0].GetMessageText(skimmer).Should().Be($"{definition.Message}");
 }
        private SearchSkimmer CreateSkimmer(
            SearchDefinition definition,
            IRegex engine = null,
            ValidatorsCache validators        = null,
            FileRegionsCache fileRegionsCache = null,
            IFileSystem fileSystem            = null)
        {
            var definitions = new SearchDefinitions
            {
                Definitions = new List <SearchDefinition>(new[] { definition }),
            };

            definitions = AnalyzeCommand.PushInheritedData(definitions, sharedStrings: null);

            return(new SearchSkimmer(
                       engine: engine ?? RE2Regex.Instance,
                       validators: validators,
                       fileRegionsCache: fileRegionsCache ?? new FileRegionsCache(),
                       definition: definitions.Definitions[0],
                       fileSystem: fileSystem));
        }
        public void SearchSkimmer_DenyFileNameRegexFiltersProperly()
        {
            string scanTargetExtension = Guid.NewGuid().ToString();

            SearchDefinition definition = null;

            AnalyzeContext context =
                CreateGuidMatchingSkimmer(
                    scanTargetExtension: scanTargetExtension,
                    ref definition,
                    out SearchSkimmer skimmer,
                    allowFileExtension: null,
                    denyFileExtension: scanTargetExtension);

            AnalysisApplicability applicability = skimmer.CanAnalyze(context, out string reasonIfNotApplicable);

            applicability.Should().Be(AnalysisApplicability.NotApplicableToSpecifiedTarget);
            reasonIfNotApplicable.Should().Be(SpamResources.TargetDoesNotMeetFileNameCriteria);

            skimmer.Analyze(context);
            ((TestLogger)context.Logger).Results.Should().BeNull();
        }
        public void SearchSkimmer_NoDetectionWhenMatchIsEmpty()
        {
            var expression = new MatchExpression();
            SearchDefinition definition = CreateDefaultSearchDefinition(expression);

            string scanTargetContents = definition.Id;

            var logger = new TestLogger();

            var context = new AnalyzeContext
            {
                TargetUri    = new Uri($"file:///c:/{definition.Name}.Fake.asc"),
                FileContents = $"{ definition.Id}",
                Logger       = logger
            };

            SearchSkimmer skimmer = CreateSkimmer(definition);

            skimmer.Analyze(context);

            logger.Results.Should().BeNull();
        }
        public void SearchSkimmer_BothAllowAndDenyFileNameRegexFiltersProperly()
        {
            string scanTargetExtension = Guid.NewGuid().ToString();

            // Analysis should not occur unless the file name both matches
            // the allow regex, if present, and does not match the deny
            // regex, if present. So, if the file name matches both the
            // allow and deny regex, we should not analyze.

            SearchDefinition definition = null;

            AnalyzeContext context =
                CreateGuidMatchingSkimmer(
                    scanTargetExtension: scanTargetExtension,
                    ref definition,
                    out SearchSkimmer skimmer,
                    allowFileExtension: scanTargetExtension,
                    denyFileExtension: scanTargetExtension);

            skimmer.Analyze(context);

            ((TestLogger)context.Logger).Results.Should().BeNull();
        }
        public void SearchSkimmer_DetectsFilePatternOnly()
        {
            string           fileExtension = Guid.NewGuid().ToString();
            MatchExpression  expr          = CreateFileDetectingMatchExpression(fileExtension: fileExtension);
            SearchDefinition definition    = CreateDefaultSearchDefinition(expr);

            string scanTargetContents = definition.Id;

            var logger = new TestLogger();

            var context = new AnalyzeContext
            {
                TargetUri    = new Uri($"file:///c:/{definition.Name}.Fake.{fileExtension}"),
                FileContents = definition.Id,
                Logger       = logger
            };

            SearchSkimmer skimmer = CreateSkimmer(definition);

            skimmer.Analyze(context);

            ValidateResultsAgainstDefinition(logger.Results, definition, skimmer);
        }
        public void SearchSkimmer_ValidatorResultsAreProperlyPrioritized()
        {
            string validatorAssemblyPath = $@"c:\{Guid.NewGuid()}.dll";
            string scanTargetExtension   = Guid.NewGuid().ToString();

            var mockFileSystem = new Mock <IFileSystem>();

            mockFileSystem.Setup(x => x.FileExists(validatorAssemblyPath)).Returns(true);
            mockFileSystem.Setup(x => x.AssemblyLoadFrom(validatorAssemblyPath)).Returns(this.GetType().Assembly);

            var validators = new ValidatorsCache(
                new string[] { validatorAssemblyPath },
                fileSystem: mockFileSystem.Object);

            MatchExpression expression =
                CreateGuidDetectingMatchExpression(
                    allowFileExtension: scanTargetExtension);

            expression.ContentsRegex = "TestRule";

            SearchDefinition definition = CreateDefaultSearchDefinition(expression);

            // This Id will match us up with the TestRuleValidator type.
            definition.Id = "TestRule";

            AnalyzeContext context =
                CreateGuidMatchingSkimmer(
                    scanTargetExtension: scanTargetExtension,
                    ref definition,
                    out SearchSkimmer skimmer,
                    validators: validators);

            skimmer.Analyze(context);

            //((TestLogger)context.Logger).Results.Should().BeNull();
        }
Ejemplo n.º 10
0
        internal static SearchDefinitions PushInheritedData(SearchDefinitions definitions, Dictionary <string, string> sharedStrings)
        {
            var idToExpressionsMap = new Dictionary <string, List <MatchExpression> >();

            foreach (SearchDefinition definition in definitions.Definitions)
            {
                definition.FileNameDenyRegex = PushData(definition.FileNameDenyRegex,
                                                        definition.SharedStrings,
                                                        sharedStrings);

                definition.FileNameAllowRegex = PushData(definition.FileNameAllowRegex,
                                                         definition.SharedStrings,
                                                         sharedStrings);

                foreach (MatchExpression matchExpression in definition.MatchExpressions)
                {
                    matchExpression.FileNameDenyRegex = PushData(matchExpression.FileNameDenyRegex,
                                                                 definition.SharedStrings,
                                                                 sharedStrings);

                    matchExpression.FileNameDenyRegex ??= definition.FileNameDenyRegex;

                    matchExpression.FileNameAllowRegex = PushData(matchExpression.FileNameAllowRegex,
                                                                  definition.SharedStrings,
                                                                  sharedStrings);

                    matchExpression.FileNameAllowRegex ??= definition.FileNameAllowRegex;

                    matchExpression.ContentsRegex = PushData(matchExpression.ContentsRegex,
                                                             definition.SharedStrings,
                                                             sharedStrings);

                    matchExpression.Id ??= definition.Id;
                    matchExpression.Name ??= definition.Name;
                    matchExpression.Message ??= definition.Message;
                    matchExpression.Description ??= definition.Description;

                    if (matchExpression.Level == 0)
                    {
                        matchExpression.Level = definition.Level;
                    }

                    if (!idToExpressionsMap.TryGetValue(matchExpression.Id, out List <MatchExpression> cachedMatchExpressions))
                    {
                        cachedMatchExpressions = idToExpressionsMap[matchExpression.Id] = new List <MatchExpression>();
                    }

                    cachedMatchExpressions.Add(matchExpression);
                }
            }

            var searchDefinitions = new SearchDefinitions
            {
                Definitions = new List <SearchDefinition>(),
            };

            foreach (KeyValuePair <string, List <MatchExpression> > kv in idToExpressionsMap)
            {
                string ruleId = kv.Key;
                List <MatchExpression> matchExpressions = kv.Value;

                var definition = new SearchDefinition
                {
                    Id               = matchExpressions[0].Id,
                    Name             = matchExpressions[0].Name,
                    MatchExpressions = matchExpressions,
                    Description      = matchExpressions[0].Description,
                };

                searchDefinitions.Definitions.Add(definition);
            }

#if DEBUG
            ValidateSharedStringsExpansion(searchDefinitions);
#endif

            return(searchDefinitions);
        }
        public void SearchSkimmer_DetectsBase64EncodedPattern()
        {
            MatchExpression  expr       = CreateGuidDetectingMatchExpression();
            SearchDefinition definition = CreateDefaultSearchDefinition(expr);

            string originalMessage = definition.Message;

            // We inject the well-known encoding name that reports with
            // 'plaintext' or 'base64-encoded' depending on how a match
            // was made.
            definition.Message = $"{{0:encoding}}:{definition.Message}";

            string scanTargetContents = definition.Id;

            byte[] bytes         = Encoding.UTF8.GetBytes(scanTargetContents);
            string base64Encoded = Convert.ToBase64String(bytes);

            var logger = new TestLogger();

            var context = new AnalyzeContext
            {
                TargetUri    = new Uri($"file:///c:/{definition.Name}.{definition.FileNameAllowRegex}"),
                FileContents = base64Encoded,
                Logger       = logger
            };

            SearchSkimmer skimmer = CreateSkimmer(definition);

            skimmer.Analyze(context);

            // Analyzing base64-encoded values with MatchLengthToDecode > 0 succeeds
            logger.Results.Count.Should().Be(1);
            logger.Results[0].RuleId.Should().Be(definition.Id);
            logger.Results[0].Level.Should().Be(definition.Level);
            logger.Results[0].GetMessageText(skimmer).Should().Be($"base64-encoded:{originalMessage}");

            // Analyzing base64-encoded values with MatchLengthToDecode == 0 fails
            definition.MatchExpressions[0].MatchLengthToDecode = 0;

            logger.Results.Clear();
            skimmer = CreateSkimmer(definition);
            skimmer.Analyze(context);

            logger.Results.Count.Should().Be(0);

            // Analyzing plaintext values with MatchLengthToDecode > 0 succeeds
            context.FileContents = scanTargetContents;

            logger.Results.Clear();
            skimmer = CreateSkimmer(definition);
            skimmer.Analyze(context);

            // But we should see a change in encoding information in message. Note
            // that when emitting plaintext matches, we elide this information
            // entirely (i.e., we only explicitly report 'base64-encoded' and
            // report nothing for plaintext).
            logger.Results.Count.Should().Be(1);
            logger.Results[0].RuleId.Should().Be(definition.Id);
            logger.Results[0].Level.Should().Be(definition.Level);
            logger.Results[0].GetMessageText(skimmer).Should().Be($":{originalMessage}");
        }
 public SearchSkimmer(IRegex engine, ValidatorsCache validators, FileRegionsCache fileRegionsCache, SearchDefinition definition, IFileSystem fileSystem = null)
     : this(
         engine,
         validators,
         fileRegionsCache,
         definition.Id,
         definition.Name,
         definition.Description,
         definition.MatchExpressions,
         fileSystem)
 {
 }