validators 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,14 @@
1
- require "validators/constants"
2
- require "validators/ip"
3
- require "validators/validates_datetime"
4
- require "validators/validates_ip_address"
5
- require "validators/validates_email_format_of"
6
- require "validators/validates_url_format_of"
7
- require "validators/validates_ownership_of"
8
- require "validators/validates_cpf_format_of"
9
- require "validators/validates_cnpj_format_of"
10
- require "validators/validates_ssh_private_key"
11
- require "validators/validates_ssh_public_key"
12
-
13
1
  module Validators
2
+ require "validators/constants"
3
+ require "validators/ip"
4
+ require "validators/validates_datetime"
5
+ require "validators/validates_ip_address"
6
+ require "validators/validates_email_format_of"
7
+ require "validators/validates_url_format_of"
8
+ require "validators/validates_ownership_of"
9
+ require "validators/validates_cpf_format_of"
10
+ require "validators/validates_cnpj_format_of"
11
+ require "validators/validates_ssh_private_key"
12
+ require "validators/validates_ssh_public_key"
13
+ require "validators/validates_hostname_format_of"
14
14
  end
@@ -14,4 +14,15 @@ module Validators
14
14
  ([/?]\S*)? # optional /whatever or ?whatever
15
15
  \z
16
16
  ]ixs
