beskar 0.0.2 → 0.1.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -0
  3. data/README.md +298 -110
  4. data/app/controllers/beskar/application_controller.rb +170 -0
  5. data/app/controllers/beskar/banned_ips_controller.rb +280 -0
  6. data/app/controllers/beskar/dashboard_controller.rb +70 -0
  7. data/app/controllers/beskar/security_events_controller.rb +182 -0
  8. data/app/controllers/concerns/beskar/controllers/security_tracking.rb +6 -6
  9. data/app/models/beskar/banned_ip.rb +68 -27
  10. data/app/models/beskar/security_event.rb +14 -0
  11. data/app/services/beskar/banned_ip_manager.rb +78 -0
  12. data/app/views/beskar/banned_ips/edit.html.erb +259 -0
  13. data/app/views/beskar/banned_ips/index.html.erb +361 -0
  14. data/app/views/beskar/banned_ips/new.html.erb +310 -0
  15. data/app/views/beskar/banned_ips/show.html.erb +310 -0
  16. data/app/views/beskar/dashboard/index.html.erb +280 -0
  17. data/app/views/beskar/security_events/index.html.erb +309 -0
  18. data/app/views/beskar/security_events/show.html.erb +307 -0
  19. data/app/views/layouts/beskar/application.html.erb +647 -5
  20. data/config/routes.rb +41 -0
  21. data/lib/beskar/configuration.rb +24 -10
  22. data/lib/beskar/engine.rb +4 -4
  23. data/lib/beskar/logger.rb +293 -0
  24. data/lib/beskar/middleware/request_analyzer.rb +128 -53
  25. data/lib/beskar/models/security_trackable_authenticable.rb +11 -11
  26. data/lib/beskar/models/security_trackable_devise.rb +5 -5
  27. data/lib/beskar/models/security_trackable_generic.rb +12 -12
  28. data/lib/beskar/services/account_locker.rb +12 -12
  29. data/lib/beskar/services/geolocation_service.rb +8 -8
  30. data/lib/beskar/services/ip_whitelist.rb +2 -2
  31. data/lib/beskar/services/waf.rb +307 -78
  32. data/lib/beskar/version.rb +1 -1
  33. data/lib/beskar.rb +1 -0
  34. data/lib/generators/beskar/install/install_generator.rb +158 -0
  35. data/lib/generators/beskar/install/templates/initializer.rb.tt +177 -0
  36. data/lib/tasks/beskar_tasks.rake +11 -2
  37. metadata +35 -6
  38. data/lib/beskar/templates/beskar_initializer.rb +0 -107
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ Beskar.configure do |config|
4
+ # ============================================================================
5
+ # DASHBOARD AUTHENTICATION (REQUIRED)
6
+ # ============================================================================
7
+ # Configure how to authenticate access to the Beskar security dashboard.
8
+ # This is REQUIRED for all environments.
9
+ #
10
+ # The authenticate_admin callback receives the request object and is executed
11
+ # in the controller context, giving you access to all controller methods
12
+ # (cookies, session, authenticate_or_request_with_http_basic, etc.).
13
+ # The block should return truthy value to allow access, falsey to deny.
14
+
15
+ # Option 1: Using Devise with admin role (recommended for production)
16
+ # config.authenticate_admin = ->(request) do
17
+ # user = request.env['warden']&.authenticate(scope: :user)
18
+ # user&.admin?
19
+ # end
20
+
21
+ # Option 2: HTTP Basic Authentication (uses controller method)
22
+ # config.authenticate_admin = ->(request) do
23
+ # authenticate_or_request_with_http_basic("Beskar Admin") do |username, password|
24
+ # username == ENV['BESKAR_ADMIN_USERNAME'] &&
25
+ # password == ENV['BESKAR_ADMIN_PASSWORD']
26
+ # end
27
+ # end
28
+
29
+ # Option 3: Token-based authentication
30
+ # config.authenticate_admin = ->(request) do
31
+ # request.headers['Authorization'] == "Bearer #{ENV['BESKAR_ADMIN_TOKEN']}"
32
+ # end
33
+
34
+ # Option 4: Cookie-based authentication (uses controller cookies)
35
+ # config.authenticate_admin = ->(request) do
36
+ # cookies.signed[:admin_token] == ENV['BESKAR_ADMIN_TOKEN']
37
+ # end
38
+
39
+ # Option 5: Using CanCanCan (uses controller method)
40
+ # config.authenticate_admin = ->(request) do
41
+ # authorize! :manage, :beskar_dashboard
42
+ # end
43
+
44
+ # Option 6: Using Pundit (uses controller method)
45
+ # config.authenticate_admin = ->(request) do
46
+ # authorize :beskar_dashboard, :access?
47
+ # end
48
+
49
+ # Option 7: For development/testing ONLY (NOT for production!)
50
+ # config.authenticate_admin = ->(request) do
51
+ # Rails.env.development? || Rails.env.test?
52
+ # end
53
+
54
+ # ============================================================================
55
+ # MONITOR-ONLY MODE
56
+ # ============================================================================
57
+ # When enabled, Beskar will log all security events but won't actually block
58
+ # any requests. Useful for testing or initial deployment.
59
+ config.monitor_only = <%= Rails.env.development? ? 'true' : 'false' %>
60
+
61
+ # ============================================================================
62
+ # IP WHITELIST
63
+ # ============================================================================
64
+ # IPs that should never be blocked (your office, monitoring services, etc.)
65
+ config.ip_whitelist = [
66
+ # '192.168.1.0/24', # Local network
67
+ # '10.0.0.0/8', # Private network
68
+ # '127.0.0.1', # Localhost
69
+ ]
70
+
71
+ # ============================================================================
72
+ # WAF (WEB APPLICATION FIREWALL) - Score-Based Blocking
73
+ # ============================================================================
74
+ # Enable WAF to protect against common attacks and vulnerability scans.
75
+ # Uses score-based blocking with exponential decay for intelligent threat detection.
76
+ config.waf[:enabled] = true
77
+
78
+ # Optionally customize WAF settings (these are the defaults):
79
+ # config.waf[:auto_block] = true # Automatically block IPs after threshold
80
+ # config.waf[:score_threshold] = 150 # Cumulative risk score before blocking
81
+ # config.waf[:violation_window] = 6.hours # Maximum time window to track violations
82
+ # config.waf[:block_durations] = [1.hour, 6.hours, 24.hours, 7.days] # Escalating durations
83
+ # config.waf[:permanent_block_after] = 500 # Permanent block when cumulative score reaches this
84
+ # config.waf[:create_security_events] = true # Create SecurityEvent records
85
+ #
86
+ # === Exponential Decay Configuration ===
87
+ # Violations decay over time based on severity (reduces false positives)
88
+ # config.waf[:decay_enabled] = true
89
+ # config.waf[:decay_rates] = { # Half-life in minutes
90
+ # critical: 360, # 6 hour half-life (config files, path traversal)
91
+ # high: 120, # 2 hour half-life (WordPress, PHP admin scans)
92
+ # medium: 45, # 45 minute half-life (unknown formats)
93
+ # low: 15 # 15 minute half-life (RecordNotFound/404s)
94
+ # }
95
+ # config.waf[:max_violations_tracked] = 50 # Maximum violations to track per IP
96
+ #
97
+ # === RecordNotFound Exclusions ===
98
+ # Exclude legitimate 404-prone paths from triggering violations
99
+ # config.waf[:record_not_found_exclusions] = [
100
+ # %r{/posts/.*}, # Blog posts with slugs
101
+ # %r{/products/[\w-]+}, # Product URLs with slugs
102
+ # %r{/public/.*} # Public content
103
+ # ]
104
+ #
105
+ # === Pre-configured Profiles ===
106
+ # See WAF_CONFIGURATION_PROFILES.md for complete profile examples:
107
+ # - STRICT: score_threshold = 100 (high-security)
108
+ # - BALANCED: score_threshold = 150 (recommended default)
109
+ # - PERMISSIVE: score_threshold = 200 (high-traffic sites)
110
+
111
+ # ============================================================================
112
+ # SECURITY TRACKING
113
+ # ============================================================================
114
+ # Security tracking is enabled by default. To disable or customize:
115
+ # config.security_tracking[:enabled] = false
116
+ # config.security_tracking[:track_successful_logins] = true
117
+ # config.security_tracking[:track_failed_logins] = true
118
+ # config.security_tracking[:auto_analyze_patterns] = true
119
+
120
+ # ============================================================================
121
+ # RATE LIMITING
122
+ # ============================================================================
123
+ # Rate limiting is configured by default. To customize:
124
+ # config.rate_limiting[:ip_attempts][:limit] = 10
125
+ # config.rate_limiting[:ip_attempts][:period] = 1.hour
126
+ # config.rate_limiting[:ip_attempts][:exponential_backoff] = true
127
+ #
128
+ # config.rate_limiting[:account_attempts][:limit] = 5
129
+ # config.rate_limiting[:account_attempts][:period] = 15.minutes
130
+ # config.rate_limiting[:account_attempts][:exponential_backoff] = true
131
+ #
132
+ # config.rate_limiting[:global_attempts][:limit] = 100
133
+ # config.rate_limiting[:global_attempts][:period] = 1.minute
134
+ # config.rate_limiting[:global_attempts][:exponential_backoff] = false
135
+
136
+ # ============================================================================
137
+ # RISK-BASED ACCOUNT LOCKING
138
+ # ============================================================================
139
+ # Risk-based locking is disabled by default. To enable:
140
+ # config.risk_based_locking[:enabled] = true
141
+ # config.risk_based_locking[:immediate_signout] = false # Sign out users immediately when locked
142
+ # config.risk_based_locking[:risk_threshold] = 75 # Risk score threshold for locking
143
+ # config.risk_based_locking[:auto_unlock_time] = 1.hour # How long to lock the account
144
+ # config.risk_based_locking[:notify_user] = true # Notify user on lock
145
+ # config.risk_based_locking[:log_lock_events] = true # Log lock events
146
+
147
+ # ============================================================================
148
+ # GEOLOCATION
149
+ # ============================================================================
150
+ # Geolocation uses a mock provider by default. To use MaxMind:
151
+ # 1. Download GeoLite2-City database from maxmind.com
152
+ # 2. Place it in config/GeoLite2-City.mmdb
153
+ # 3. Configure:
154
+ # config.geolocation[:provider] = :maxmind
155
+ # config.geolocation[:maxmind_city_db_path] = Rails.root.join('config', 'GeoLite2-City.mmdb').to_s
156
+ # config.geolocation[:cache_ttl] = 4.hours
157
+
158
+ # ============================================================================
159
+ # AUTHENTICATION MODELS
160
+ # ============================================================================
161
+ # Authentication models are auto-detected by default. To customize:
162
+ # config.authentication_models[:auto_detect] = false # Disable auto-detection
163
+ # config.authentication_models[:devise] = [:user, :admin]
164
+ # config.authentication_models[:rails_auth] = [:customer]
165
+
166
+ # ============================================================================
167
+ # EMERGENCY PASSWORD RESET
168
+ # ============================================================================
169
+ # Emergency password reset is disabled by default. To enable:
170
+ # config.emergency_password_reset[:enabled] = true
171
+ # config.emergency_password_reset[:impossible_travel_threshold] = 3
172
+ # config.emergency_password_reset[:suspicious_device_threshold] = 5
173
+ # config.emergency_password_reset[:total_locks_threshold] = 5
174
+ # config.emergency_password_reset[:send_notification] = true
175
+ # config.emergency_password_reset[:notify_security_team] = true
176
+ # config.emergency_password_reset[:require_manual_unlock] = false
177
+ end
@@ -37,8 +37,17 @@ namespace :beskar do
37
37
  end
38
38
 
39
39
  puts "📝 Creating initializer..."
40
- template_path = File.expand_path("../beskar/templates/beskar_initializer.rb", __dir__)
41
- FileUtils.cp(template_path, initializer_path)
40
+ template_path = File.expand_path("../generators/beskar/install/templates/initializer.rb.tt", __dir__)
41
+
42
+ # Read the template and process ERB (Rails will be available in the rake task context)
43
+ template_content = File.read(template_path)
44
+ erb = ERB.new(template_content, trim_mode: '-')
45
+
46
+ # Evaluate the ERB template in a context where Rails is available
47
+ processed_content = erb.result(binding)
48
+
49
+ # Write the processed initializer
50
+ File.write(initializer_path, processed_content)
42
51
  puts "✓ Created config/initializers/beskar.rb"
43
52
  puts
44
53
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beskar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Litwiniuk
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: 8.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: csv
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: maxminddb
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +80,7 @@ dependencies:
66
80
  - !ruby/object:Gem::Version
67
81
  version: '0'
68
82
  - !ruby/object:Gem::Dependency
69
- name: ostruct
83
+ name: factory_bot_rails
70
84
  requirement: !ruby/object:Gem::Requirement
71
85
  requirements:
72
86
  - - ">="
@@ -80,7 +94,7 @@ dependencies:
80
94
  - !ruby/object:Gem::Version
81
95
  version: '0'
82
96
  - !ruby/object:Gem::Dependency
83
- name: factory_bot_rails
97
+ name: mocha
84
98
  requirement: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - ">="
@@ -94,7 +108,7 @@ dependencies:
94
108
  - !ruby/object:Gem::Version
95
109
  version: '0'
96
110
  - !ruby/object:Gem::Dependency
97
- name: mocha
111
+ name: ostruct
98
112
  requirement: !ruby/object:Gem::Requirement
99
113
  requirements:
100
114
  - - ">="
@@ -117,11 +131,15 @@ executables: []
117
131
  extensions: []
118
132
  extra_rdoc_files: []
119
133
  files:
134
+ - CHANGELOG.md
120
135
  - MIT-LICENSE
121
136
  - README.md
122
137
  - Rakefile
123
138
  - app/assets/stylesheets/beskar/application.css
124
139
  - app/controllers/beskar/application_controller.rb
140
+ - app/controllers/beskar/banned_ips_controller.rb
141
+ - app/controllers/beskar/dashboard_controller.rb
142
+ - app/controllers/beskar/security_events_controller.rb
125
143
  - app/controllers/concerns/beskar/controllers/security_tracking.rb
126
144
  - app/helpers/beskar/application_helper.rb
127
145
  - app/jobs/beskar/application_job.rb
@@ -129,6 +147,14 @@ files:
129
147
  - app/models/beskar/application_record.rb
130
148
  - app/models/beskar/banned_ip.rb
131
149
  - app/models/beskar/security_event.rb
150
+ - app/services/beskar/banned_ip_manager.rb
151
+ - app/views/beskar/banned_ips/edit.html.erb
152
+ - app/views/beskar/banned_ips/index.html.erb
153
+ - app/views/beskar/banned_ips/new.html.erb
154
+ - app/views/beskar/banned_ips/show.html.erb
155
+ - app/views/beskar/dashboard/index.html.erb
156
+ - app/views/beskar/security_events/index.html.erb
157
+ - app/views/beskar/security_events/show.html.erb
132
158
  - app/views/layouts/beskar/application.html.erb
133
159
  - config/locales/en.yml
134
160
  - config/routes.rb
@@ -137,6 +163,7 @@ files:
137
163
  - lib/beskar.rb
138
164
  - lib/beskar/configuration.rb
139
165
  - lib/beskar/engine.rb
166
+ - lib/beskar/logger.rb
140
167
  - lib/beskar/middleware.rb
141
168
  - lib/beskar/middleware/request_analyzer.rb
142
169
  - lib/beskar/models/security_trackable.rb
@@ -149,8 +176,9 @@ files:
149
176
  - lib/beskar/services/ip_whitelist.rb
150
177
  - lib/beskar/services/rate_limiter.rb
151
178
  - lib/beskar/services/waf.rb
152
- - lib/beskar/templates/beskar_initializer.rb
153
179
  - lib/beskar/version.rb
180
+ - lib/generators/beskar/install/install_generator.rb
181
+ - lib/generators/beskar/install/templates/initializer.rb.tt
154
182
  - lib/tasks/beskar_tasks.rake
155
183
  homepage: https://humadroid.io/beskar
156
184
  licenses:
@@ -158,6 +186,7 @@ licenses:
158
186
  metadata:
159
187
  homepage_uri: https://humadroid.io/beskar
160
188
  source_code_uri: https://github.com/humadroid-io/beskar
189
+ changelog_uri: https://github.com/humadroid-io/beskar/blob/master/CHANGELOG.md
161
190
  rdoc_options: []
162
191
  require_paths:
163
192
  - lib
@@ -172,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
201
  - !ruby/object:Gem::Version
173
202
  version: '0'
174
203
  requirements: []
175
- rubygems_version: 3.7.2
204
+ rubygems_version: 3.6.9
176
205
  specification_version: 4
177
206
  summary: An all-in-one security engine for Rails providing WAF, bot detection, and
178
207
  account takeover prevention.
