trackguard 0.24.0 → 0.27.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5aa174f1f8378c716f8e601ed6d3f44b2b0efc3b6edfc81adeb50748f0e05474
4
- data.tar.gz: 9170569fe975d076478d533eb4358f15f0537ef443ab13fb8438ce2c2d08c17d
3
+ metadata.gz: 8e9860b115149813503e2063f8ed18c86fe82510c392a12a15eec6ecda39abbc
4
+ data.tar.gz: 34f0816d3a6193f71b985336fec9076e8c7889ff583c60165b0ddbcfc7a118da
5
5
  SHA512:
6
- metadata.gz: 0a7d7bd33d7060fd30d59594485082a2e549fb1b5f8daef66835ae1e005f1a03065626608a372b7a346a9335a888685ed3fe20397b00e10c01a3f4af90b48d67
7
- data.tar.gz: 3b1911ae2d9e9826166bad1c8539a227b73627991c9d5928a2bf07abb0e58ad7408331b191353cabac544acbae30ad56f65c41db42cece8357f04e16989fa0ea
6
+ metadata.gz: 8bccd308249f6c1dc2413abeb2b4c0e133736b3e75bd8f325ca64d042e9989c6b6c826d2959d92912965974062cb73b031f74413587bb2439b48dc1eef5e1a50
7
+ data.tar.gz: 5d56636a21dd20f458b48047ea2749ad54994e11db96c70574148b267440a0da0bd05706cd6ca9d22e1192b1d7f7b498c0733a75bed260a088978e08886f152e
@@ -0,0 +1,27 @@
1
+ module Trackguard
2
+ module Admin
3
+ class BlockedPathsController < BaseController
4
+ skip_before_action :verify_authenticity_token, if: :valid_api_token?
5
+
6
+ def index
7
+ render json: BlockedPath.order(:pattern).pluck(:pattern)
8
+ end
9
+
10
+ def create
11
+ record = BlockedPath.find_or_create_by!(pattern: params.fetch(:pattern))
12
+ Rails.cache.delete(BlockedPath::CACHE_KEY)
13
+ render json: { status: "ok", pattern: record.pattern }
14
+ rescue ActionController::ParameterMissing, ActiveRecord::RecordInvalid => e
15
+ render json: { status: "error", message: e.message }, status: :unprocessable_content
16
+ end
17
+
18
+ private
19
+
20
+ def authenticate_admin!
21
+ return if valid_api_token?
22
+
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
@@ -5,14 +5,13 @@ module Trackguard
5
5
  HARD_FLAG_THRESHOLD = 50
6
6
  HIGH_VOLUME_MIN = 20
7
7
  MEDIUM_VOLUME_MIN = 10
8
- FLAG_SCORE_THRESHOLD = 6
8
+ FLAG_SCORE_THRESHOLD = 5
9
9
  MIN_VIEWS = 3
10
10
 
11
11
  WEIGHTS = {
12
12
  high_volume: 4,
13
13
  medium_volume: 2,
14
- no_session: 3,
15
- no_referer: 2
14
+ no_session: 3
16
15
  }.freeze
17
16
 
18
17
  def perform
@@ -55,12 +54,17 @@ module Trackguard
55
54
  return
56
55
  end
57
56
 
57
+ if (path = probe_path_hit(views))
58
+ flag!(visitor, "probe path hit: #{path}", name: name)
59
+ return
60
+ end
61
+
58
62
  # Don't flag casual visitors with very few views — on a single-page site,
59
63
  # legitimate users naturally hit only "/" once or twice.
60
64
  return if count < MIN_VIEWS
61
65
 
62
- if views.all? { |pv| pv.session_id.nil? && pv.referer.nil? && pv.path == "/" }
63
- flag!(visitor, "no session, no referrer, single root hit", name: name)
66
+ if views.all? { |pv| pv.session_id.nil? && pv.referer.nil? } && views.map(&:path).uniq.size == 1
67
+ flag!(visitor, "no session, no referrer, single path hit", name: name)
64
68
  return
65
69
  end
