# Copyright (c) 2015 Sqreen. All Rights Reserved. # Please refer to our terms for more information: https://www.sqreen.com/terms.html # TODO: sqreen/events require 'json' require 'sqreen/log' require 'sqreen/event' require 'sqreen/encoding_sanitizer' require 'sqreen/sensitive_data_redactor' module Sqreen # When a request is deeemed worthy of being sent to the backend class RequestRecord < Sqreen::Event def initialize(payload, redactor = nil) @redactor = redactor super(payload) end def observed (payload && payload[:observed]) || {} end def to_hash res = { :version => '20171208' } if payload[:observed] res[:observed] = payload[:observed].dup rulespack = nil if observed[:attacks] res[:observed][:attacks] = observed[:attacks].map do |att| natt = att.dup rulespack = natt.delete(:rulespack_id) || rulespack natt end end if observed[:sqreen_exceptions] res[:observed][:sqreen_exceptions] = observed[:sqreen_exceptions].map do |exc| nex = exc.dup excp = nex.delete(:exception) if excp nex[:message] = excp.message nex[:klass] = excp.class.name end rulespack = nex.delete(:rulespack_id) || rulespack nex end end res[:rulespack_id] = rulespack unless rulespack.nil? if observed[:observations] res[:observed][:observations] = observed[:observations].map do |cat, key, value, time| { :category => cat, :key => key, :value => value, :time => time } end end if observed[:sdk] res[:observed][:sdk] = processed_sdk_calls end end res[:local] = payload['local'] if payload['local'] if payload['request'] res[:request] = payload['request'].dup res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip] else res[:request] = {} end if payload['response'] res[:response] = payload['response'].dup else res[:response] = {} end res[:request][:parameters] = payload['params'] if payload['params'] res[:request][:headers] = payload['headers'] if payload['headers'] res = Sqreen::EncodingSanitizer.sanitize(res) if @redactor res[:request], redacted = @redactor.redact(res[:request]) if redacted.any? && res[:observed] && res[:observed][:attacks] res[:observed][:attacks] = @redactor.redact_attacks!(res[:observed][:attacks], redacted) end if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions] res[:observed][:sqreen_exceptions] = @redactor.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted) end end res end private def processed_sdk_calls auth_keys = last_identify_id observed[:sdk].map do |meth, time, *args| { :name => meth, :time => time, :args => inject_identifiers(args, meth, auth_keys), } end end def inject_identifiers(args, meth, auth_keys) return args unless meth == :track && auth_keys track_opts = args[1] || {} if track_opts[:user_identifiers].nil? args[1] = track_opts.dup args[1][:user_identifiers] = auth_keys elsif track_opts[:user_identifiers] != auth_keys Sqreen.log.warn 'Sqreen.identify and Sqreen.track have been called ' \ 'with different user_identifiers values' end args end def last_identify_id return nil unless observed[:sdk] observed[:sdk].reverse_each do |meth, _time, *args| next unless meth == :identify return args.first if args.respond_to? :first end nil end end end