# Copyright (c) 2015 Sqreen. All Rights Reserved. # Please refer to our terms for more information: https://www.sqreen.com/terms.html require 'sqreen/rule_callback' require 'sqreen/binding_accessor' require 'sqreen/mono_time' require 'sqreen/rules_callbacks/matcher_rule' module Sqreen module Rules # Callback that match on a list or matcher+binding accessor class BindingAccessorMatcherCB < RuleCB MAX_LENGTH = 1024 * 128 attr_reader :rules # matcher on one elem class MatcherElem def initialize(expr) prepare([expr]) end include Matcher end def initialize(klass, method, rule_hash) super(klass, method, rule_hash) @rules = [] if @data.empty? || @data['values'].nil? || @data['values'].empty? msg = "no rules in data (had #{@data.keys})" raise Sqreen::Exception, msg end prepare_rules(@data['values']) end def prepare_rules(rules) accessors = Hash.new do |hash, key| hash[key] = BindingAccessor.new(key, true) end @rules = rules.map do |r| if r['binding_accessor'].empty? raise Sqreen::Exception, "no accessors #{r['id']}" end [ r['id'], r['binding_accessor'].map { |expression| accessors[expression] }, MatcherElem.new(r['matcher']), r['matcher']['value'], ] end end def pre(inst, args, budget = nil, &_block) unless budget.nil? finish = budget + Sqreen.time end resol_cache = Hash.new do |hash, accessor| hash[accessor] = accessor.resolve(binding, framework, inst, args) end @rules.each do |id, accessors, matcher, matcher_ref| accessors.each do |accessor| val = resol_cache[accessor] val = [val] if val.is_a?(String) next unless val.respond_to?(:each) next if val.respond_to?(:seek) val.each do |v| if !budget.nil? && Sqreen.time > finish return nil end next if !v.is_a?(String) || (!matcher.min_size.nil? && v.size < matcher.min_size) next if v.size > MAX_LENGTH next if matcher.match(v).nil? infos = { 'id' => id, 'binding_accessor' => accessor.expression, 'matcher' => matcher_ref, 'found' => v, } record_event(infos) return advise_action(:raise, :infos => infos) end end end nil end end end end