mini_defender 0.6.5 → 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12e38770ec94ea06cf7c9a6f40af0cc37fc2017deb30161c2804c9e3024d7ad4
4
- data.tar.gz: 36738ff2ca0ad2316dbb0f68fee90ad921690fab463cf4050103789edb975212
3
+ metadata.gz: 3bae6fdb0faacfd54fe463d30f80710e40d383bd868d64e65da7243bae0c5b1c
4
+ data.tar.gz: f9cf13d8acbc654b9c647c33b322937722b97f0a99b8d389d4311002a3a5a65e
5
5
  SHA512:
6
- metadata.gz: 94d2291d0f17296b246ae67f96685f20dd7c7316d7ed329d89fc2141d76af57c538ca3909b52be177b9d08663448c2941669668861ba0408d40bdb10f75ad462
7
- data.tar.gz: d5f5aab2a675b44ce991573938eea9ca9782e954971365d71102ba6e8081b802d76cffa4f3382354bbf04695028e88cede5686146c28003ef1c1ee4f8f33e30a
6
+ metadata.gz: 2c50350da6f341f0487357cf63cad4dbf070c5c8f89614344619182dffd9b7f345b3015466e185fe4114cadcd2a3f7159bbf87e7413bd0d887327cdb13cebbce
7
+ data.tar.gz: 8bb5e5e2702c985a7c3933147d0db5f59abde4e566f8747aa6158d21fb5bd440dcf6f1d8706ae0846e0532a14d918d2b36d04673f519d98c72412b480c25fef4
@@ -0,0 +1,64 @@
1
+ # RFC 2606 - Reserved Domain Names
2
+ # https://datatracker.ietf.org/doc/html/rfc2606
3
+ *.test
4
+ *.example
5
+ *.invalid
6
+ localhost
7
+ *.localhost
8
+ example.com
9
+ example.net
10
+ example.org
11
+
12
+ # RFC 6761 - Special-Use Domain Names
13
+ # https://datatracker.ietf.org/doc/html/rfc6761
14
+ *.local
15
+ *.onion
16
+ *.home.arpa
17
+
18
+ # RFC 1918 - Private Address Space
19
+ # https://datatracker.ietf.org/doc/html/rfc1918
20
+ 10.*
21
+ 172.(1[6-9]|2[0-9]|3[0-1]).*
22
+ 192.168.*
23
+
24
+ # RFC 3330 - Special-Use IPv4 Addresses
25
+ # https://datatracker.ietf.org/doc/html/rfc3330
26
+ 127.*
27
+ 169.254.*
28
+ 0.0.0.0
29
+
30
+ # RFC 4291 - IPv6 Addressing Architecture
31
+ # https://datatracker.ietf.org/doc/html/rfc4291
32
+ ::1
33
+ fe80:*
34
+ ::
35
+ ::ffff:*
36
+
37
+ # RFC 4193 - Unique Local IPv6 Unicast Addresses
38
+ # https://datatracker.ietf.org/doc/html/rfc4193
39
+ fc00:*
40
+ fd00:*
41
+
42
+ # Common Internal Network Patterns (based on RFC 2606 and 6761)
43
+ *.intranet
44
+ *.internal
45
+ *.corp
46
+ *.lan
47
+ intranet.*
48
+ internal.*
49
+ corp.*
50
+ lan.*
51
+
52
+ # Development Environments (based on RFC 2606)
53
+ *.dev.test
54
+ *.staging.test
55
+ *.qa.test
56
+ dev.example.*
57
+ staging.example.*
58
+ qa.example.*
59
+
60
+ # RFC 6052 - IPv6 Translation
61
+ 64:ff9b::*
62
+
63
+ # RFC 3986 - URI Encoded Forms
64
+ %6C%6F%63%61%6C%68%6F%73%74
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'action_dispatch'
4
+ require 'marcel'
4
5
 
5
6
  class MiniDefender::Rules::Image < MiniDefender::Rule
6
7
  MIMES = %w[image/jpeg image/png image/gif image/bmp image/png image/svg+xml image/webp]
@@ -10,7 +11,10 @@ class MiniDefender::Rules::Image < MiniDefender::Rule
10
11
  end
11
12
 
12
13
  def passes?(attribute, value, validator)
13
- value.is_a?(ActionDispatch::Http::UploadedFile) && MIMES.include?(value.content_type)
14
+ content_type = Marcel::MimeType.for(value.read)
15
+ value.rewind
16
+
17
+ value.is_a?(ActionDispatch::Http::UploadedFile) && MIMES.include?(content_type)
14
18
  end
15
19
 
16
20
  def message(attribute, value, validator)
@@ -54,9 +54,10 @@ class MiniDefender::Rules::Integer < MiniDefender::Rule
54
54
  end
55
55
 
56
56
  # Remove leading zero so Integer will not treat it as octal
57
+ # Handle leading zeros while preserving both + and - signs
57
58
  value = value
58
59
  .to_s
59
- .gsub(/^0+/, '')
60
+ .gsub(/^([+-])?0+(?=\d)/, '\1')
60
61
 
61
62
  if @mode == 'relaxed'
62
63
  value = normalize_digits(value)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'action_dispatch'
4
+ require 'marcel'
4
5
 
5
6
  class MiniDefender::Rules::MimeTypes < MiniDefender::Rule
6
7
  def initialize(types)
@@ -26,7 +27,10 @@ class MiniDefender::Rules::MimeTypes < MiniDefender::Rule
26
27
 
27
28
  def passes?(attribute, value, validator)
28
29
  @file = value.is_a?(ActionDispatch::Http::UploadedFile)
29
- @file && @types.include?(value.content_type)
30
+ content_type = Marcel::MimeType.for(value.read)
31
+ value.rewind
32
+
33
+ @file && @types.include?(content_type)
30
34
  end
31
35
 
32
36
  def message(attribute, value, validator)
@@ -1,17 +1,140 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'uri'
4
+ require 'ipaddr'
5
+ require 'public_suffix'
4
6
 
5
7
  class MiniDefender::Rules::Url < MiniDefender::Rule
8
+ ALLOWED_MODIFIERS = %w[https public not_ip not_private]
9
+
10
+ def initialize(modifiers = [])
11
+ @modifiers = Array(modifiers).map(&:to_s)
12
+
13
+ unless @modifiers.empty?
14
+ validate_modifiers!
15
+ end
16
+
17
+ @validation_error = nil
18
+ end
19
+
6
20
  def self.signature
7
21
  'url'
8
22
  end
9
23
 
24
+ def self.make(modifiers) # no need to raise an error when no modifier is entered; as 'url' rule checks URL structure on its own
25
+ new(modifiers)
26
+ end
27
+
10
28
  def passes?(attribute, value, validator)
11
- value.is_a?(String) && URI.regexp(%w[http https]).match?(value)
29
+ unless value.is_a?(String)
30
+ return false
31
+ end
32
+
33
+ begin
34
+ uri = URI.parse(value)
35
+
36
+ if uri.host.blank? || uri.scheme.blank?
37
+ return false
38
+ end
39
+
40
+ unless %w[http https].include?(uri.scheme)
41
+ @validation_error = 'URL protocol must be HTTP or HTTPS.'
42
+ return false
43
+ end
44
+
45
+ if @modifiers.empty?
46
+ return true
47
+ end
48
+
49
+ if @modifiers.include?('https') && uri.scheme != 'https'
50
+ @validation_error = 'The URL must use HTTPS.'
51
+ return false
52
+ end
53
+
54
+ if @modifiers.include?('public') && (!PublicSuffix.valid?(uri.host) || private_network?(uri.host))
55
+ @validation_error = 'The URL must use a valid public domain.'
56
+ return false
57
+ end
58
+
59
+ if @modifiers.include?('not_ip') && ip_address?(uri.host)
60
+ @validation_error = 'IP addresses are not allowed in URLs.'
61
+ return false
62
+ end
63
+
64
+ if @modifiers.include?('not_private') && private_network?(uri.host)
65
+ @validation_error = 'Private or reserved resources are not allowed.'
66
+ return false
67
+ end
68
+
69
+ true
70
+ rescue URI::InvalidURIError
71
+ @validation_error = 'The field must contain a valid URL.'
72
+ false
73
+ rescue PublicSuffix::Error
74
+ false
75
+ end
12
76
  end
13
77
 
14
78
  def message(attribute, value, validator)
15
- 'The field must contain a valid URL.'
79
+ @validation_error || 'The field must contain a valid URL.'
80
+ end
81
+
82
+ def private_network?(host)
83
+ unless host
84
+ return false
85
+ end
86
+
87
+ host = host.downcase
88
+
89
+ private_patterns.any? { |pattern| pattern.match?(host) }
90
+ end
91
+
92
+ private
93
+
94
+ def validate_modifiers!
95
+ invalid_modifiers = @modifiers - ALLOWED_MODIFIERS
96
+ if invalid_modifiers.empty?
97
+ return
98
+ end
99
+
100
+ raise ArgumentError, "Invalid URL modifiers: #{invalid_modifiers.join(', ')}"
101
+ end
102
+
103
+ def ip_address?(host)
104
+ unless host
105
+ return false
106
+ end
107
+
108
+ begin
109
+ IPAddr.new(host)
110
+ true
111
+ rescue IPAddr::InvalidAddressError
112
+ false
113
+ end
114
+ end
115
+
116
+ def private_patterns
117
+ # Cache the result in class variable to avoid loading again
118
+ # across multiple instances
119
+ @@private_patterns ||= begin
120
+ pattern_file = File.expand_path('../data/private_network_patterns.txt', __dir__)
121
+
122
+ File.readlines(pattern_file).filter_map do |line|
123
+ line = line.strip
124
+
125
+ if line.empty? || line.start_with?('#')
126
+ next
127
+ end
128
+
129
+ # Pattern => regex (once)
130
+ pattern = line
131
+ .gsub('.', '\.') # escape dots
132
+ .gsub('*', '.*') # wildcards => regex
133
+ .gsub('[0-9]+', '\d+') # convert number ranges
134
+ .gsub(/\[(.+?)\]/, '(\1)') # convert chars classes
135
+
136
+ Regexp.new("^#{pattern}$", Regexp::IGNORECASE)
137
+ end
138
+ end
16
139
  end
17
140
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniDefender
4
- VERSION = "0.6.5"
4
+ VERSION = "0.6.8"
5
5
  end
@@ -33,4 +33,6 @@ Gem::Specification.new do |spec|
33
33
  spec.add_runtime_dependency 'actionpack', '>= 6.0'
34
34
  spec.add_runtime_dependency 'countries'
35
35
  spec.add_runtime_dependency 'money'
36
+ spec.add_runtime_dependency 'marcel'
37
+ spec.add_runtime_dependency 'public_suffix'
36
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_defender
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali Alhoshaiyan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-29 00:00:00.000000000 Z
11
+ date: 2024-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: marcel
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: public_suffix
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: A small and efficient validation library for Rails and anything that
84
112
  uses Ruby.
85
113
  email:
@@ -96,6 +124,7 @@ files:
96
124
  - RULES.md
97
125
  - Rakefile
98
126
  - lib/mini_defender.rb
127
+ - lib/mini_defender/data/private_network_patterns.txt
99
128
  - lib/mini_defender/extensions/enumerable.rb
100
129
  - lib/mini_defender/handles_validation_errors.rb
101
130
  - lib/mini_defender/rule.rb
@@ -219,7 +248,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
248
  - !ruby/object:Gem::Version
220
249
  version: '0'
221
250
  requirements: []
222
- rubygems_version: 3.4.10
251
+ rubygems_version: 3.5.3
223
252
  signing_key:
224
253
  specification_version: 4
225
254
  summary: A small and efficient validation library for Rails and anything that uses