email_address 0.0.3 → 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.
@@ -1,119 +0,0 @@
1
- module EmailAddress
2
- ##############################################################################
3
- # Matcher - Allows matching of an email address against a list of matching
4
- # tokens.
5
- #
6
- # Match Patterns
7
- # * Top-Level-Domain: .org
8
- # * Domain Name: example.com
9
- # * Registration Name: hotmail. (matches any TLD)
10
- # * Domain Glob: *.exampl?.com
11
- # * Provider Name: google
12
- # * Mailbox Name or Glob: user00*@
13
- # * Address or Glob: postmaster@domain*.com
14
- # * Provider or Registration: msn (?? Possible combo for either match?)
15
- #
16
- # Usage:
17
- # m = EmailAddress::Matcher.new(".org example.com hotmail. google user*@ root@*.com")
18
- # m.include?("pat@example.com")
19
- ##############################################################################
20
-
21
- class Matcher
22
- attr_reader :rules, :email
23
-
24
- def self.matches?(rule, email)
25
- EmailAddress::Matcher.new(rule).matches?(email)
26
- end
27
-
28
- def initialize(rules=[], empty_rules_return=false)
29
- self.rules = rules
30
- @empty_rules_return = empty_rules_return
31
- end
32
-
33
- def rules=(r)
34
- @rules = r.is_a?(Array) ? r : r.split(/\s+/)
35
- @rules = @rules.map(&:downcase)
36
- end
37
-
38
- def email=(e)
39
- e = EmailAddress.new(e) if e.is_a?(String)
40
- if e.is_a?(EmailAddress::Address)
41
- @email_address = e
42
- @email = e.normalize
43
- @mailbox = e.mailbox
44
- @domain = e.host.name
45
- @domain_parts = e.host.parts
46
- @provider = e.provider
47
- elsif e.is_a?(Hash)
48
- @email = e[:email]
49
- @mailbox = e[:mailbox]
50
- @domain = e[:domain]
51
- @domain_parts = EmailAddress::DomainParser.new(@domain).parts
52
- @provider = e[:provider]
53
- end
54
- end
55
-
56
- # Takes a email address string, returns true if it matches a rule
57
- def include?(email_address)
58
- self.email = email_address
59
- return @empty_rules_return if @rules.empty?
60
- @rules.each do |rule|
61
- return true if registration_name_matches?(rule)
62
- return true if tld_matches?(rule)
63
- return true if provider_matches?(rule)
64
- return true if domain_matches?(rule)
65
- return true if email_matches?(rule)
66
- return true if @email_address && ip_cidr_matches?(rule)
67
- end
68
- false
69
- end
70
-
71
- # Does "example." match any tld?
72
- def registration_name_matches?(rule)
73
- @domain_parts[:registration_name]+'.' == rule ? true : false
74
- end
75
-
76
- # Does "sub.example.com" match ".com" and ".example.com" top level names?
77
- def tld_matches?(rule)
78
- rule.match(/\A\..+\z/) &&
79
- ( @domain[-rule.size, rule.size] == rule || ".#{@domain}" == rule) \
80
- ? true : false
81
- end
82
-
83
- def provider_matches?(rule)
84
- rule =~ /\A[\w\-]*\z/ && self.provider == rule.to_sym
85
- end
86
-
87
- def provider
88
- @provider ||= EmailAddress::Config.providers.each do |prov, defn|
89
- if defn.has_key?(:domains) && !defn[:domains].empty?
90
- defn[:domains].each do |d|
91
- if domain_matches?(d) || registration_name_matches?(d)
92
- return @provider = prov
93
- end
94
- end
95
- end
96
- end
97
- @provider ||= :unknown
98
- end
99
-
100
- # Does domain == rule or glob matches?
101
- def domain_matches?(rule, domain=@domain)
102
- return false if rule.include?("@")
103
- domain == rule || File.fnmatch?(rule, domain)
104
- end
105
-
106
- # Does "root@*.com" match "root@example.com" domain name
107
- def email_matches?(rule)
108
- return false unless rule.include?("@")
109
- @email == rule || File.fnmatch?(rule, @email)
110
- end
111
-
112
- # Does an IP of mail exchanger for "sub.example.com" match "xxx.xx.xx.xx/xx"?
113
- def ip_cidr_matches?(rule)
114
- return false unless rule.match(/\A\d.+\/\d+\z/) && @email_address.host.exchanger
115
- @email_address.host.exchanger.in_cidr?(rule) ? true : false
116
- end
117
-
118
- end
119
- end
@@ -1,141 +0,0 @@
1
- module EmailAddress
2
- class Validator
3
- LEGIBLE_LOCAL_REGEX = /\A[a-z0-9]+(([\.\-\_\'\+][a-z0-9]+)+)?\z/
4
- DOT_ATOM_REGEX = /[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]/
5
- ERRORS = %i(bad_syntax bad_email bad_mailbox bad_domain bad_exchanger bad_recipient)
6
- attr_reader :error
7
-
8
- def self.validate(address, options={})
9
- EmailAddress::Validator.new(address, options).valid?
10
- end
11
-
12
- def initialize(address, options={})
13
- @address = address
14
- @local = address.local
15
- @host = address.host
16
- @options = options
17
- @rules = EmailAddress::Config.provider(@host.provider)
18
- @error = nil
19
- end
20
-
21
- # Returns true if email address seems valid, false otherwise.
22
- # For error, call #error method to get error code (symbol).
23
- def valid?
24
- return false unless valid_sizes?
25
- if @rules[:valid_mailbox] && ! @rules[:valid_mailbox].call(@local.to_s)
26
- #p ["VALIDATOR", @local.to_s, @rules[:valid_mailbox]]
27
- return invalid(:bad_mailbox)
28
- else
29
- return false unless valid_local?
30
- end
31
- if EmailAddress::Config.options[:check_dns]
32
- return invalid(:bad_exchanger) unless valid_mx? || (valid_dns? && @options[:allow_dns_a])
33
- end
34
- true
35
- end
36
-
37
- def mailbox_validator(v)
38
- return true unless v
39
- if v.is_a?(Proc)
40
- return invalid(:bad_mailbox) unless @rules[:valid_mailbox].call(@local)
41
- elsif v == :legible
42
- return legible?
43
- elsif v == :rfc
44
- return rfc_compliant?
45
- end
46
- end
47
-
48
- # True if the DNS A record or MX records are defined
49
- # Why A record? Some domains are misconfigured with only the A record.
50
- def valid_dns?
51
- @host.exchanger.has_dns_a_record?
52
- end
53
-
54
- # True if the DNS MX records have been defined. More strict than #valid?
55
- def valid_mx?
56
- @host.exchanger.mxers.size > 0
57
- end
58
-
59
- # Allows single, simple punctua3Nz=Xj/7c9 tion character between words
60
- def legible?
61
- @local.to_s =~ LEGIBLE_LOCAL_REGEX
62
- end
63
-
64
- def valid_sizes?
65
- return invalid(:bad_email) unless @rules[:address_size].include?(@address.to_s.size)
66
- return invalid(:bad_mailbox) unless @rules[:local_size ].include?(@local.to_s.size)
67
- return invalid(:bad_mailbox) unless @rules[:mailbox_size].include?(@local.mailbox.size)
68
- return invalid(:bad_domain ) unless @rules[:domain_size ].include?(@host.to_s.size)
69
- true
70
- end
71
-
72
- def valid_local?
73
- return invalid(:bad_mailbox) unless valid_local_part?(@local.mailbox)
74
- return invalid(:bad_mailbox) unless @local.comment.empty? || valid_local_part?(@local.comment)
75
- if @local.tag
76
- @local.tag.split(@rules[:tag_separator]).each do |t|
77
- return invalid(:bad_mailbox, t) unless valid_local_part?(t)
78
- end
79
- end
80
- true
81
- end
82
-
83
- # Valid within a mailbox, tag, comment
84
- def valid_local_part?(p)
85
- p =~ LEGIBLE_LOCAL_REGEX
86
- end
87
-
88
-
89
- def invalid(reason, *info)
90
- @error = reason
91
- #p "INVALID ----> #{reason} for #{@local.to_s}@#{@host.to_s} #{info.inspect}"
92
- false
93
- end
94
-
95
- def valid_google_local?
96
- true
97
- end
98
-
99
- ############################################################################
100
- # RFC5322 Rules (Oct 2008):
101
- #---------------------------------------------------------------------------
102
- # addr-spec = local-part "@" domain
103
- # local-part = dot-atom / quoted-string / obs-local-part
104
- # domain = dot-atom / domain-literal / obs-domain
105
- # domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
106
- # dtext = %d33-90 / ; Printable US-ASCII
107
- # %d94-126 / ; characters not including
108
- # obs-dtext ; "[", "]", or "\"
109
- # atext = ALPHA / DIGIT / ; Printable US-ASCII
110
- # "!" / "#" / ; characters not including
111
- # "$" / "%" / ; specials. Used for atoms.
112
- # "&" / "'" /
113
- # "*" / "+" /
114
- # "-" / "/" /
115
- # "=" / "?" /
116
- # "^" / "_" /
117
- # "`" / "{" /
118
- # "|" / "}" /
119
- # "~"
120
- # atom = [CFWS] 1*atext [CFWS]
121
- # dot-atom-text = 1*atext *("." 1*atext)
122
- # dot-atom = [CFWS] dot-atom-text [CFWS]
123
- # specials = "(" / ")" / ; Special characters that do
124
- # "<" / ">" / ; not appear in atext
125
- # "[" / "]" /
126
- # ":" / ";" /
127
- # "@" / "\" /
128
- # "," / "." /
129
- # DQUOTE
130
- # qtext = %d33 / ; Printable US-ASCII
131
- # %d35-91 / ; characters not including
132
- # %d93-126 / ; "\" or the quote character
133
- # obs-qtext
134
- # qcontent = qtext / quoted-pair
135
- # quoted-string = [CFWS]
136
- # DQUOTE *([FWS] qcontent) [FWS] DQUOTE
137
- # [CFWS]
138
- ############################################################################
139
-
140
- end
141
- end
@@ -1,21 +0,0 @@
1
- require_relative '../test_helper'
2
-
3
- class TestDomainMatcher < MiniTest::Test
4
- MATCHER = EmailAddress::DomainMatcher
5
-
6
- def test_hostname
7
- assert_equal true, MATCHER.matches?("example.com", "example.com")
8
- assert_equal true, MATCHER.matches?("example.com", "example")
9
- assert_equal true, MATCHER.matches?("example.com", ".com")
10
- assert_equal true, MATCHER.matches?("example.com", ".example.com")
11
- end
12
-
13
- def test_list
14
- assert_equal true, MATCHER.matches?("example.com", %w(ex .tld example))
15
- end
16
-
17
- def test_glob_matches
18
- assert_equal true, MATCHER.matches?("example.com", %w(ex*.com))
19
- end
20
-
21
- end
@@ -1,29 +0,0 @@
1
- require_relative '../test_helper'
2
-
3
- class TestDomainParser < MiniTest::Test
4
- def test_hostname
5
- parts = EmailAddress::DomainParser.parse("Example.com")
6
- assert_equal 'example.com', parts[:domain_name]
7
- assert_equal 'example', parts[:registration_name]
8
- assert_equal 'com', parts[:tld]
9
- assert_equal '', parts[:subdomains]
10
- end
11
-
12
- def test_sld
13
- parts = EmailAddress::DomainParser.parse("sub.Example.co.uk")
14
- assert_equal 'example.co.uk', parts[:domain_name]
15
- assert_equal 'co.uk', parts[:tld]
16
- assert_equal 'sub', parts[:subdomains]
17
- end
18
-
19
- def test_provider
20
- parser = EmailAddress::DomainParser.new("gmail.com")
21
- assert_equal :google, parser.provider
22
- end
23
-
24
- def test_yahoo
25
- parser = EmailAddress::DomainParser.new("yahoo.co.uk")
26
- assert_equal :yahoo, parser.provider
27
- end
28
-
29
- end
@@ -1,44 +0,0 @@
1
- require_relative '../test_helper'
2
-
3
- class TestDomainMatcher < MiniTest::Test
4
-
5
- def setup
6
- @matcher = EmailAddress::Matcher.new(
7
- ".org example.com domain*.com hotmail. google user*@ root@*.com 207.99.0.0/16")
8
- end
9
-
10
- def test_tld
11
- assert_equal true, @matcher.include?("pat@example.org")
12
- end
13
-
14
- def test_domain
15
- assert_equal true, @matcher.include?("pat@example.com")
16
- assert_equal false, @matcher.include?("pat@nomatch.com")
17
- end
18
-
19
- def test_registration
20
- assert_equal true, @matcher.include?("pat@hotmail.ca")
21
- end
22
-
23
- def test_domain_glob
24
- assert_equal true, @matcher.include?("pat@domain123.com")
25
- end
26
-
27
- def test_provider
28
- assert_equal true, @matcher.include?("pat@gmail.com")
29
- end
30
-
31
- def test_mailbox
32
- assert_equal true, @matcher.include?("user123@example.com")
33
- end
34
-
35
- def test_address
36
- assert_equal true, @matcher.include?("root@example.com")
37
- end
38
-
39
- def test_cidr
40
- # If this breaks, check its MX IP addresses against "207.99.0.0/30"
41
- assert_equal true, @matcher.include?("test@biglist.com")
42
- end
43
-
44
- end
@@ -1,16 +0,0 @@
1
- require_relative '../test_helper'
2
-
3
- class EmailAddress::TestValidator < MiniTest::Test
4
-
5
- def test_basic
6
- assert_equal true, EmailAddress.new('user.name@gmail.com').valid?
7
- assert_equal true, EmailAddress.new('user.name+tagme@gmail.com').valid?
8
- end
9
-
10
- def test_bad_local
11
- assert_equal false, EmailAddress.new('user!name@gmail.com').valid?
12
- assert_equal false, EmailAddress.new('***@yahoo.com').valid?
13
- assert_equal false, EmailAddress.new('***@unknowndom41n.com').valid?
14
- end
15
-
16
- end