module Sqreen::Rules::Matcher

matcher behavior

Constants

ANYWHERE_OPT
MATCH_PREDICATE

Attributes

min_size[R]

Public Class Methods

prepare_re_pattern(value, options, case_sensitive) click to toggle source
# File lib/sqreen/rules/matcher_rule.rb, line 13
def self.prepare_re_pattern(value, options, case_sensitive)
  res = 0
  res |= Regexp::MULTILINE  if options.include?('multiline')
  res |= Regexp::IGNORECASE unless case_sensitive
  r = Regexp.compile(value, res)
  r =~ ''
  r
end

Public Instance Methods

match(str) click to toggle source
# File lib/sqreen/rules/matcher_rule.rb, line 83
def match(str)
  return if str.nil? || str.empty? || !str.is_a?(String)
  str = enforce_encoding(str) unless str.ascii_only?
  istr = str.downcase unless @string.empty?

  @string.each do |fun, cases|
    cases.each do |case_type, patterns|
      input_str = case_type == :ci ? istr : str
      patterns.each do |pat|
        return pat if fun.call(pat, input_str)
      end
    end
  end

  if defined?(Encoding)
    if MATCH_PREDICATE
      @regexp_patterns.each do |p|
        next unless Encoding.compatible?(p, str)
        return p if p.match?(str)
      end
    else
      @regexp_patterns.each do |p|
        next unless Encoding.compatible?(p, str)
        return p if p.match(str)
      end
    end
  else
    @regexp_patterns.each do |p|
      return p if p.match(str)
    end
  end
  nil
end
prepare(patterns) click to toggle source
# File lib/sqreen/rules/matcher_rule.rb, line 24
def prepare(patterns)
  @string = {}
  @regexp_patterns = []

  if patterns.nil?
    msg = "no key 'values' in data (had #{@data.keys})"
    raise Sqreen::Exception, msg
  end

  @funs = {
    ANYWHERE_OPT => lambda { |value, str| str.include?(value) },
    'starts_with'.freeze => lambda { |value, str| str.start_with?(value) },
    'ends_with'.freeze => lambda { |value, str| str.end_with?(value)   },
    'equals'.freeze    => lambda { |value, str| str == value           },
  }

  sizes = []
  patterns.each do |entry|
    next unless entry
    type = entry['type']
    val = entry['value']
    opts = entry['options']
    opt = ANYWHERE_OPT
    opt = opts.first.freeze if opts && opts.first && opts.first != ''
    case_sensitive = entry['case_sensitive'] || false
    case type
    when 'string'
      if case_sensitive
        case_type = :cs
      else
        case_type = :ci
        val.downcase!
      end

      way = @funs[opt]
      unless way
        Sqreen.log.debug { "Error: unknown string option '#{opt}' " }
        next
      end
      @string[way] = { :ci => [], :cs => [] } unless @string.key?(way)
      @string[way][case_type] << val
      sizes << entry.fetch('min_length') { val.size }
    when 'regexp'
      pattern = Matcher.prepare_re_pattern(val, opt, case_sensitive)
      next unless pattern
      @regexp_patterns << pattern
      sizes << entry['min_length']
    else
      raise Sqreen::Exception, "No such matcher type #{type}"
    end
  end

  @min_size = sizes.min unless sizes.any?(&:nil?)

  return unless [@regexp_patterns, @string].map(&:empty?).all?
  msg = "no key 'regexp' nor 'match' in data (had #{@data.keys})"
  raise Sqreen::Exception, msg
end

Private Instance Methods

enforce_encoding(str) click to toggle source
# File lib/sqreen/rules/matcher_rule.rb, line 119
def enforce_encoding(str)
  encoded8bit = str.encoding.name == 'ASCII-8BIT'
  return str if !encoded8bit && str.valid_encoding?
  str.chars.map do |v|
    if !v.valid_encoding? || (encoded8bit && !v.ascii_only?)
      ''
    else
      v
    end
  end.join
end