email_address 0.1.20 → 0.2.0

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: 89deebff7a17e3e90d1bfc92f8f22e1ab489d8c284c5d8070503e12b44345a72
4
- data.tar.gz: 558ae5a8cff2abd326b1f6dddf6e6c01b4ef91bd0a94a55c44dea817696e4b31
3
+ metadata.gz: f9667acc31d6ce84fd3acb2e8e2f3ea04e496df5ff9dc5f89815fa148df1113e
4
+ data.tar.gz: e17aa2b229cb28ca80dcbf37226a5411052758db1e15cee0ddc2038d5244de42
5
5
  SHA512:
6
- metadata.gz: 25850ded8a4ecb0ecb093e0f4583ee657fa134f93e976a2a44af829ab755487be9dd181fb15512af9e041854619dfa4c9cb8b0c009462cd6a7111d35808678ab
7
- data.tar.gz: 26562889a56d1ddf32812c5f98948238672ba201072797db16e63b7f52ef03e022fe8b73a06096702a1f2a68905873f31420b17a457466da0e550f9cc3a168a0
6
+ metadata.gz: 908fa1ffaa5692b07fa4e586a66a8fdf6395c1a51013ee389e0437df175d6712ecc57831b6616cfabd28463a87c7a60df9b6ba8382cba0c58d8449e4ada51c6d
7
+ data.tar.gz: a9f2a9bb8280118af5b21b08e8ca2273b16f3d5f700b91cb7c36b22444a7d5878e54a45292a2080243aff6fa4d31cd2ca3af4bd664f182b49d52ab42b864c711
@@ -0,0 +1,18 @@
1
+ name: CI Build
2
+ on: [push, pull_request]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ ruby-version: [2.6, 2.7, 3.0, jruby]
9
+ steps:
10
+ - uses: actions/checkout@v2
11
+ - uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: ${{ matrix.ruby-version }}
14
+ bundler-cache: true # runs `bundle install` and caches installed gems automatically
15
+ - name: Install dependencies
16
+ run: bundle install
17
+ - name: Run tests
18
+ run: bundle exec rake
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in email_address.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Email Address
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/email_address.svg)](http://rubygems.org/gems/email_address)
4
- [![Build Status](https://travis-ci.org/afair/email_address.svg?branch=v0.1)](https://travis-ci.org/afair/email_address)
4
+ [![CI Build](https://github.com/afair/email_address/actions/workflows/ci.yml/badge.svg)](https://github.com/afair/email_address/actions/workflows/ci.yml)
5
5
  [![Code Climate](https://codeclimate.com/github/afair/email_address/badges/gpa.svg)](https://codeclimate.com/github/afair/email_address)
6
6
 
7
7
  The `email_address` gem provides a ruby language library for working
@@ -98,7 +98,7 @@ introduces terms to distinguish types of email addresses.
98
98
  madness!."()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a(comment )"@example.org
99
99
 
100
100
  * *Base* - A unique mailbox without tags. For gmail, is uses the incoming
101
- punctation, essential when building an MD5 or SHA1 to match services
101
+ punctation, essential when building an MD5, SHA1, or SHA256 to match services
102
102
  like Gravatar, and email address digest interchange.
103
103
 
104
104
  * *Canonical* - An unique account address, lower-cased, without the
@@ -234,6 +234,7 @@ Here are some other methods that are available.
234
234
  ```ruby
235
235
  email.redact #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
236
236
  email.sha1 #=> "bea3f3560a757f8142d38d212a931237b218eb5e"
237
+ email.sha256 #=> "9e2a0270f2d6778e5f647fc9eaf6992705ca183c23d1ed1166586fd54e859f75"
237
238
  email.md5 #=> "c5be3597c391169a5ad2870f9ca51901"
238
239
  email.host_name #=> "gmail.com"
239
240
  email.provider #=> :google
@@ -272,6 +273,25 @@ class User < ActiveRecord::Base
272
273
  end
273
274
  ```
274
275
 
276
+ #### Rails I18n
277
+
278
+ Copy and adapt `lib/email_address/messages.yaml` into your locales and
279
+ create an after initialization callback:
280
+
281
+ ```ruby
282
+ # config/initializers/email_address.rb
283
+
284
+ Rails.application.config.after_initialize do
285
+ I18n.available_locales.each do |locale|
286
+ translations = I18n.t(:email_address, locale: locale)
287
+
288
+ next unless translations.is_a? Hash
289
+
290
+ EmailAddress::Config.error_messages translations.transform_keys(&:to_s), locale.to_s
291
+ end
292
+ end
293
+ ```
294
+
275
295
  #### Rails Email Address Type Attribute
276
296
 
277
297
  Initial support is provided for Active Record 5.0 attributes API.
@@ -476,6 +496,11 @@ Full translation support would be ideal though.
476
496
  the SHA1 Digest, making it unique to your application so it can't easily be
477
497
  discovered by comparing against a known list of email/sha1 pairs.
478
498
 
499
+ * sha256_secret -
500
+ This application-level secret is appended to the email_address to compute
501
+ the SHA256 Digest, making it unique to your application so it can't easily be
502
+ discovered by comparing against a known list of email/sha256 pairs.
503
+
479
504
  * munge_string - "*****", the string to replace into munged addresses.
480
505
 
481
506
  For local part configuration:
data/Rakefile CHANGED
@@ -1,9 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
3
  require "bundler/setup"
4
- require 'rake/testtask'
4
+ require "rake/testtask"
5
5
 
6
- task :default => :test
6
+ task default: :test
7
7
 
8
8
  desc "Run the Test Suite, toot suite"
9
9
  Rake::TestTask.new do |t|
@@ -1,37 +1,36 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'email_address/version'
3
+ require "email_address/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "email_address"
8
- spec.version = EmailAddress::VERSION
9
- spec.authors = ["Allen Fair"]
10
- spec.email = ["allen.fair@gmail.com"]
11
- spec.description = %q{The EmailAddress Gem to work with and validate email addresses.}
12
- spec.summary = %q{This gem provides a ruby language library for working with and validating email addresses. By default, it validates against conventional usage, the format preferred for user email addresses. It can be configured to validate against RFC “Standard” formats, common email service provider formats, and perform DNS validation.}
13
- spec.homepage = "https://github.com/afair/email_address"
14
- spec.license = "MIT"
6
+ spec.name = "email_address"
7
+ spec.version = EmailAddress::VERSION
8
+ spec.authors = ["Allen Fair"]
9
+ spec.email = ["allen.fair@gmail.com"]
10
+ spec.description = "The EmailAddress Gem to work with and validate email addresses."
11
+ spec.summary = "This gem provides a ruby language library for working with and validating email addresses. By default, it validates against conventional usage, the format preferred for user email addresses. It can be configured to validate against RFC “Standard” formats, common email service provider formats, and perform DNS validation."
12
+ spec.homepage = "https://github.com/afair/email_address"
13
+ spec.license = "MIT"
15
14
 
16
- #spec.required_ruby_version = ">= 2.3.0"
17
- spec.files = `git ls-files`.split($/)
18
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.required_ruby_version = ">= 2.5", "< 4"
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
19
  spec.require_paths = ["lib"]
21
20
 
22
21
  spec.add_development_dependency "rake"
23
- spec.add_development_dependency "minitest", "~> 5.11"
24
- spec.add_development_dependency "bundler" #, "~> 1.16.0"
25
- if RUBY_PLATFORM == 'java'
26
- spec.add_development_dependency "activerecord", "= 4.2.10"
27
- spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", '~> 1.3.24'
22
+ spec.add_development_dependency "minitest", "~> 5.11"
23
+ spec.add_development_dependency "bundler" # , "~> 1.16.0"
24
+ if RUBY_PLATFORM == "java"
25
+ spec.add_development_dependency "activerecord", "~> 5.2.6"
26
+ spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", "~> 52.7"
28
27
  else
29
- spec.add_development_dependency "activerecord", "~> 5.2.4"
28
+ spec.add_development_dependency "activerecord", "~> 6.1.4"
30
29
  spec.add_development_dependency "sqlite3"
31
30
  end
32
- #spec.add_development_dependency "codeclimate-test-reporter"
33
31
  spec.add_development_dependency "simplecov"
32
+ spec.add_development_dependency "pry"
33
+ spec.add_development_dependency "standard", "~> 1.1.1"
34
34
 
35
35
  spec.add_dependency "simpleidn"
36
- spec.add_dependency "netaddr", '>= 2.0.4', '< 3'
37
36
  end
data/lib/email_address.rb CHANGED
@@ -3,7 +3,6 @@
3
3
  # EmailAddress parses and validates email addresses against RFC standard,
4
4
  # conventional, canonical, formats and other special uses.
5
5
  module EmailAddress
6
-
7
6
  require "email_address/config"
8
7
  require "email_address/exchanger"
9
8
  require "email_address/host"
@@ -49,21 +48,21 @@ module EmailAddress
49
48
 
50
49
  # Creates an instance of this email address.
51
50
  # This is a short-cut to EmailAddress::Address.new
52
- def new(email_address, config={})
53
- Address.new(email_address, config)
51
+ def new(email_address, config = {}, locale = "en")
52
+ Address.new(email_address, config, locale)
54
53
  end
55
54
 
56
- def new_redacted(email_address, config={})
57
- Address.new(Address.new(email_address, config).redact)
55
+ def new_redacted(email_address, config = {}, locale = "en")
56
+ Address.new(Address.new(email_address, config, locale).redact)
58
57
  end
59
58
 
60
- def new_canonical(email_address, config={})
61
- Address.new(Address.new(email_address, config).canonical, config)
59
+ def new_canonical(email_address, config = {}, locale = "en")
60
+ Address.new(Address.new(email_address, config, locale).canonical, config)
62
61
  end
63
62
 
64
63
  # Does the email address match any of the given rules
65
- def matches?(email_address, rules, config={})
66
- Address.new(email_address, config).matches?(rules)
64
+ def matches?(email_address, rules, config = {}, locale = "en")
65
+ Address.new(email_address, config, locale).matches?(rules)
67
66
  end
68
67
  end
69
68
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EmailAddress
4
-
5
4
  # ActiveRecord validator class for validating an email
6
5
  # address with this library.
7
6
  # Note the initialization happens once per process.
@@ -16,14 +15,13 @@ module EmailAddress
16
15
  # Default field: :email or :email_address (first found)
17
16
  #
18
17
  class ActiveRecordValidator < ActiveModel::Validator
19
-
20
- def initialize(options={})
18
+ def initialize(options = {})
21
19
  @opt = options
22
20
  end
23
21
 
24
22
  def validate(r)
25
23
  if @opt[:fields]
26
- @opt[:fields].each {|f| validate_email(r, f) }
24
+ @opt[:fields].each { |f| validate_email(r, f) }
27
25
  elsif @opt[:field]
28
26
  validate_email(r, @opt[:field])
29
27
  elsif r.respond_to? :email
@@ -33,17 +31,15 @@ module EmailAddress
33
31
  end
34
32
  end
35
33
 
36
- def validate_email(r,f)
34
+ def validate_email(r, f)
37
35
  return if r[f].nil?
38
36
  e = Address.new(r[f])
39
37
  unless e.valid?
40
38
  error_message = @opt[:message] ||
41
- Config.error_messages[:invalid_address] ||
42
- "Invalid Email Address"
39
+ Config.error_message(:invalid_address, I18n.locale.to_s) ||
40
+ "Invalid Email Address"
43
41
  r.errors.add(f, error_message)
44
42
  end
45
43
  end
46
-
47
44
  end
48
-
49
45
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "digest/sha1"
4
+ require "digest/sha2"
4
5
  require "digest/md5"
5
6
 
6
7
  module EmailAddress
@@ -10,7 +11,7 @@ module EmailAddress
10
11
  include Comparable
11
12
  include Rewriter
12
13
 
13
- attr_accessor :original, :local, :host, :config, :reason
14
+ attr_accessor :original, :local, :host, :config, :reason, :locale
14
15
 
15
16
  CONVENTIONAL_REGEX = /\A#{Local::CONVENTIONAL_MAILBOX_WITHIN}
16
17
  @#{Host::DNS_HOST_REGEX}\z/x
@@ -22,15 +23,16 @@ module EmailAddress
22
23
  # Given an email address of the form "local@hostname", this sets up the
23
24
  # instance, and initializes the address to the "normalized" format of the
24
25
  # address. The original string is available in the #original method.
25
- def initialize(email_address, config = {})
26
+ def initialize(email_address, config = {}, locale = "en")
26
27
  @config = Config.new(config)
27
28
  @original = email_address
29
+ @locale = locale
28
30
  email_address = (email_address || "").strip
29
31
  email_address = parse_rewritten(email_address) unless config[:skip_rewrite]
30
32
  local, host = Address.split_local_host(email_address)
31
33
 
32
- @host = Host.new(host, @config)
33
- @local = Local.new(local, @config, @host)
34
+ @host = Host.new(host, @config, locale)
35
+ @local = Local.new(local, @config, @host, locale)
34
36
  @error = @error_message = nil
35
37
  end
36
38
 
@@ -86,8 +88,8 @@ module EmailAddress
86
88
  def host_name
87
89
  @host.host_name
88
90
  end
89
- alias right host_name
90
- alias hostname host_name
91
+ alias_method :right, :host_name
92
+ alias_method :hostname, :host_name
91
93
 
92
94
  # Returns the ESP (Email Service Provider) or ISP name derived
93
95
  # using the provider configuration rules.
@@ -111,7 +113,7 @@ module EmailAddress
111
113
  "#{local}@#{host}"
112
114
  end
113
115
  end
114
- alias to_s normal
116
+ alias_method :to_s, :normal
115
117
 
116
118
  def inspect
117
119
  "#<#{self.class}:0x#{object_id.to_s(16)} address=\"#{self}\">"
@@ -159,32 +161,36 @@ module EmailAddress
159
161
  [local.munge, host.munge].join("@")
160
162
  end
161
163
 
162
- # Returns and MD5 of the canonical address form. Some cross-system systems
164
+ # Returns and MD5 of the base address form. Some cross-system systems
163
165
  # use the email address MD5 instead of the actual address to refer to the
164
166
  # same shared user identity without exposing the actual address when it
165
167
  # is not known in common.
166
168
  def reference(form = :base)
167
169
  Digest::MD5.hexdigest(send(form))
168
170
  end
169
- alias md5 reference
171
+ alias_method :md5, :reference
170
172
 
171
- # This returns the SHA1 digest (in a hex string) of the canonical email
173
+ # This returns the SHA1 digest (in a hex string) of the base email
172
174
  # address. See #md5 for more background.
173
175
  def sha1(form = :base)
174
176
  Digest::SHA1.hexdigest((send(form) || "") + (@config[:sha1_secret] || ""))
175
177
  end
176
178
 
179
+ def sha256(form = :base)
180
+ Digest::SHA256.hexdigest((send(form) || "") + (@config[:sha256_secret] || ""))
181
+ end
182
+
177
183
  #---------------------------------------------------------------------------
178
184
  # Comparisons & Matching
179
185
  #---------------------------------------------------------------------------
180
186
 
181
187
  # Equal matches the normalized version of each address. Use the Threequal to check
182
188
  # for match on canonical or redacted versions of addresses
183
- def ==(other_email)
184
- to_s == other_email.to_s
189
+ def ==(other)
190
+ to_s == other.to_s
185
191
  end
186
- alias eql? ==
187
- alias equal? ==
192
+ alias_method :eql?, :==
193
+ alias_method :equal?, :==
188
194
 
189
195
  # Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison
190
196
  # of this addres with another, using the canonical or redacted forms.
@@ -197,12 +203,12 @@ module EmailAddress
197
203
  redact == other_email.canonical ||
198
204
  canonical == other_email.redact
199
205
  end
200
- alias include? same_as?
206
+ alias_method :include?, :same_as?
201
207
 
202
208
  # Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison
203
209
  # of this addres with another, using the normalized form.
204
- def <=>(other_email)
205
- to_s <=> other_email.to_s
210
+ def <=>(other)
211
+ to_s <=> other.to_s
206
212
  end
207
213
 
208
214
  # Address matches one of these Matcher rule patterns
@@ -214,7 +220,7 @@ module EmailAddress
214
220
 
215
221
  # Does "root@*.com" match "root@example.com" domain name
216
222
  rules.each do |r|
217
- if r.match(/.+@.+/)
223
+ if /.+@.+/.match?(r)
218
224
  return r if File.fnmatch?(r, to_s)
219
225
  end
220
226
  end
@@ -276,7 +282,7 @@ module EmailAddress
276
282
  def set_error(err, reason = nil)
277
283
  @error = err
278
284
  @reason = reason
279
- @error_message = Config.error_message(err)
285
+ @error_message = Config.error_message(err, locale)
280
286
  false
281
287
  end
282
288
 
@@ -17,6 +17,11 @@ module EmailAddress
17
17
  # the SHA1 Digest, making it unique to your application so it can't easily be
18
18
  # discovered by comparing against a known list of email/sha1 pairs.
19
19
  #
20
+ # * sha256_secret ""
21
+ # This application-level secret is appended to the email_address to compute
22
+ # the SHA256 Digest, making it unique to your application so it can't easily be
23
+ # discovered by comparing against a known list of email/sha256 pairs.
24
+ #
20
25
  # For local part configuration:
21
26
  # * local_downcase: true
22
27
  # Downcase the local part. You probably want this for uniqueness.
@@ -104,6 +109,7 @@ module EmailAddress
104
109
  dns_lookup: :mx, # :mx, :a, :off
105
110
  dns_timeout: nil,
106
111
  sha1_secret: "",
112
+ sha256_secret: "",
107
113
  munge_string: "*****",
108
114
 
109
115
  local_downcase: true,
@@ -188,9 +194,14 @@ module EmailAddress
188
194
  # Customize your own error message text.
189
195
  def self.error_messages(hash = {}, locale = "en", *extra)
190
196
  hash = extra.first if extra.first.is_a? Hash
191
- unless hash.empty?
197
+
198
+ @errors[locale] ||= {}
199
+ @errors[locale]["email_address"] ||= {}
200
+
201
+ unless hash.nil? || hash.empty?
192
202
  @errors[locale]["email_address"] = @errors[locale]["email_address"].merge(hash)
193
203
  end
204
+
194
205
  @errors[locale]["email_address"]
195
206
  end
196
207
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "resolv"
4
- require "netaddr"
5
4
  require "socket"
6
5
 
7
6
  module EmailAddress
@@ -58,8 +57,8 @@ module EmailAddress
58
57
 
59
58
  ress = begin
60
59
  dns.getresources(@host, Resolv::DNS::Resource::IN::MX)
61
- rescue Resolv::ResolvTimeout
62
- []
60
+ rescue Resolv::ResolvTimeout
61
+ []
63
62
  end
64
63
 
65
64
  records = ress.map { |r|
@@ -105,22 +104,9 @@ module EmailAddress
105
104
 
106
105
  # Given a cidr (ip/bits) and ip address, returns true on match. Caches cidr object.
107
106
  def in_cidr?(cidr)
108
- if cidr.include?(":")
109
- c = NetAddr::IPv6Net.parse(cidr)
110
- return true if mx_ips.find do |ip|
111
- next unless ip.include?(":")
112
- rel = c.rel NetAddr::IPv6Net.parse(ip)
113
- !rel.nil? && rel >= 0
114
- end
115
- elsif cidr.include?(".")
116
- c = NetAddr::IPv4Net.parse(cidr)
117
- return true if mx_ips.find do |ip|
118
- next if ip.include?(":")
119
- rel = c.rel NetAddr::IPv4Net.parse(ip)
120
- !rel.nil? && rel >= 0
121
- end
122
- end
123
- false
107
+ net = IPAddr.new(cidr)
108
+ found = mx_ips.detect { |ip| net.include?(IPAddr.new(ip)) }
109
+ !!found
124
110
  end
125
111
  end
126
112
  end