66
70
 
@@ -80,11 +84,6 @@ module Trackguard
80
84
  reasons << "#{pct(views, :session_id)}% of views had no session"
81
85
  end
82
86
 
83
- if blank_ratio(views, :referer) > 0.0
84
- score += WEIGHTS[:no_referer]
85
- reasons << "#{pct(views, :referer)}% of views had no referer"
86
- end
87
-
88
87
  return if score < FLAG_SCORE_THRESHOLD
89
88
 
90
89
  flag!(visitor, reasons.join("; "), name: name)
@@ -114,8 +113,16 @@ module Trackguard
114
113
  end
115
114
  end
116
115
 
116
+ def probe_path_hit(views)
117
+ views.find { |pv| BlockedPath.blocked?(pv.path) }&.path
118
+ end
119
+
117
120
  def ua_flag_reason(user_agent)
118
- "blank or minimal user-agent" if user_agent.blank? || user_agent.to_s.length < 10
121
+ return "blank or minimal user-agent" if user_agent.blank? || user_agent.to_s.length < 10
122
+ return "bare Mozilla/5.0 user-agent" if user_agent.strip == "Mozilla/5.0"
123
+ return "malformed user-agent (quoted)" if user_agent.start_with?('"')
124
+
125
+ "malformed user-agent (duplicate)" if user_agent.scan("Mozilla/5.0").size > 1
119
126
  end
120
127
 
121
128
  def flag!(visitor, reason, name: nil)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trackguard
4
+ class BlockedPath < ApplicationRecord
5
+ self.table_name = "trackguard_blocked_paths"
6
+
7
+ CACHE_KEY = "trackguard/blocked_path_patterns"
8
+
9
+ validates :pattern, presence: true, uniqueness: true
10
+
11
+ def self.blocked?(path)
12
+ patterns = Rails.cache.fetch(CACHE_KEY, expires_in: 10.minutes) do
13
+ pluck(:pattern)
14
+ end
15
+ patterns.any? { |p| path.to_s.downcase.include?(p.downcase) }
16
+ end
17
+
18
+ def self.matching_pattern(path)
19
+ patterns = Rails.cache.fetch(CACHE_KEY, expires_in: 10.minutes) do
20
+ pluck(:pattern)
21
+ end
22
+ patterns.find { |p| path.to_s.downcase.include?(p.downcase) }
23
+ end
24
+ end
25
+ end
@@ -4,10 +4,12 @@ module Trackguard
4
4
  class BlockedRequest < Visit
5
5
  REASON_SCANNER = "trackguard/block known scanners"
6
6
  REASON_FLAGGED = "trackguard/flagged visitors"
7
+ REASON_PROBE = "trackguard/block known paths"
7
8
 
8
9
  validates :path, :block_reason, presence: true
9
10
 
10
11
  scope :scanners, -> { where(block_reason: REASON_SCANNER) }
11
12
  scope :flagged, -> { where(block_reason: REASON_FLAGGED) }
13
+ scope :probes, -> { where(block_reason: REASON_PROBE) }
12
14
  end
13
15
  end
data/config/routes.rb CHANGED
@@ -6,6 +6,7 @@ Trackguard::Engine.routes.draw do
6
6
  resource :analytics, only: :show
7
7
  resources :visits, only: :index
8
8
  resources :blocked_user_agents, only: %i[index create]
9
+ resources :blocked_paths, only: %i[index create]
9
10
  patch "visitors/flag", to: "visitors#flag", as: :flag_visitor
10
11
  patch "visitors/unflag", to: "visitors#unflag", as: :unflag_visitor
11
12
  patch "visitors/whitelist", to: "whitelisted_ips#create", as: :whitelist_visitor
@@ -11,14 +11,20 @@ module Trackguard
11
11
  ActiveRecord::Generators::Base.next_migration_number(dirname)
12
12
  end
13
13
 