17
+
18
+ URL_FORMAT_WITHOUT_TLD_VALIDATION = %r[
19
+ \A
20
+ https?:// # http:// or https://
21
+ ([^\s:@]+:[^\s:@]*@)? # optional username:pw@
22
+ ( (([^\W_]+\.)*xn--)?[^\W_]+([-.][^\W_]+)*\..{2,}\.? | # domain (including Punycode/IDN)...
23
+ #{IPv4_PART}(\.#{IPv4_PART}){3} ) # or IPv4
24
+ (:\d{1,5})? # optional port
25
+ ([/?]\S*)? # optional /whatever or ?whatever
26
+ \z
27
+ ]ixs
17
28
  end
@@ -0,0 +1,62 @@
1
+ module ActiveModel
2
+ module Validations
3
+ class HostnameValidator < EachValidator
4
+ # Rules taken from http://www.zytrax.com/books/dns/apa/names.html
5
+ def validate_each(record, attribute, value)
6
+ return if valid_hostname?(value.to_s)
7
+
8
+ record.errors.add(attribute, :invalid_hostname,
9
+ :message => options[:message],
10
+ :value => value
11
+ )
12
+ end
13
+
14
+ def valid_hostname?(host)
15
+ host = host.to_s
16
+ uri = URI(host)
17
+
18
+ uri.host.nil? &&
19
+ uri.scheme.nil? &&
20
+ uri.fragment.nil? &&
21
+ uri.query.nil? &&
22
+ uri.path == host &&
23
+ host.split('.').all? {|label| valid_label?(label) } &&
24
+ host.size <= 255 &&
25
+ valid_tld?(host)
26
+ rescue URI::InvalidURIError
27
+ false
28
+ end
29
+
30
+ def valid_label?(label)
31
+ !label.start_with?('-') &&
32
+ !label.match(/\A\d+\z/) &&
33
+ label.match(/\A[a-z0-9-]{1,63}\z/i)
34
+ end
35
+
36
+ def valid_tld?(host)
37
+ return true unless options[:tld]
38
+ return false if host.split('.').size == 1
39
+
40
+ tld = host[/\.(.*?)$/, 1].to_s.downcase
41
+ UrlValidator.tlds.include?(tld)
42
+ end
43
+ end
44
+
45
+ module ClassMethods
46
+ # Validates whether or not the specified URL is valid.
47
+ #
48
+ # class User < ActiveRecord::Base
49
+ # validates_hostname_format_of :site
50
+ #
51
+ # # Validates against a list of valid TLD.
52
+ # validates_hostname_format_of :site, tld: true
53
+ # end
54
+ #
55
+ def validates_hostname_format_of(*attr_names)
56
+ validates_with HostnameValidator, _merge_attributes(attr_names)
57
+ end
58
+
59
+ alias_method :validates_hostname, :validates_hostname_format_of
60
+ end
61
+ end
62
+ end
@@ -1,13 +1,38 @@
1
1
  module ActiveModel
2
2
  module Validations
3
3
  class UrlValidator < EachValidator
4
+ TLD_FILE_PATH = File.expand_path('../../../data/tld.txt', __FILE__)
5
+
6
+ def self.tlds
7
+ @tld ||= File.read(TLD_FILE_PATH).lines.map(&:chomp)
8
+ end
9
+
4
10
  def validate_each(record, attribute, value)
5
- if value.to_s !~ Validators::URL_FORMAT
6
- record.errors.add(
7
- attribute, :invalid_url,
8
- :message => options[:message], :value => value
9
- )
10
- end
11
+ return if url?(value.to_s)
12
+
13
+ record.errors.add(attribute, :invalid_url,
14
+ :message => options[:message],
15
+ :value => value
16
+ )
17
+ end
18
+
19
+ def url?(url)
20
+ uri = URI(url)
21
+ regex = options[:tld] ? Validators::URL_FORMAT_WITHOUT_TLD_VALIDATION :
22
+ Validators::URL_FORMAT
23
+
24
+ uri.kind_of?(URI::HTTP) &&
25
+ url.match(regex) &&
26
+ valid_tld?(uri.host)
27
+ rescue URI::InvalidURIError
28
+ false
29
+ end
30
+
31
+ def valid_tld?(host)
32
+ return true unless options[:tld]
33
+ tld = host[/\.(.*?)$/, 1].to_s.downcase
34
+
35
+ self.class.tlds.include?(tld)
11
36
  end
12
37
  end
13
38
 
@@ -16,6 +41,9 @@ module ActiveModel
16
41
  #
17
42
  # class User < ActiveRecord::Base
18
43
  # validates_url_format_of :site
44
+ #
45
+ # # Validates against a list of valid TLD.
46
+ # validates_url_format_of :site, tld: true
19
47
  # end
20
48
  #
21
49
  def validates_url_format_of(*attr_names)
@@ -1,7 +1,7 @@
1
1
  module Validators
2
2
  module Version
3
3
  MAJOR = 2
4
- MINOR = 3
4
+ MINOR = 4
5
5
  PATCH = 0
6
6
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
  end
@@ -1,10 +1,13 @@
1
- require "bundler/setup"
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
2
3
 
4
+ require "bundler/setup"
3
5
  require "active_record"
4
6
  require "validators"
5
7
  require "active_support/all"
6
8
 
7
9
  Time.zone = "America/Sao_Paulo"
10
+ TLDs = ActiveModel::Validations::UrlValidator.tlds.sample(100)
8
11
 
9
12
  Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
10
13
 
@@ -0,0 +1,26 @@
1
+ VALID_HOSTNAMES = %W[
2
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
3
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
4
+ a-b.com
5
+ a-b-.com
6
+ a123.com
7
+ 123a.com
8
+ ABC123.com
9
+ 123ABC.com
10
+ ]
11
+
12
+ INVALID_HOSTNAMES = %W[
13
+ 192.168.42.42
14
+ a..com
15
+ #{'a'*64}.com
16
+ http://example.com
17
+ https://example.com
18
+ example.com?a=1
19
+ example.com#fragment
20
+ -example.com
21
+ 1234
22
+ example.-test.com
23
+ example.1234.com
24
+ example_domain.com
25
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
26
+ ]
@@ -20,3 +20,40 @@ end
20
20
  class Person < ActiveRecord::Base
21
21
  self.table_name = :users
22
22
  end
23
+
24
+ class UserWithTLD
25
+ include ActiveModel::Validations
26
+ attr_accessor :url
27
+
28
+ validates_url_format_of :url, tld: true
29
+
30
+ def self.name
31
+ 'User'
32
+ end
33
+
34
+ def initialize(url)
35
+ @url = url
36
+ end
37
+ end
38
+
39
+ class ServerWithoutTLD
40
+ include ActiveModel::Validations
41
+ attr_accessor :host
42
+
43
+ validates_hostname :host
44
+
45
+ def initialize(host)
46
+ @host = host
47
+ end
48
+ end
49
+
50
+ class ServerWithTLD
51
+ include ActiveModel::Validations
52
+ attr_accessor :host
53
+
54
+ validates_hostname :host, tld: true
55
+
56
+ def initialize(host)
57
+ @host = host
58
+ end
59
+ end
@@ -12,7 +12,6 @@ VALID_URLS = [
12
12
  'http://user:pass@example.com',
13
13
  'http://user:@example.com',
14
14
  'http://example.com/~user',
15
- 'http://example.xy', # Not a real TLD, but we're fine with anything of 2-6 chars
16
15
  'http://example.museum',
17
16
  'http://1.0.255.249',
18
17
  'http://1.2.3.4:80',
@@ -22,6 +21,7 @@ VALID_URLS = [
22
21
  'http://xn--rksmrgs-5wao1o.nu', # Punycode
23
22
  'http://www.xn--rksmrgs-5wao1o.nu',
24
23
  'http://foo.bar.xn--rksmrgs-5wao1o.nu',
24
+ 'http://example.xy', # Only valid TLD
25
25
  'http://example.com.', # Explicit TLD root period
26
26
  'http://example.com./foo'
27
27
  ]
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe ".validates_hostname_format_of" do
4
+ context "with TLD validation" do
5
+ it 'rejects invalid TLD' do
6
+ server = ServerWithTLD.new('example.xy')
7
+ expect(server).not_to be_valid
8
+ end
9
+
10
+ it 'rejects only host label' do
11
+ server = ServerWithTLD.new('com')
12
+ expect(server).not_to be_valid
13
+ end
14
+
15
+ TLDs.each do |tld|
16
+ it "accepts #{tld} as TLD" do
17
+ server = ServerWithTLD.new("example.#{tld}")
18
+ expect(server).to be_valid
19
+ end
20
+ end
21
+ end
22
+
23
+ context "without TLD validation" do
24
+ VALID_HOSTNAMES.each do |host|
25
+ it "accepts #{host}" do
26
+ server = ServerWithoutTLD.new(host)
27
+ expect(server).to be_valid
28
+ end
29
+ end
30
+
31
+ INVALID_HOSTNAMES.each do |host|
32
+ it "rejects #{host}" do
33
+ server = ServerWithoutTLD.new(host)
34
+ expect(server).not_to be_valid
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,38 +2,54 @@
2
2
  require "spec_helper"
3
3
 
4
4
  describe ".validates_url_format_of" do
5
- before do
6
- User.validates_url_format_of :url, :allow_blank => false
7
- end
5
+ context "validating TLD" do
6
+ it "rejects invalid TLD" do
7
+ user = UserWithTLD.new('http://example.xy')
8
+ expect(user).not_to be_valid
9
+ end
8
10
 
9
- VALID_URLS.each do |url|
10
- it "accepts #{url.inspect} as a valid url" do
11
- user = User.new(:url => url)
12
- expect(user).to be_valid
11
+ TLDs.each do |tld|
12
+ it "accepts #{tld} as TLD" do
13
+ user = UserWithTLD.new("http://example.#{tld}")
14
+ expect(user).to be_valid
15
+ end
13
16
  end
14
17
  end
15
18
 
16
- INVALID_URLS.each do |url|
17
- it "rejects #{url.inspect} as a valid url" do
18
- user = User.new(:url => url)
19
- expect(user).not_to be_valid
19
+ context "without validating TLD" do
20
+ before do
21
+ User.validates_url_format_of :url, :allow_blank => false
20
22
  end
21
- end
22
23
 
23
- it "defines alias method" do
24
- expect(User).to respond_to(:validates_url)
25
- end
24
+ VALID_URLS.each do |url|
25
+ it "accepts #{url.inspect} as a valid url" do
26
+ user = User.new(:url => url)
27
+ expect(user).to be_valid
28
+ end
29
+ end
26
30
 
27
- it "uses default error message" do
28
- user = User.new(:url => "invalid")
29
- expect(user).not_to be_valid
30
- expect(user.errors[:url]).to eq(["is not a valid address"])
31
- end
31
+ INVALID_URLS.each do |url|
32
+ it "rejects #{url.inspect} as a valid url" do
33
+ user = User.new(:url => url)
34
+ expect(user).not_to be_valid
35
+ end
36
+ end
37
+
38
+ it "defines alias method" do
39
+ expect(User).to respond_to(:validates_url)
40
+ end
41
+
42
+ it "uses default error message" do
43
+ user = User.new(:url => "invalid")
44
+ expect(user).not_to be_valid
45
+ expect(user.errors[:url]).to eq(["is not a valid address"])
46
+ end
32
47
 
33
- it "uses I18n string as error message [pt-BR]" do
34
- I18n.locale = :'pt-BR'
35
- user = User.new(:url => "invalid")
36
- expect(user).not_to be_valid
37
- expect(user.errors[:url]).to eq(["não parece ser uma URL válida"])
48
+ it "uses I18n string as error message [pt-BR]" do
49
+ I18n.locale = :'pt-BR'
50
+ user = User.new(:url => "invalid")
51
+ expect(user).not_to be_valid
52
+ expect(user.errors[:url]).to eq(["não parece ser uma URL válida"])
53
+ end
38
54
  end
39
55
  end
@@ -17,10 +17,11 @@ Gem::Specification.new do |s|
17
17
  s.require_paths = ["lib"]
18
18
 
19
19
  s.add_development_dependency "activerecord", ">= 3.0"
20
- s.add_development_dependency "rspec", "3.0.0.beta2"
20
+ s.add_development_dependency "rspec"
21
21
  s.add_development_dependency "sqlite3-ruby"
22
22
  s.add_development_dependency "rake"
23
23
  s.add_development_dependency "pry-meta"
24
24
  s.add_development_dependency "cpf_cnpj"
25
25
  s.add_development_dependency "sshkey"
26
+ s.add_development_dependency "codeclimate-test-reporter"
26
27
  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: 2.3.0
4
+ version: 2.4.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: 2014-05-12 00:00:00.000000000 Z
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0.beta2
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0.beta2
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sqlite3-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: codeclimate-test-reporter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Add some nice ActiveRecord validators.
112
126
  email:
113
127
  - fnando.vieira@gmail.com
@@ -117,10 +131,12 @@ extra_rdoc_files: []
117
131
  files:
118
132
  - ".gitignore"
119
133
  - ".rspec"
134
+ - ".travis.yml"
120
135
  - Gemfile
121
136
  - Gemfile.lock
122
137
  - README.md
123
138
  - Rakefile
139
+ - data/tld.txt
124
140
  - lib/validators.rb
125
141
  - lib/validators/constants.rb
126
142
  - lib/validators/ip.rb
@@ -128,6 +144,7 @@ files:
128
144
  - lib/validators/validates_cpf_format_of.rb
129
145
  - lib/validators/validates_datetime.rb
130
146
  - lib/validators/validates_email_format_of.rb
147
+ - lib/validators/validates_hostname_format_of.rb
131
148
  - lib/validators/validates_ip_address.rb
132
149
  - lib/validators/validates_ownership_of.rb
133
150
  - lib/validators/validates_ssh_private_key.rb
@@ -138,6 +155,7 @@ files:
138
155
  - spec/spec_helper.rb
139
156
  - spec/support/dates.rb
140
157
  - spec/support/emails.rb
158
+ - spec/support/hostnames.rb
141
159
  - spec/support/ips.rb
142
160
  - spec/support/models.rb
143
161
  - spec/support/translations.yml
@@ -147,6 +165,7 @@ files:
147
165
  - spec/validators/validates_cpf_format_of_spec.rb
148
166
  - spec/validators/validates_datetime_spec.rb
149
167
  - spec/validators/validates_email_format_of_spec.rb
168
+ - spec/validators/validates_hostname_format_of_spec.rb
150
169
  - spec/validators/validates_ip_address_spec.rb
151
170
  - spec/validators/validates_ownership_of_spec.rb
152
171
  - spec/validators/validates_ssh_private_key_spec.rb
@@ -172,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
191
  version: '0'
173
192
  requirements: []
174
193
  rubyforge_project:
175
- rubygems_version: 2.2.2
194
+ rubygems_version: 2.4.6
176
195
  signing_key:
177
196
  specification_version: 4
178
197
  summary: Add some nice ActiveRecord validators.
@@ -181,6 +200,7 @@ test_files:
181
200
  - spec/spec_helper.rb
182
201
  - spec/support/dates.rb
183
202
  - spec/support/emails.rb
203
+ - spec/support/hostnames.rb
184
204
  - spec/support/ips.rb
185
205
  - spec/support/models.rb
186
206
  - spec/support/translations.yml
@@ -190,6 +210,7 @@ test_files:
190
210
  - spec/validators/validates_cpf_format_of_spec.rb
191
211
  - spec/validators/validates_datetime_spec.rb
192
212
  - spec/validators/validates_email_format_of_spec.rb
213
+ - spec/validators/validates_hostname_format_of_spec.rb
193
214
  - spec/validators/validates_ip_address_spec.rb
194
215
  - spec/validators/validates_ownership_of_spec.rb
195
216
  - spec/validators/validates_ssh_private_key_spec.rb