email_address 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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