14
- def create_migration_file
15
- migration_template "create_trackguard_tables.rb", "db/migrate/create_trackguard_tables.rb"
14
+ def create_migration_files
15
+ migration_template "create_trackguard_visitors.rb", "db/migrate/create_trackguard_visitors.rb"
16
+ migration_template "create_trackguard_visits.rb", "db/migrate/create_trackguard_visits.rb"
17
+ migration_template "create_trackguard_whitelisted_ips.rb", "db/migrate/create_trackguard_whitelisted_ips.rb"
18
+ migration_template "create_trackguard_blocked_user_agents.rb",
19
+ "db/migrate/create_trackguard_blocked_user_agents.rb"
20
+ migration_template "create_trackguard_blocked_paths.rb", "db/migrate/create_trackguard_blocked_paths.rb"
16
21
  end
17
22
 
18
23
  def print_next_steps
19
24
  say "\nNext steps:", :green
20
25
  say " 1. rails db:migrate"
21
26
  say " 2. rails trackguard:seed_blocked_user_agents"
27
+ say " 3. rails trackguard:seed_blocked_paths"
22
28
  end
23
29
  end
24
30
  end
@@ -0,0 +1,10 @@
1
+ class CreateTrackguardBlockedPaths < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :trackguard_blocked_paths do |t|
4
+ t.string :pattern, null: false
5
+ t.timestamps
6
+ end
7
+
8
+ add_index :trackguard_blocked_paths, :pattern, unique: true
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateTrackguardBlockedUserAgents < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :trackguard_blocked_user_agents do |t|
4
+ t.string :pattern, null: false
5
+ t.timestamps
6
+ end
7
+
8
+ add_index :trackguard_blocked_user_agents, :pattern, unique: true
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ class CreateTrackguardVisitors < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :trackguard_visitors do |t|
4
+ t.string :ip
5
+ t.string :name
6
+ t.string :user_agent
7
+ t.datetime :first_seen_at, null: false
8
+ t.datetime :last_seen_at, null: false
9
+ t.datetime :flagged_at
10
+ t.string :flag_reason
11
+ t.string :flagged_by
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :trackguard_visitors, :ip, unique: true
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ class CreateTrackguardVisits < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :trackguard_visits do |t|
4
+ t.string :type
5
+ t.string :path, null: false
6
+ t.string :user_agent
7
+ t.string :referer
8
+ t.string :session_id
9
+ t.string :trace_id
10
+ t.string :source
11
+ t.string :block_reason
12
+ t.string :http_method
13
+ t.references :visitor, null: false, foreign_key: { to_table: :trackguard_visitors }
14
+ t.datetime :created_at, null: false
15
+ end
16
+
17
+ add_index :trackguard_visits, :type
18
+ add_index :trackguard_visits, :path
19
+ add_index :trackguard_visits, :created_at
20
+ add_index :trackguard_visits, :source
21
+ add_index :trackguard_visits, :block_reason
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ class CreateTrackguardWhitelistedIps < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :trackguard_whitelisted_ips do |t|
4
+ t.string :ip, null: false
5
+ t.datetime :expires_at, null: false
6
+ t.references :visitor, foreign_key: { to_table: :trackguard_visitors }
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :trackguard_whitelisted_ips, :ip, unique: true
11
+ add_index :trackguard_whitelisted_ips, :expires_at
12
+ end
13
+ end
@@ -29,4 +29,97 @@ namespace :trackguard do
29
29
  puts "Done: #{inserted} inserted, #{patterns.size - inserted} already existed " \
30
30
  "(#{Trackguard::BlockedUserAgent.count} total)"
31
31
  end
32
+
33
+ desc "Seed default blocked path patterns into trackguard_blocked_paths"
34
+ task seed_blocked_paths: :environment do
35
+ patterns = [
36
+ # WordPress
37
+ "wp-login.php", "wp-admin", "wp-config.php", "xmlrpc.php",
38
+ # Other CMS admin panels
39
+ "/administrator", "/typo3/",
40
+ # PHP shells & backdoors
41
+ "shell.php", "cmd.php", "c99.php", "r57.php", "webshell", "backdoor.php",
42
+ # Environment & config leaks
43
+ "/.env", "/web.config",
44
+ "phpinfo.php", "info.php", "test.php",
45
+ # Database admin tools
46
+ "/phpmyadmin", "/pma/", "/myadmin", "adminer.php",
47
+ # Source control leaks
48
+ "/.git/config", "/.git/HEAD", "/.svn/",
49
+ # Cloud credential leaks
50
+ "/.aws/credentials",
51
+ # Spring Boot / Java actuator
52
+ "/actuator/env", "/actuator/mappings", "/solr/admin/"
53
+ ]
54
+
55
+ inserted = patterns.count do |p|
56
+ Trackguard::BlockedPath.find_or_create_by!(pattern: p).previously_new_record?
57
+ end
58
+
59
+ puts "Done: #{inserted} inserted, #{patterns.size - inserted} already existed " \
60
+ "(#{Trackguard::BlockedPath.count} total)"
61
+ end
62
+
63
+ desc "Replace the monolithic create_trackguard_tables migration with individual per-table migrations"
64
+ task cleanup_monolithic_migration: :environment do
65
+ require "erb"
66
+
67
+ migrate_dir = Rails.root.join("db", "migrate")
68
+ monolithic = Dir[migrate_dir.join("*_create_trackguard_tables.rb")].first
69
+
70
+ unless monolithic
71
+ puts "No create_trackguard_tables migration found — nothing to do."
72
+ next
73
+ end
74
+
75
+ base_version = File.basename(monolithic).match(/\A(\d{14})/)[1].to_i
76
+ template_dir = Trackguard::Engine.root.join("lib", "generators", "trackguard", "templates")
77
+
78
+ splits = [
79
+ [ base_version, "create_trackguard_visitors" ],
80
+ [ base_version + 1, "create_trackguard_visits" ],
81
+ [ base_version + 2, "create_trackguard_whitelisted_ips" ],
82
+ [ base_version + 3, "create_trackguard_blocked_user_agents" ],
83
+ [ base_version + 4, "create_trackguard_blocked_paths" ]
84
+ ]
85
+
86
+ create_list = splits.map { |ts, name| " db/migrate/#{ts}_#{name}.rb" }.join("\n")
87
+
88
+ puts "This will make the following changes to your application:"
89
+ puts ""
90
+ puts " Remove: db/migrate/#{File.basename(monolithic)}"
91
+ puts " Create (table/index creation guarded with if_not_exists):"
92
+ puts create_list
93
+ puts ""
94
+ puts " Run `rails db:migrate` afterwards — existing tables and indexes are skipped safely."
95
+ puts ""
96
+
97
+ $stdout.print "Proceed? [y/N] "
98
+ input = $stdin.gets.to_s.strip.downcase
99
+ unless input == "y"
100
+ puts "Aborted."
101
+ next
102
+ end
103
+
104
+ puts ""
105
+
106
+ splits.each do |ts, name|
107
+ path = migrate_dir.join("#{ts}_#{name}.rb")
108
+ if path.exist?
109
+ puts " skip #{path.basename}"
110
+ else
111
+ raw = ERB.new(File.read(template_dir.join("#{name}.rb"))).result(binding)
112
+ guarded = raw
113
+ .gsub(/create_table (\S+) do/, 'create_table \1, if_not_exists: true do')
114
+ .gsub(/^(\s+add_index .+)$/, '\1, if_not_exists: true')
115
+ path.write(guarded)
116
+ puts " create #{path.basename}"
117
+ end
118
+ end
119
+
120
+ FileUtils.rm(monolithic)
121
+ puts " remove #{File.basename(monolithic)}"
122
+
123
+ puts "\nDone. Run `rails db:migrate` to apply any missing migrations."
124
+ end
32
125
  end
@@ -4,11 +4,13 @@ module Trackguard
4
4
  module Adapters
5
5
  class Base
6
6
  def blocked_user_agent?(user_agent) = raise NotImplementedError, "#{self.class}#blocked_user_agent?"
7
+ def blocked_path?(path) = raise NotImplementedError, "#{self.class}#blocked_path?"
7
8
  def whitelisted_ip?(ip) = raise NotImplementedError, "#{self.class}#whitelisted_ip?"
