validators 3.0.5 → 3.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.
@@ -0,0 +1,27 @@
1
+ ---
2
+ en:
3
+ activemodel: &activemodel
4
+ errors:
5
+ messages:
6
+ disposable_email: "is not allowed (high-bounce domain)"
7
+ invalid_cnpj: "is not a valid CNPJ"
8
+ invalid_cpf: "is not a valid CPF"
9
+ invalid_date: "is not a valid date"
10
+ invalid_date_after: "needs to be after %{date}"
11
+ invalid_date_before: "needs to be before %{date}"
12
+ invalid_email: "is not a valid address"
13
+ invalid_hostname: "does not have a valid hostname"
14
+ invalid_ip_address: "is not a valid IP address"
15
+ invalid_ipv4_address: "is not a valid IPv4 address"
16
+ invalid_ipv6_address: "is not a valid IPv6 address"
17
+ invalid_owner: "is not associated with your user"
18
+ invalid_ssh_private_key: "is not a valid private SSH key"
19
+ invalid_ssh_private_key_bits: "needs to be at least %{required} bits; got %{value} bits instead"
20
+ invalid_ssh_private_key_type: "must be a %{value} key"
21
+ invalid_ssh_public_key: "is not a valid public SSH key"
22
+ invalid_url: "is not a valid address"
23
+ reserved_hostname: "%{value} is a reserved hostname"
24
+ reserved_username: "%{value} is a reserved username"
25
+
26
+ activerecord:
27
+ <<: *activemodel
@@ -0,0 +1,27 @@
1
+ ---
2
+ pt-BR:
3
+ activemodel: &activemodel
4
+ errors:
5
+ messages:
6
+ disposable_email: "não é permitido (e-mail temporário)"
7
+ invalid_cnpj: "não é um CNPJ válido"
8
+ invalid_cpf: "não é um CPF válido"
9
+ invalid_date: "não é uma data válida"
10
+ invalid_date_after: "precisa ser depois de %{date}"
11
+ invalid_date_before: "precisa ser antes de %{date}"
12
+ invalid_email: "não parece ser um e-mail válido"
13
+ invalid_hostname: "não é um hostname válido"
14
+ invalid_ip_address: "não é um endereço IP válido"
15
+ invalid_ipv4_address: "não é um endereço IPv4 válido"
16
+ invalid_ipv6_address: "não é um endereço IPv6 válido"
17
+ invalid_owner: "não está associado ao seu usuário"
18
+ invalid_ssh_private_key: "não é uma chave privada de SSH válida"
19
+ invalid_ssh_private_key_bits: "precisa ter pelo menos %{required} bits; a sua chave tem %{value} bits"
20
+ invalid_ssh_private_key_type: "precisa ser uma chave %{value}"
21
+ invalid_ssh_public_key: "não é uma chave pública de SSH válida"
22
+ invalid_url: "não parece ser uma URL válida"
23
+ reserved_hostname: "%{value} é um hostname reservado"
24
+ reserved_username: "%{value} é nome de usuário reservado"
25
+
26
+ activerecord:
27
+ <<: *activemodel
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validators
4
+ class ReservedHostnames
5
+ FILE_PATH = File.expand_path("../../data/reserved_hostnames.json", __dir__)
6
+
7
+ def self.reserved?(hostname, matchers = nil)
8
+ matchers = parse_list(matchers) if matchers
9
+ matchers ||= all
10
+ match_any?(matchers, hostname)
11
+ end
12
+
13
+ def self.all
14
+ @all ||= JSON
15
+ .parse(File.read(FILE_PATH))
16
+ .map {|matcher| parse(matcher) }
17
+ end
18
+
19
+ def self.parse(matcher)
20
+ return matcher unless matcher.start_with?("/")
21
+
22
+ Regexp.compile(matcher[%r{/(.*?)/}, 1])
23
+ end
24
+
25
+ def self.parse_list(matchers)
26
+ matchers.map {|matcher| parse(matcher) }
27
+ end
28
+
29
+ def self.match_any?(matchers, hostname)
30
+ hostname = normalize(hostname)
31
+ matchers.any? {|matcher| match?(matcher, hostname) }
32
+ end
33
+
34
+ def self.normalize(hostname)
35
+ hostname.downcase.gsub(/[_-]/, "")
36
+ end
37
+
38
+ def self.match?(matcher, hostname)
39
+ case matcher
40
+ when String
41
+ matcher == hostname
42
+ when Regexp
43
+ hostname =~ matcher
44
+ else
45
+ raise "Unknown matcher type: #{matcher.class}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class ReservedHostnameValidator < EachValidator
6
+ def validate_each(record, attribute, value)
7
+ return if value.blank? && options[:allow_blank]
8
+ return if value.nil? && options[:allow_nil]
9
+ return unless reserved?(value.to_s)
10
+
11
+ record.errors.add(
12
+ attribute,
13
+ :"reserved_#{options[:error_name]}",
14
+ message: options[:message],
15
+ value: value
16
+ )
17
+ end
18
+
19
+ def reserved?(subdomain)
20
+ ::Validators::ReservedHostnames.reserved?(subdomain, options[:in])
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ # Validates whether or not the specified hostname is valid.
26
+ # The `in: array` can have strings and patterns. A pattern is everything
27
+ # that starts with `/` and will be parsed as a regular expression.
28
+ #
29
+ # Notice that subdomains will be normalized; it'll be downcased and have
30
+ # its underscores and hyphens stripped.
31
+ #
32
+ # class User < ActiveRecord::Base
33
+ # validates_reserved_hostname :site
34
+ #
35
+ # # Validates against a custom list.
36
+ # validates_reserved_hostname :site, in: %w[www]
37
+ # end
38
+ #
39
+ def validates_reserved_hostname(*attr_names)
40
+ options = _merge_attributes(attr_names).merge(error_name: :hostname)
41
+ validates_with ReservedHostnameValidator, options
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Validations
5
+ class ReservedUsernameValidator < ReservedHostnameValidator
6
+ end
7
+
8
+ module ClassMethods
9
+ # Validates whether or not the specified username is valid.
10
+ # The `in: array` can have strings and patterns. A pattern is everything
11
+ # that starts with `/` and will be parsed as a regular expression.
12
+ #
13
+ # Notice that subdomains will be normalized; it'll be downcased and have
14
+ # its underscores and hyphens stripped.
15
+ #
16
+ # class User < ActiveRecord::Base
17
+ # validates_reserved_hostname :site
18
+ #
19
+ # # Validates against a custom list.
20
+ # validates_reserved_hostname :site, in: %w[www]
21
+ # end
22
+ #
23
+ def validates_reserved_username(*attr_names)
24
+ options = _merge_attributes(attr_names).merge(error_name: :username)
25
+ validates_with ReservedHostnameValidator, options
26
+ end
27
+ end
28
+ end
29
+ end
@@ -3,8 +3,8 @@
3
3
  module Validators
