Name

sn_em_tbac.EvtMgmtTagBasedComparators

Description

Function to compare values for Tag Based Alert Clustering Engine. This script is being called from alert correlation rules.

Script

var EvtMgmtTagBasedComparators = Class.create();
EvtMgmtTagBasedComparators.prototype = {
  type: 'EvtMgmtTagBasedComparators',

  initialize: function() {
      // Is correlation case sensitive property, defaults to true.
      this.correlationCaseSensitiveProperty = gs.getProperty('sa_analytics.correlation_case_sensitive', 'true');

      // List of allowed algorithms 
      this.allowedFuzzyAlgorithms = gs.getProperty('evt_mgmt.sn_em_tbac.allowed_fuzzy_algorithms', '');

      // Supported algorithm names
      this.LEVENSHTEIN = 'levenshtein';

      // Default fuzzy algorithm
      this.DEFAULT_FUZZY_ALGORITHM = this.LEVENSHTEIN;
  },

  /*
   * Returns true if s1 is equal to s2, taking the correlation case sensitivity property into consideration.
   * Returns false if the given arguments are not strings, or if the strings aren't equal.
   */
  exact: function(s1, s2) {
      if (!this.areStrings(s1, s2)) {
          return false;
      }

      // If the property is set to false then lower case the strings before comparing them.
      if (!this.isCorrelationCaseSensitive()) {
          s1 = s1.toLowerCase();
          s2 = s2.toLowerCase();
      }

      return s1 == s2;
  },

  /*
   * Fuzzy function to return true if strings are similar.
   */
  fuzzy: function(similarity, s1, s2, algorithm) {
      similarity = Number(similarity);
      if (!this.areStrings(s1, s2) || isNaN(similarity) || similarity < 0 || similarity > 100) {
          return false;
      }
      similarity = similarity / 100; // convert to a number between [0,1]

      // Set default algorithm if the given algorithm is NOT allowed
      if (this.allowedFuzzyAlgorithms && !this.allowedFuzzyAlgorithms.includes(algorithm)) {
          algorithm = this.DEFAULT_FUZZY_ALGORITHM;
      }

      var result = 0;

      // In case of fuzzy match, always transform the compared string to lower case.
      s1 = s1.toLowerCase();
      s2 = s2.toLowerCase();

      switch (algorithm) {
          case this.LEVENSHTEIN:
              result = this._levenshteinAlgorithm(s1, s2);
              break;
      }

      return result >= similarity;
  },

  /*
   * Returns true if each of s1 and s2 are matching the given pattern, false otherwise.
   */
  pattern: function(s1, s2, patternAsRegexWithoutFlags) {
      if (!this.areStrings(s1, s2)) {
          return false;
      }

      // As regex with flags: i - case insensitive, g - global (all occurrences in string).
      // Add the case-insensitive flag only if the correlation case sensitivity property is set to false.
      var caseInsensitiveFlag = (!this.isCorrelationCaseSensitive()) ? 'i' : '';

      var flags = caseInsensitiveFlag + 'g'; // 'ig' or 'g' depends on case sensitivity property.
      var regexp = new RegExp(patternAsRegexWithoutFlags, flags);

      return (s1.match(regexp) != null) && (s2.match(regexp) != null);
  },

  /*
   * Returns true if the given GR is matching the given filter condition, false otherwise.
   * Takes the correlation case sensitivity property value into consideration.
   */
  checkRecord: function(gr, filterCondition) {
      if (!gr || !gr.isValidRecord()) {
          return false;
      }

      var glideFilter = new GlideFilter(filterCondition, 'filterConditionWithCases');
      // If the property is set to false then set the case sensitive flag to false.
      if (!this.isCorrelationCaseSensitive()) {
          glideFilter.setCaseSensitive(false);
      }

      return glideFilter.match(gr, true);
  },

  // Levenshtein distance algorithm for Fuzzy match comparison.
  _levenshteinAlgorithm: function(a, b) {
      if (a.length == 0) return b.length;
      if (b.length == 0) return a.length;
      var matrix = [];
      // increment along the first column of each row
      var i;
      for (i = 0; i <= b.length; i++) {
          matrix[i] = [i];
      }
      // increment each column in the first row
      var j;
      for (j = 0; j <= a.length; j++) {
          matrix[0][j] = j;
      }
      // Fill in the rest of the matrix
      for (i = 1; i <= b.length; i++) {
          for (j = 1; j <= a.length; j++) {
              if (b.charAt(i - 1) == a.charAt(j - 1)) {
                  matrix[i][j] = matrix[i - 1][j - 1];
              } else {
                  matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
                      Math.min(matrix[i][j - 1] + 1, // insertion
                          matrix[i - 1][j] + 1)); // deletion
              }
          }
      }

      var levenshteinDistance = matrix[b.length][a.length];

      // Addition to levenshtein distance, to get the result as decimal.
      return (1 - (levenshteinDistance / Math.max(a.length, b.length)));
  },

  isCorrelationCaseSensitive: function() {
      return this.correlationCaseSensitiveProperty == 'true';
  },

  // Returns true if the type of s1 and s2 is string, false otherwise.
  areStrings: function(s1, s2) {
      return (typeof s1 === 'string' && typeof s2 === 'string');
  }
};

Sys ID

08d44353532c70107c03ddeeff7b120a

Offical Documentation

Official Docs: