class Sqreen::Rules::ExecJSCB

Exec js callbacks

Public Class Methods

js_service() click to toggle source

@return [Sqreen::Js::JsService]

# File lib/sqreen/rules/execjs_cb.rb, line 20
def js_service
  Sqreen::Js::JsService.instance
end
new(klass, method, rule_hash) click to toggle source
Calls superclass method
# File lib/sqreen/rules/execjs_cb.rb, line 25
def initialize(klass, method, rule_hash)
  super(klass, method, rule_hash)
  callbacks = @rule[Attrs::CALLBACKS]
  @conditions = @rule.fetch(Attrs::CONDITIONS, {})

  build_runnable(callbacks)

  unless pre? || post? || failing?
    raise Sqreen::Exception, 'no JS CB provided'
  end

  @executable = ExecJSCB.js_service.prepare(rule_name, @source)
  @argument_filter = ArgumentFilter.new(rule_hash)
end

Private Class Methods

build_accessors(reqs) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 131
def build_accessors(reqs)
  reqs.map do |req|
    BindingAccessor.new(req, true)
  end
end

Public Instance Methods

failing(rv, inst, args, budget = nil, &_block) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 66
def failing(rv, inst, args, budget = nil, &_block)
  Sqreen.log.debug { "#{self.class} failing args: #{args.inspect}" }
  return unless failing?

  call_callback('failing', budget, inst, @cb_bas['failing'], args, rv)
end
failing?() click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 48
def failing?
  @js_failing
end
post(rv, inst, args, budget = nil, &_block) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 59
def post(rv, inst, args, budget = nil, &_block)
  Sqreen.log.debug { "#{self.class} post args: #{args.inspect}" }
  return unless post?

  call_callback('post', budget, inst, @cb_bas['post'], args, rv)
end
post?() click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 44
def post?
  @js_post
end
pre(inst, args, budget = nil, &_block) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 52
def pre(inst, args, budget = nil, &_block)
  Sqreen.log.debug { "#{self.class} pre args: #{args.inspect}" }
  return unless pre?

  call_callback('pre', budget, inst, @cb_bas['pre'], args)
end
pre?() click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 40
def pre?
  @js_pre
end

Private Instance Methods

build_runnable(callbacks) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 138
def build_runnable(callbacks)
  @cb_bas = {}
  @source = ''
  @js_pre = !callbacks['pre'].nil?
  @js_post = !callbacks['post'].nil?
  @js_failing = !callbacks['failing'].nil?
  callbacks.each do |name, args_or_func|
    @source << "this['#{name.tr("'", "\\'")}'] = "
    if args_or_func.is_a?(Array)
      args_or_func = args_or_func.dup
      @source << args_or_func.pop
      @cb_bas[name] = self.class.build_accessors(args_or_func)
    else
      @source << args_or_func
      @cb_bas[name] = []
    end
    @source << ";\n"
  end
end
call_callback(cb_name, budget, inst, cb_ba_args, args, rv = nil) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 99
def call_callback(cb_name, budget, inst, cb_ba_args, args, rv = nil)
  arguments = cb_ba_args.map do |ba|
    ba.resolve(binding, framework, inst, args, @data, rv)
  end
  arguments = @argument_filter.filter(cb_name, arguments)

  Sqreen.log.debug { "js:#{@executable.class} callback:#{cb_name}" }
  ret = @executable.run_js_cb(cb_name, budget, arguments)

  unless record_and_continue?(ret)
    return nil if ret.nil?
    return advise_action(ret[:status], ret)
  end

  name = ret[:call]
  rv = ret[:data]
  new_ba_args = if ret[:args]
                  self.class.build_accessors(ret[:args])
                else
                  @cb_bas[name] || []
                end

  # XXX: budgets was not subtracted from
  call_callback(name, budget, inst, new_ba_args, args, rv)
rescue StandardError => e
  Sqreen.log.warn { "Caught JS callback exception: #{e.inspect}" }
  Sqreen.log.debug e.backtrace
  record_exception(e, :cb => cb_name, :args => arguments)
  nil
end
record_and_continue?(ret) click to toggle source
# File lib/sqreen/rules/execjs_cb.rb, line 75
def record_and_continue?(ret)
  case ret
  when NilClass
    false
  when Hash
    ret.keys.each do |k| # rubocop:disable Performance/HashEachMethods
      ret[(begin
        k.to_sym
      rescue StandardError
        k
      end)] = ret[k] end
    record_event(ret[:record]) unless ret[:record].nil?
    unless ret['observations'].nil?
      ret['observations'].each do |obs|
        obs[3] = Time.parse(obs[3]) if obs.size >= 3 && obs[3].is_a?(String)
        record_observation(*obs)
      end
    end
    !ret[:call].nil?
  else
    raise Sqreen::Exception, "Invalid return type #{ret.inspect}"
  end
end