4
4
  module Version
5
5
  MAJOR = 3
6
- MINOR = 0
7
- PATCH = 5
6
+ MINOR = 1
7
+ PATCH = 0
8
8
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
9
9
  end
10
10
  end
data/lib/validators.rb CHANGED
@@ -8,6 +8,8 @@ module Validators
8
8
  require "validators/tld"
9
9
  require "validators/hostname"
10
10
  require "validators/disposable_hostnames"
11
+ require "validators/reserved_hostnames"
12
+
11
13
  require "validators/validates_datetime"
12
14
  require "validators/validates_ip_address"
13
15
  require "validators/validates_email_format_of"
@@ -18,4 +20,8 @@ module Validators
18
20
  require "validators/validates_ssh_private_key"
19
21
  require "validators/validates_ssh_public_key"
20
22
  require "validators/validates_hostname_format_of"
23
+ require "validators/validates_reserved_hostname"
24
+ require "validators/validates_reserved_username"
25
+
26
+ I18n.load_path += Dir[File.join(__dir__, "validators/locale/*.yml")]
21
27
  end
@@ -1,5 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ def build_model(&block)
4
+ Class.new do
5
+ include ActiveModel::Model
6
+
7
+ def self.name
8
+ "SomeModel"
9
+ end
10
+
11
+ instance_eval(&block)
12
+ end
13
+ end
14
+
3
15
  class User < ActiveRecord::Base
4
16
  has_many :tasks
5
17
  has_many :categories
data/test/test_helper.rb CHANGED
@@ -1,16 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "simplecov"
4
- require "simplecov-console"
5
-
6
- SimpleCov.minimum_coverage 100
7
- SimpleCov.minimum_coverage_by_file 100
8
- SimpleCov.refuse_coverage_drop
3
+ $VERBOSE = nil
9
4
 
10
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
11
- SimpleCov::Formatter::Console,
12
- SimpleCov::Formatter::HTMLFormatter
13
- ])
5
+ require "simplecov"
6
+ SimpleCov.start
14
7
 
15
8
  SimpleCov.start do
16
9
  add_filter "test/support"
@@ -33,9 +26,6 @@ Dir[File.join(__dir__, "support/**/*.rb")].sort.each {|f| require f }
33
26
  ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
34
27
  load "schema.rb"
35
28
 
36
- I18n.enforce_available_locales = false
37
- I18n.load_path << File.join(__dir__, "support/translations.yml")
38
-
39
29
  module Minitest
40
30
  class Test
41
31
  setup do
@@ -21,7 +21,8 @@ class DisposableEmailTest < Minitest::Test
21
21
  user = User.new(email: "user@custom.#{domain}")
22
22
  user.valid?
23
23
 
24
- assert_includes user.errors[:email], I18n.t("activerecord.errors.messages.disposable_email")
24
+ assert_includes user.errors[:email],
25
+ "is not allowed (high-bounce domain)"
25
26
  end
26
27
  end
27
28
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class ValidatesReservedHostnameTest < Minitest::Test
6
+ test "rejects reserved hostname" do
7
+ model = build_model do
8
+ attr_accessor :hostname
9
+ validates_reserved_hostname :hostname
10
+ end
11
+
12
+ instance = model.new(hostname: "www")
13
+
14
+ refute instance.valid?
15
+ assert_includes instance.errors[:hostname],
16
+ "www is a reserved hostname"
17
+ end
18
+
19
+ test "rejects reserved hostname with pattern" do
20
+ model = build_model do
21
+ attr_accessor :hostname
22
+ validates_reserved_hostname :hostname
23
+ end
24
+
25
+ instance = model.new(hostname: "www1234")
26
+
27
+ refute instance.valid?
28
+ end
29
+
30
+ test "uses custom list" do
31
+ model = build_model do
32
+ attr_accessor :hostname
33
+ validates_reserved_hostname :hostname, in: %w[nope]
34
+ end
35
+
36
+ instance = model.new(hostname: "nope")
37
+
38
+ refute instance.valid?
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class ValidatesReservedUsernameTest < Minitest::Test
6
+ test "rejects reserved username" do
7
+ model = build_model do
8
+ attr_accessor :username
9
+ validates_reserved_username :username
10
+ end
11
+
12
+ instance = model.new(username: "www")
13
+
14
+ refute instance.valid?
15
+ assert_includes instance.errors[:username],
16
+ "www is a reserved username"
17
+ end
18
+
19
+ test "rejects reserved username with pattern" do
20
+ model = build_model do
21
+ attr_accessor :username
22
+ validates_reserved_username :username
23
+ end
24
+
25
+ instance = model.new(username: "www1234")
26
+
27
+ refute instance.valid?
28
+ end
29
+
30
+ test "uses custom list" do
31
+ model = build_model do
32
+ attr_accessor :username
33
+ validates_reserved_username :username, in: %w[nope]
34
+ end
35
+
36
+ instance = model.new(username: "nope")
37
+
38
+ refute instance.valid?
39
+ end
40
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validators
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.5
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-19 00:00:00.000000000 Z
11
+ date: 2020-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -196,12 +196,16 @@ files:
196
196
  - bin/sync-disposable-hostnames
197
197
  - bin/sync-tld
198
198
  - data/disposable.json
199
+ - data/reserved_hostnames.json
199
200
  - data/tld.json
200
201
  - lib/validators.rb
201
202
  - lib/validators/constants.rb
202
203
  - lib/validators/disposable_hostnames.rb
203
204
  - lib/validators/hostname.rb
204
205
  - lib/validators/ip.rb
206
+ - lib/validators/locale/en.yml
207
+ - lib/validators/locale/pt-BR.yml
208
+ - lib/validators/reserved_hostnames.rb
205
209
  - lib/validators/tld.rb
206
210
  - lib/validators/validates_cnpj_format_of.rb
207
211
  - lib/validators/validates_cpf_format_of.rb