@@ -1,107 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Beskar.configure do |config|
4
- # ============================================================================
5
- # Web Application Firewall (WAF) - ENABLED IN MONITOR MODE BY DEFAULT
6
- # ============================================================================
7
- # Detects and logs vulnerability scanning attempts (WordPress, phpMyAdmin, etc.)
8
- # Start in monitor-only mode to observe patterns before enabling blocking.
9
- #
10
- config.waf = {
11
- enabled: true, # Master switch for WAF
12
- monitor_only: true, # LOG ONLY - does not block (recommended to start)
13
- auto_block: true, # Auto-block IPs after threshold (when monitor_only=false)
14
- block_threshold: 3, # Number of violations before blocking
15
- violation_window: 1.hour, # Time window for counting violations
16
- block_durations: [1.hour, 6.hours, 24.hours, 7.days], # Escalating ban durations
17
- permanent_block_after: 5, # Permanent ban after N violations (nil = never)
18
- create_security_events: true # Log violations to SecurityEvent table
19
- }
20
-
21
- # After monitoring for 24-48 hours, review logs and disable monitor_only:
22
- # config.waf[:monitor_only] = false
23
-
24
- # View WAF activity in logs:
25
- # tail -f log/production.log | grep "Beskar::WAF"
26
-
27
- # Query violations that would be blocked:
28
- # Beskar::SecurityEvent.where(event_type: 'waf_violation')
29
- # .where("metadata->>'would_be_blocked' = ?", 'true').count
30
-
31
- # ============================================================================
32
- # IP Whitelisting (RECOMMENDED)
33
- # ============================================================================
34
- # Trusted IPs bypass all blocking (bans, rate limits, WAF) while still
35
- # logging activity for audit purposes.
36
- #
37
- # config.ip_whitelist = [
38
- # "192.168.1.100", # Single IP address
39
- # "10.0.0.0/24", # CIDR notation - entire subnet
40
- # "172.16.0.0/16" # Larger CIDR range
41
- # # Add your office IPs, monitoring services, trusted partners, etc.
42
- # ]
43
-
44
- # ============================================================================
45
- # Security Event Tracking (OPTIONAL)
46
- # ============================================================================
47
- # Track authentication events for risk analysis and threat detection.
48
- # Disable if you don't need historical security event data.
49
- #
50
- # config.security_tracking = {
51
- # enabled: true, # Master switch for all tracking
52
- # track_successful_logins: true, # Track successful authentications
53
- # track_failed_logins: true, # Track failed authentication attempts
54
- # auto_analyze_patterns: true # Enable automatic pattern analysis
55
- # }
56
-
57
- # ============================================================================
58
- # Rate Limiting (OPTIONAL)
59
- # ============================================================================
60
- # Protect against brute force attacks by limiting authentication attempts.
61
- #
62
- # config.rate_limiting = {
63
- # ip_attempts: {
64
- # limit: 10, # Max attempts per IP
65
- # period: 1.hour, # Time window
66
- # exponential_backoff: true # Increase delay after each attempt
67
- # },
68
- # account_attempts: {
69
- # limit: 5, # Max attempts per account
70
- # period: 15.minutes,
71
- # exponential_backoff: true
72
- # },
73
- # global_attempts: {
74
- # limit: 100, # System-wide limit (DDoS protection)
75
- # period: 1.minute,
76
- # exponential_backoff: false
77
- # }
78
- # }
79
-
80
- # ============================================================================
81
- # Risk-Based Account Locking (OPTIONAL)
82
- # ============================================================================
83
- # Automatically lock accounts when authentication risk score is too high.
84
- # Requires Devise :lockable module.
85
- #
86
- # config.risk_based_locking = {
87
- # enabled: false, # Disabled by default
88
- # risk_threshold: 75, # Lock if risk score >= this (0-100)
89
- # lock_strategy: :devise_lockable, # Strategy: :devise_lockable, :custom, :none
90
- # auto_unlock_time: 1.hour, # Time until automatic unlock
91
- # notify_user: true, # Send notification on lock
92
- # log_lock_events: true # Create security events for locks
93
- # }
94
-
95
- # ============================================================================
96
- # IP Geolocation (OPTIONAL)
97
- # ============================================================================
98
- # Enhance risk assessment with geographic information.
99
- # Requires MaxMind GeoLite2-City database (free with registration).
100
- # Download from: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
101
- #
102
- # config.geolocation = {
103
- # provider: :maxmind,
104
- # maxmind_city_db_path: Rails.root.join('db', 'geoip', 'GeoLite2-City.mmdb').to_s,
105
- # cache_ttl: 4.hours
106
- # }
107
- end