require 'uri' module LiveQA module Plugins module Rack ## # LiveQA \Plugins \Rack \Middleware # # Middleware for Rack # class Middleware def initialize(app) @app = app end def call(env) request = ::Rack::Request.new(env) store_tracker(request) store_request_data(request, env) LiveQA::Plugins::Rails::MiddlewareData.store_data(request) if defined?(::Rails) status, headers, body = @app.call(env) write_cookie_session_tracker_id!(headers, env) [status, headers, body] ensure LiveQA::Store.clear! end private def session_tracker_id_name 'liveqa_tracker_id'.freeze end def store_tracker(request) LiveQA::Store.set( :session_tracker_id, request.cookies[session_tracker_id_name] || SecureRandom.uuid ) end def store_request_data(request, env) LiveQA::Store.set( :request, url: obfuscate_uri(request.url), ssl: request.ssl?, host: request.host, port: request.port, path: request.path, referrer: obfuscate_uri(request.referrer), method: request.request_method, xhr: request.xhr?, user_agent: request.user_agent, ip: request.ip, get_params: obfuscation_get_params(request, 'GET'), post_params: obfuscation_get_params(request, 'POST'), headers: obfuscate_headers(env) ) LiveQA::Store.bulk_set( server_software: request.env['SERVER_SOFTWARE'] ) end def write_cookie_session_tracker_id!(headers, env) ::Rack::Utils.set_cookie_header!( headers || {}, session_tracker_id_name, value: LiveQA::Store.get(:session_tracker_id), path: '/', secure: https_request?(env) ) end def obfuscate_uri(url) uri = URI.parse(url) params = Util.deep_obfuscate_value( ::Rack::Utils.parse_query(uri.query), LiveQA.configurations.obfuscated_fields, 'HIDDEN' ) return url if params.empty? uri.merge( "?#{::Rack::Utils.build_query(params)}" ).to_s rescue '' end def obfuscation_get_params(request, type) Util.deep_obfuscate_value( request.send(type), LiveQA.configurations.obfuscated_fields ) rescue {} end # determines if a request is HTTPS based on headers and env variabled def https_request?(env) env['HTTPS'] == 'on' || env['HTTP_X_FORWARDED_SSL'] == 'on' || env['HTTP_X_FORWARDED_PROTO'].to_s.split(',').first == 'https' || env['rack.url_scheme'] == 'https' end def obfuscate_headers(env) skip_headers = %w[HTTP_USER_AGENT HTTP_COOKIE HTTP_REFERER HTTP_HOST] headers = env.keys.grep(/^HTTP_|^CONTENT_TYPE$|^CONTENT_LENGTH$/).each_with_object({}) do |key, hash| next if skip_headers.include?(key) name = key.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') hash[name] = env[key] end Util.deep_obfuscate_value( headers, LiveQA.configurations.obfuscated_fields ) rescue {} end end end end end