@@ -210,6 +214,8 @@ files:
210
214
  - lib/validators/validates_hostname_format_of.rb
211
215
  - lib/validators/validates_ip_address.rb
212
216
  - lib/validators/validates_ownership_of.rb
217
+ - lib/validators/validates_reserved_hostname.rb
218
+ - lib/validators/validates_reserved_username.rb
213
219
  - lib/validators/validates_ssh_private_key.rb
214
220
  - lib/validators/validates_ssh_public_key.rb
215
221
  - lib/validators/validates_url_format_of.rb
@@ -220,7 +226,6 @@ files:
220
226
  - test/support/hostnames.rb
221
227
  - test/support/ips.rb
222
228
  - test/support/models.rb
223
- - test/support/translations.yml
224
229
  - test/support/urls.rb
225
230
  - test/test_helper.rb
226
231
  - test/validators/disposable_email_test.rb
@@ -237,6 +242,8 @@ files:
237
242
  - test/validators/validates_ip_address/ipv6_test.rb
238
243
  - test/validators/validates_ip_address_test.rb
239
244
  - test/validators/validates_ownership_of_test.rb
245
+ - test/validators/validates_reserved_hostname_test.rb
246
+ - test/validators/validates_reserved_username_test.rb
240
247
  - test/validators/validates_ssh_private_key/bits_test.rb
241
248
  - test/validators/validates_ssh_private_key/common_test.rb
242
249
  - test/validators/validates_ssh_private_key/dsa_test.rb
@@ -275,7 +282,6 @@ test_files:
275
282
  - test/support/hostnames.rb
276
283
  - test/support/ips.rb
277
284
  - test/support/models.rb
278
- - test/support/translations.yml
279
285
  - test/support/urls.rb
280
286
  - test/test_helper.rb
281
287
  - test/validators/disposable_email_test.rb
@@ -292,6 +298,8 @@ test_files:
292
298
  - test/validators/validates_ip_address/ipv6_test.rb
293
299
  - test/validators/validates_ip_address_test.rb
294
300
  - test/validators/validates_ownership_of_test.rb
301
+ - test/validators/validates_reserved_hostname_test.rb
302
+ - test/validators/validates_reserved_username_test.rb
295
303
  - test/validators/validates_ssh_private_key/bits_test.rb
296
304
  - test/validators/validates_ssh_private_key/common_test.rb
297
305
  - test/validators/validates_ssh_private_key/dsa_test.rb
@@ -1,39 +0,0 @@
1
- en:
2
- activerecord: &activerecord
3
- errors:
4
- messages:
5
- record_invalid: "Errors: %{errors}"
6
- invalid_date: "is not a valid date"
7
- invalid_date_before: "needs to be before %{date}"
8
- invalid_date_after: "needs to be after %{date}"
9
- invalid_email: "is not a valid address"
10
- invalid_url: "is not a valid address"
11
- invalid_ipv4_address: "is not a valid IPv4 address"
12
- invalid_ipv6_address: "is not a valid IPv6 address"
13
- invalid_address: "is not a valid IP address"
14
- invalid_owner: "is not associated with your user"
15
- invalid_cpf: "is not a valid CPF"
16
- invalid_cnpj: "is not a valid CNPJ"
17
- disposable_email: "is not allowed (high-bounce domain)"
18
- invalid_hostname: "does not have a valid hostname"
19
-
20
- activemodel:
21
- <<: *activerecord
22
-
23
- pt-BR:
24
- activerecord: &activerecord
25
- errors:
26
- messages:
27
- record_invalid: "Erros: %{errors}"
28
- invalid_email: "não parece ser um e-mail válido"
29
- invalid_url: "não parece ser uma URL válida"
30
- invalid_owner: "não está associado ao seu usuário"
31
- invalid_cpf: "não é um CPF válido"
32
- invalid_cnpj: "não é um CNPJ válido"
33
- invalid_ssh_public_key: "não é uma chave pública de SSH válida"
34
- invalid_ssh_private_key: "não é uma chave privada de SSH válida"
35
- invalid_ssh_private_key_type: "precisa ser uma chave %{value}"
36
- invalid_ssh_private_key_bits: "precisa ter pelo menos %{required} bits; a sua chave tem %{value} bits"
37
-
38
- activemodel:
39
- <<: *activerecord