trackguard 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/trackguard/page_tracker.rb +2 -1
- data/app/controllers/trackguard/page_views_controller.rb +2 -1
- data/app/jobs/trackguard/detect_suspicious_visitors_job.rb +1 -1
- data/app/jobs/trackguard/track_blocked_request_job.rb +24 -0
- data/app/jobs/trackguard/track_page_view_job.rb +3 -2
- data/app/models/trackguard/blocked_request.rb +13 -0
- data/app/models/trackguard/page_view.rb +1 -8
- data/app/models/trackguard/visit.rb +13 -0
- data/app/models/trackguard/visitor.rb +3 -2
- data/app/services/trackguard/page_view_recorder.rb +13 -10
- data/lib/generators/trackguard/install_generator.rb +4 -0
- data/lib/generators/trackguard/templates/add_trackguard_visits.rb +27 -0
- data/lib/trackguard/rack_attack.rb +20 -0
- data/lib/trackguard/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a4acea93b885f29862fb335806a5f378f63497793fff3e6a57cdb3eb2f0de255
|
|
4
|
+
data.tar.gz: 0aa85cf87c159a589960c253ae5bb96b4ae095093b4b2963a7f4b96590e3b065
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f770cb91aedabae79a1195b075a68d690eb730fb1ca55529c68b37ce156aebd42217174efc32beb8296d0a4bd6f45a67f94d56a3b9d8ca6103c5bc2b389bd42
|
|
7
|
+
data.tar.gz: 67b00fa4e4f2500fc2145650871f973808f0c7e6af12b0e2b212dd700c8f35b8dae9e521c4a5719ead55dd5911e43db2e428e072e7e84ed514b18a0e35a4cd40
|
|
@@ -9,7 +9,8 @@ module Trackguard
|
|
|
9
9
|
session_id: session.id.to_s,
|
|
10
10
|
trace_id: params[:trace_id].to_s.presence,
|
|
11
11
|
source: params[:ref].to_s.strip.downcase.first(64).presence,
|
|
12
|
-
initial: params[:initial] == true
|
|
12
|
+
initial: params[:initial] == true,
|
|
13
|
+
http_method: "GET"
|
|
13
14
|
)
|
|
14
15
|
|
|
15
16
|
head :no_content
|
|
@@ -103,7 +103,7 @@ module Trackguard
|
|
|
103
103
|
.unflagged
|
|
104
104
|
.joins("LEFT OUTER JOIN trackguard_whitelisted_ips wi ON wi.visitor_id = trackguard_visitors.id")
|
|
105
105
|
.joins(:page_views)
|
|
106
|
-
.where(
|
|
106
|
+
.where(trackguard_visits: { trace_id: shared, created_at: cutoff.. })
|
|
107
107
|
.where("wi.id IS NULL OR wi.expires_at <= ?", Time.current)
|
|
108
108
|
.distinct
|
|
109
109
|
.each do |visitor|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trackguard
|
|
4
|
+
class TrackBlockedRequestJob < ApplicationJob
|
|
5
|
+
queue_as :default
|
|
6
|
+
|
|
7
|
+
def perform(ip:, user_agent:, path:, http_method:, block_reason:)
|
|
8
|
+
visitor = Visitor.find_or_create_by!(ip: ip) do |v|
|
|
9
|
+
v.user_agent = user_agent
|
|
10
|
+
v.first_seen_at = Time.current
|
|
11
|
+
v.last_seen_at = Time.current
|
|
12
|
+
end
|
|
13
|
+
visitor.update!(last_seen_at: Time.current, user_agent: user_agent)
|
|
14
|
+
|
|
15
|
+
BlockedRequest.create!(
|
|
16
|
+
path: path,
|
|
17
|
+
user_agent: user_agent,
|
|
18
|
+
http_method: http_method,
|
|
19
|
+
block_reason: block_reason,
|
|
20
|
+
visitor: visitor
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -2,7 +2,8 @@ module Trackguard
|
|
|
2
2
|
class TrackPageViewJob < ApplicationJob
|
|
3
3
|
queue_as :default
|
|
4
4
|
|
|
5
|
-
def perform(path:, ip:, user_agent:, referer:, session_id: nil, trace_id: nil, source: nil, initial: false
|
|
5
|
+
def perform(path:, ip:, user_agent:, referer:, session_id: nil, trace_id: nil, source: nil, initial: false,
|
|
6
|
+
http_method: nil)
|
|
6
7
|
hashed_session_id = Digest::SHA256.hexdigest(session_id) if session_id.present?
|
|
7
8
|
|
|
8
9
|
visitor = Visitor.find_or_create_by!(ip: ip) do |v|
|
|
@@ -22,7 +23,7 @@ module Trackguard
|
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
PageView.create_with(source:, referer:)
|
|
26
|
+
PageView.create_with(source:, referer:, http_method:)
|
|
26
27
|
.find_or_create_by!(path:, user_agent:, session_id: hashed_session_id, trace_id:, visitor:)
|
|
27
28
|
end
|
|
28
29
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trackguard
|
|
4
|
+
class BlockedRequest < Visit
|
|
5
|
+
REASON_SCANNER = "trackguard/block known scanners"
|
|
6
|
+
REASON_FLAGGED = "trackguard/flagged visitors"
|
|
7
|
+
|
|
8
|
+
validates :path, :block_reason, presence: true
|
|
9
|
+
|
|
10
|
+
scope :scanners, -> { where(block_reason: REASON_SCANNER) }
|
|
11
|
+
scope :flagged, -> { where(block_reason: REASON_FLAGGED) }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
module Trackguard
|
|
2
|
-
class PageView <
|
|
3
|
-
self.table_name = "trackguard_page_views"
|
|
4
|
-
|
|
5
|
-
belongs_to :visitor, class_name: "Trackguard::Visitor"
|
|
6
|
-
|
|
2
|
+
class PageView < Visit
|
|
7
3
|
validates :path, presence: true
|
|
8
4
|
|
|
9
|
-
scope :today, -> { where(created_at: Time.current.beginning_of_day..) }
|
|
10
5
|
scope :this_week, -> { where(created_at: 1.week.ago..) }
|
|
11
6
|
scope :this_month, -> { where(created_at: 1.month.ago..) }
|
|
12
|
-
scope :last_30, -> { where(created_at: 30.days.ago..) }
|
|
13
|
-
scope :last_24h, -> { where(created_at: 24.hours.ago..) }
|
|
14
7
|
scope :with_referrer, -> { where.not(referer: [ nil, "" ]) }
|
|
15
8
|
scope :with_source, -> { where.not(source: [ nil, "" ]) }
|
|
16
9
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trackguard
|
|
4
|
+
class Visit < ApplicationRecord
|
|
5
|
+
self.table_name = "trackguard_visits"
|
|
6
|
+
|
|
7
|
+
belongs_to :visitor, class_name: "Trackguard::Visitor"
|
|
8
|
+
|
|
9
|
+
scope :today, -> { where(created_at: Time.current.beginning_of_day..) }
|
|
10
|
+
scope :last_24h, -> { where(created_at: 24.hours.ago..) }
|
|
11
|
+
scope :last_30, -> { where(created_at: 30.days.ago..) }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -7,8 +7,9 @@ module Trackguard
|
|
|
7
7
|
|
|
8
8
|
validates :flagged_by, inclusion: { in: FLAGGED_BY }, allow_blank: true
|
|
9
9
|
|
|
10
|
-
has_many :page_views,
|
|
11
|
-
|
|
10
|
+
has_many :page_views, class_name: "Trackguard::PageView", foreign_key: "visitor_id"
|
|
11
|
+
has_many :blocked_requests, class_name: "Trackguard::BlockedRequest", foreign_key: "visitor_id"
|
|
12
|
+
has_one :whitelisted_ip, class_name: "Trackguard::WhitelistedIp", foreign_key: "visitor_id"
|
|
12
13
|
|
|
13
14
|
scope :unflagged, -> { where(flagged_at: nil) }
|
|
14
15
|
scope :flagged, -> { where.not(flagged_at: nil) }
|
|
@@ -8,15 +8,17 @@ module Trackguard
|
|
|
8
8
|
bot|crawl|spider
|
|
9
9
|
/ix
|
|
10
10
|
|
|
11
|
-
def initialize(path:, ip:, user_agent:, referer:, session_id:, trace_id:, source: nil, initial: false
|
|
12
|
-
|
|
13
|
-
@
|
|
14
|
-
@
|
|
15
|
-
@
|
|
16
|
-
@
|
|
17
|
-
@
|
|
18
|
-
@
|
|
19
|
-
@
|
|
11
|
+
def initialize(path:, ip:, user_agent:, referer:, session_id:, trace_id:, source: nil, initial: false,
|
|
12
|
+
http_method: nil)
|
|
13
|
+
@path = path.to_s
|
|
14
|
+
@ip = ip
|
|
15
|
+
@user_agent = user_agent.to_s
|
|
16
|
+
@referer = referer
|
|
17
|
+
@session_id = session_id
|
|
18
|
+
@trace_id = trace_id
|
|
19
|
+
@source = source.presence
|
|
20
|
+
@initial = initial
|
|
21
|
+
@http_method = http_method
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def call
|
|
@@ -32,7 +34,8 @@ module Trackguard
|
|
|
32
34
|
session_id: @session_id,
|
|
33
35
|
trace_id: @trace_id,
|
|
34
36
|
source: @source,
|
|
35
|
-
initial: @initial
|
|
37
|
+
initial: @initial,
|
|
38
|
+
http_method: @http_method
|
|
36
39
|
)
|
|
37
40
|
end
|
|
38
41
|
end
|
|
@@ -15,6 +15,10 @@ module Trackguard
|
|
|
15
15
|
migration_template "create_trackguard_tables.rb", "db/migrate/create_trackguard_tables.rb"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def create_visits_migration_file
|
|
19
|
+
migration_template "add_trackguard_visits.rb", "db/migrate/add_trackguard_visits.rb"
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
def print_next_steps
|
|
19
23
|
say "\nNext steps:", :green
|
|
20
24
|
say " 1. rails db:migrate"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddTrackguardVisits < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
4
|
+
def up
|
|
5
|
+
rename_table :trackguard_page_views, :trackguard_visits
|
|
6
|
+
|
|
7
|
+
add_column :trackguard_visits, :type, :string
|
|
8
|
+
add_column :trackguard_visits, :block_reason, :string
|
|
9
|
+
add_column :trackguard_visits, :http_method, :string
|
|
10
|
+
|
|
11
|
+
add_index :trackguard_visits, :type
|
|
12
|
+
add_index :trackguard_visits, :block_reason
|
|
13
|
+
|
|
14
|
+
execute "UPDATE trackguard_visits SET type = 'Trackguard::PageView'"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def down
|
|
18
|
+
remove_index :trackguard_visits, :block_reason
|
|
19
|
+
remove_index :trackguard_visits, :type
|
|
20
|
+
|
|
21
|
+
remove_column :trackguard_visits, :http_method
|
|
22
|
+
remove_column :trackguard_visits, :block_reason
|
|
23
|
+
remove_column :trackguard_visits, :type
|
|
24
|
+
|
|
25
|
+
rename_table :trackguard_visits, :trackguard_page_views
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -26,6 +26,26 @@ module Trackguard
|
|
|
26
26
|
limit: Trackguard.throttle_limit,
|
|
27
27
|
period: Trackguard.throttle_period, &:ip
|
|
28
28
|
)
|
|
29
|
+
|
|
30
|
+
subscribe_to_blocked_requests
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.subscribe_to_blocked_requests
|
|
34
|
+
@subscribe_to_blocked_requests ||= ActiveSupport::Notifications.subscribe("rack.attack") do |*, payload|
|
|
35
|
+
req = payload[:request]
|
|
36
|
+
next unless req.env["rack.attack.match_type"] == :blocklist
|
|
37
|
+
|
|
38
|
+
Trackguard::TrackBlockedRequestJob.perform_later(
|
|
39
|
+
ip: req.ip,
|
|
40
|
+
user_agent: req.user_agent.to_s,
|
|
41
|
+
path: req.path,
|
|
42
|
+
http_method: req.request_method,
|
|
43
|
+
block_reason: req.env["rack.attack.matched"].to_s
|
|
44
|
+
)
|
|
45
|
+
rescue StandardError
|
|
46
|
+
# never let tracking errors surface into the middleware response
|
|
47
|
+
end
|
|
29
48
|
end
|
|
49
|
+
private_class_method :subscribe_to_blocked_requests
|
|
30
50
|
end
|
|
31
51
|
end
|
data/lib/trackguard/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trackguard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Krzysztof Rygielski
|
|
@@ -56,9 +56,12 @@ files:
|
|
|
56
56
|
- app/controllers/trackguard/page_views_controller.rb
|
|
57
57
|
- app/helpers/trackguard/application_helper.rb
|
|
58
58
|
- app/jobs/trackguard/detect_suspicious_visitors_job.rb
|
|
59
|
+
- app/jobs/trackguard/track_blocked_request_job.rb
|
|
59
60
|
- app/jobs/trackguard/track_page_view_job.rb
|
|
61
|
+
- app/models/trackguard/blocked_request.rb
|
|
60
62
|
- app/models/trackguard/blocked_user_agent.rb
|
|
61
63
|
- app/models/trackguard/page_view.rb
|
|
64
|
+
- app/models/trackguard/visit.rb
|
|
62
65
|
- app/models/trackguard/visitor.rb
|
|
63
66
|
- app/models/trackguard/whitelisted_ip.rb
|
|
64
67
|
- app/services/trackguard/application_service.rb
|
|
@@ -70,6 +73,7 @@ files:
|
|
|
70
73
|
- config/importmap.rb
|
|
71
74
|
- config/routes.rb
|
|
72
75
|
- lib/generators/trackguard/install_generator.rb
|
|
76
|
+
- lib/generators/trackguard/templates/add_trackguard_visits.rb
|
|
73
77
|
- lib/generators/trackguard/templates/create_trackguard_tables.rb
|
|
74
78
|
- lib/tasks/trackguard.rake
|
|
75
79
|
- lib/trackguard.rb
|