8
9
  def flagged_visitor?(ip) = raise NotImplementedError, "#{self.class}#flagged_visitor?"
9
10
 
10
11
  def track_page_view(path:, ip:, user_agent:, referer:, session_id:, trace_id:, source:, initial:, http_method:)
11
12
  return if blocked_user_agent?(user_agent)
13
+ return if blocked_path?(path)
12
14
  return if path.blank? || path.start_with?(Trackguard.admin_path)
13
15
 
14
16
  perform_track_page_view(
@@ -7,6 +7,10 @@ module Trackguard
7
7
  BlockedUserAgent.blocked?(user_agent)
8
8
  end
9
9
 
10
+ def blocked_path?(path)
11
+ BlockedPath.blocked?(path)
12
+ end
13
+
10
14
  def whitelisted_ip?(ip)
11
15
  WhitelistedIp.whitelisted?(ip)
12
16
  end
@@ -4,6 +4,7 @@ require "rack/attack"
4
4
 
5
5
  module Trackguard
6
6
  module RackAttack
7
+ # rubocop:disable Metrics/MethodLength
7
8
  def self.configure
8
9
  adapter = Trackguard.adapter
9
10
 
@@ -19,6 +20,10 @@ module Trackguard
19
20
  adapter.blocked_user_agent?(req.user_agent)
20
21
  end
21
22
 
23
+ ::Rack::Attack.blocklist("trackguard/block known paths") do |req|
24
+ adapter.blocked_path?(req.path)
25
+ end
26
+
22
27
  ::Rack::Attack.blocklist("trackguard/flagged visitors") do |req|
23
28
  adapter.flagged_visitor?(req.ip)
24
29
  end
@@ -31,6 +36,7 @@ module Trackguard
31
36
 
32
37
  subscribe_to_blocked_requests(adapter)
33
38
  end
39
+ # rubocop:enable Metrics/MethodLength
34
40
 
35
41
  def self.subscribe_to_blocked_requests(adapter)
36
42
  @subscribe_to_blocked_requests ||= ActiveSupport::Notifications.subscribe("rack.attack") do |*, payload|
@@ -1,3 +1,3 @@
1
1
  module Trackguard
2
- VERSION = "0.24.0".freeze
2
+ VERSION = "0.27.1".freeze
3
3
  end
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.24.0
4
+ version: 0.27.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krzysztof Rygielski
@@ -50,6 +50,7 @@ files:
50
50
  - app/controllers/concerns/trackguard/page_tracker.rb
51
51
  - app/controllers/trackguard/admin/analytics_controller.rb
52
52
  - app/controllers/trackguard/admin/base_controller.rb
53
+ - app/controllers/trackguard/admin/blocked_paths_controller.rb
53
54
  - app/controllers/trackguard/admin/blocked_user_agents_controller.rb
54
55
  - app/controllers/trackguard/admin/dashboards_controller.rb
55
56
  - app/controllers/trackguard/admin/visitors_controller.rb
@@ -60,6 +61,7 @@ files:
60
61
  - app/jobs/trackguard/detect_suspicious_visitors_job.rb
61
62
  - app/jobs/trackguard/track_blocked_request_job.rb
62
63
  - app/jobs/trackguard/track_page_view_job.rb
64
+ - app/models/trackguard/blocked_path.rb
63
65
  - app/models/trackguard/blocked_request.rb
64
66
  - app/models/trackguard/blocked_user_agent.rb
65
67
  - app/models/trackguard/page_view.rb
@@ -79,12 +81,12 @@ files:
79
81
  - app/views/trackguard/admin/visits/index.html.erb
80
82
  - config/importmap.rb
81
83
  - config/routes.rb
82
- - db/migrate/20260505191009_add_name_to_trackguard_visitors.rb
83
84
  - lib/generators/trackguard/install_generator.rb
84
- - lib/generators/trackguard/templates/add_trackguard_visits.rb
85
- - lib/generators/trackguard/templates/add_visitor_name.rb
86
- - lib/generators/trackguard/templates/create_trackguard_tables.rb
87
- - lib/generators/trackguard/upgrade_generator.rb
85
+ - lib/generators/trackguard/templates/create_trackguard_blocked_paths.rb
86
+ - lib/generators/trackguard/templates/create_trackguard_blocked_user_agents.rb
87
+ - lib/generators/trackguard/templates/create_trackguard_visitors.rb
88
+ - lib/generators/trackguard/templates/create_trackguard_visits.rb
89
+ - lib/generators/trackguard/templates/create_trackguard_whitelisted_ips.rb
88
90
  - lib/tasks/trackguard.rake
89
91
  - lib/trackguard.rb
90
92
  - lib/trackguard/adapters/base.rb
@@ -1,5 +0,0 @@
1
- class AddNameToTrackguardVisitors < ActiveRecord::Migration[8.0]
2
- def change
3
- add_column :trackguard_visitors, :name, :string
4
- end
5
- end
@@ -1,27 +0,0 @@
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
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddVisitorName < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
- def change
5
- add_column :trackguard_visitors, :name, :string
6
- end
7
- end
@@ -1,54 +0,0 @@
1
- class CreateTrackguardTables < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
- def change
3
- create_table :trackguard_visitors do |t|
4
- t.string :ip
5
- t.string :name
6
- t.string :user_agent
7
- t.datetime :first_seen_at, null: false
8
- t.datetime :last_seen_at, null: false
9
- t.datetime :flagged_at
10
- t.string :flag_reason
11
- t.string :flagged_by
12
- t.timestamps
13
- end
14
-
15
- add_index :trackguard_visitors, :ip, unique: true
16
-
17
- create_table :trackguard_visits do |t|
18
- t.string :type
19
- t.string :path, null: false
20
- t.string :user_agent
21
- t.string :referer
22
- t.string :session_id
23
- t.string :trace_id
24
- t.string :source
25
- t.string :block_reason
26
- t.string :http_method
27
- t.references :visitor, null: false, foreign_key: { to_table: :trackguard_visitors }
28
- t.datetime :created_at, null: false
29
- end
30
-
31
- add_index :trackguard_visits, :type
32
- add_index :trackguard_visits, :path
33
- add_index :trackguard_visits, :created_at
34
- add_index :trackguard_visits, :source
35
- add_index :trackguard_visits, :block_reason
36
-
37
- create_table :trackguard_whitelisted_ips do |t|
38
- t.string :ip, null: false
39
- t.datetime :expires_at, null: false
40
- t.references :visitor, foreign_key: { to_table: :trackguard_visitors }
41
- t.timestamps
42
- end
43
-
44
- add_index :trackguard_whitelisted_ips, :ip, unique: true
45
- add_index :trackguard_whitelisted_ips, :expires_at
46
-
47
- create_table :trackguard_blocked_user_agents do |t|
48
- t.string :pattern, null: false
49
- t.timestamps
50
- end
51
-
52
- add_index :trackguard_blocked_user_agents, :pattern, unique: true
53
- end
54
- end
@@ -1,27 +0,0 @@
1
- require "rails/generators"
2
- require "rails/generators/active_record"
3
-
4
- module Trackguard
5
- class UpgradeGenerator < Rails::Generators::Base
6
- include Rails::Generators::Migration
7
-
8
- source_root File.expand_path("templates", __dir__)
9
-
10
- def self.next_migration_number(dirname)
11
- ActiveRecord::Generators::Base.next_migration_number(dirname)
12
- end
13
-
14
- def create_visits_migration_file
15
- migration_template "add_trackguard_visits.rb", "db/migrate/add_trackguard_visits.rb"
16
- end
17
-
18
- def create_visitor_name_migration_file
19
- migration_template "add_visitor_name.rb", "db/migrate/add_visitor_name.rb"
20
- end
21
-
22
- def print_next_steps
23
- say "\nNext steps:", :green
24
- say " 1. rails db:migrate"
25
- end
26
- end
27
- end