Class: ShieldPressTracker::Tracker

Inherits:
Object
  • Object
show all
Defined in:
lib/shieldpress_tracker/tracker.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ Tracker

Returns a new instance of Tracker.



9
10
11
12
13
# File 'lib/shieldpress_tracker/tracker.rb', line 9

def initialize(config = {})
  @config = Config.new(config); @http_collector = HttpCollector.new
  @error_collector = ErrorCollector.new(@config.max_error_buffer); @security_collector = SecurityCollector.new(@config.max_security_buffer)
  @reporter = Reporter.new(@config.api_url, @config.api_key, @config.debug); @stopped = false; @last_audit = Time.at(0)
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



8
9
10
# File 'lib/shieldpress_tracker/tracker.rb', line 8

def config
  @config
end

#error_collectorObject (readonly)

Returns the value of attribute error_collector.



8
9
10
# File 'lib/shieldpress_tracker/tracker.rb', line 8

def error_collector
  @error_collector
end

#http_collectorObject (readonly)

Returns the value of attribute http_collector.



8
9
10
# File 'lib/shieldpress_tracker/tracker.rb', line 8

def http_collector
  @http_collector
end

#security_collectorObject (readonly)

Returns the value of attribute security_collector.



8
9
10
# File 'lib/shieldpress_tracker/tracker.rb', line 8

def security_collector
  @security_collector
end

Instance Method Details

#analyze_request(url:, method: "GET", headers: {}, body: nil, ip: nil, query: nil) ⇒ Object



32
33
34
# File 'lib/shieldpress_tracker/tracker.rb', line 32

def analyze_request(url:, method: "GET", headers: {}, body: nil, ip: nil, query: nil)
  @security_collector.analyze(url: url, method: method, headers: headers, body: body, ip: ip, query: query) if @config.security_tracking && !ignored?(url)
end

#capture_error(error, meta = {}) ⇒ Object



35
# File 'lib/shieldpress_tracker/tracker.rb', line 35

def capture_error(error, meta = {}); @error_collector.capture(error, meta) if @config.error_tracking end

#flushObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/shieldpress_tracker/tracker.rb', line 48

def flush
  c = @config
  payload = { siteId: c.site_id, appName: c.app_name, appVersion: c.app_version, environment: c.environment,
              tags: c.tags, timestamp: Time.now.utc.iso8601 }
  payload[:system] = Metrics.system if c.system_metrics
  http = @http_collector.flush if c.http_tracking; payload[:http] = http if http
  errors = @error_collector.flush if c.error_tracking; payload[:errors] = errors unless errors.nil? || errors.empty?
  security = @security_collector.flush if c.security_tracking; payload[:security] = security if security
  payload[:runtime] = Metrics.runtime if c.runtime_metrics; payload[:envSecurity] = Metrics.environment if c.env_security
  if c.dep_audit && Time.now - @last_audit >= c.dep_audit_interval.to_i; payload[:depAudit] = Metrics.dependencies; @last_audit = Time.now; end
  payload[:heartbeat] = true if c.heartbeat
  @reporter.send(payload)
rescue StandardError
  false
end

#ignored?(path) ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
28
# File 'lib/shieldpress_tracker/tracker.rb', line 25

def ignored?(path)
  path = URI.parse(path).path rescue path
  @config.ignore_paths.any? { |pattern| pattern.end_with?("/*") ? path.start_with?(pattern[0..-2]) : path == pattern }
end

#record_auth_failure(ip: nil, url: nil, method: nil, reason: nil) ⇒ Object



36
37
38
# File 'lib/shieldpress_tracker/tracker.rb', line 36

def record_auth_failure(ip: nil, url: nil, method: nil, reason: nil)
  @security_collector.record(type: :auth_failure, severity: :medium, message: "Authentication failed#{reason ? ": #{reason}" : ""}", ip: ip, url: url, method: method)
end

#record_cors_violation(ip: nil, origin: nil, url: nil) ⇒ Object



42
43
44
# File 'lib/shieldpress_tracker/tracker.rb', line 42

def record_cors_violation(ip: nil, origin: nil, url: nil)
  @security_collector.record(type: :cors_violation, severity: :medium, message: "CORS policy blocked request from origin: #{origin || 'unknown'}", ip: ip, url: url)
end

#record_rate_limit(ip: nil, url: nil, method: nil, limit: nil) ⇒ Object



39
40
41
# File 'lib/shieldpress_tracker/tracker.rb', line 39

def record_rate_limit(ip: nil, url: nil, method: nil, limit: nil)
  @security_collector.record(type: :rate_limit_hit, severity: :low, message: "Rate limit triggered", ip: ip, url: url, method: method, meta: { limit: limit })
end

#record_request(path:, method: "GET", status_code: 200, duration_ms: 0) ⇒ Object



29
30
31
# File 'lib/shieldpress_tracker/tracker.rb', line 29

def record_request(path:, method: "GET", status_code: 200, duration_ms: 0)
  @http_collector.record(path: path, method: method, status_code: status_code, duration_ms: duration_ms) if @config.http_tracking && !ignored?(path)
end

#record_security_event(type:, severity:, message:, **data) ⇒ Object



45
46
47
# File 'lib/shieldpress_tracker/tracker.rb', line 45

def record_security_event(type:, severity:, message:, **data)
  @security_collector.record(type: type, severity: severity, message: message, **data)
end

#startObject



14
15
16
17
18
19
20
21
22
23
# File 'lib/shieldpress_tracker/tracker.rb', line 14

def start
  return self if @thread&.alive?
  @stopped = false
  @thread = Thread.new do
    Thread.current.name = "shieldpress-reporter" if Thread.current.respond_to?(:name=)
    until @stopped; sleep(@config.report_interval.to_i); flush unless @stopped; end
  end
  @thread.abort_on_exception = false
  self
end

#stop(flush: true) ⇒ Object



24
# File 'lib/shieldpress_tracker/tracker.rb', line 24

def stop(flush: true); @stopped = true; @thread&.kill; self.flush if flush; self end