· 3 years ago · Oct 01, 2022, 05:30 PM
1--[[
2 ####--------------------------------####
3 #--# Author: by uriid1 #--#
4 #--# License: GNU GPLv3 #--#
5 #--# Telegram: @main_moderator #--#
6 #--# E-mail: appdurov@gmail.com #--#
7 ####--------------------------------####
8--]]
9
10local function email_validator(str)
11 if type(str) ~= 'string' then
12 return false, 'E-mail is not a string'
13 end
14
15 -- Capture
16 local local_part, domain = str:lower():match('^([A-z0-9.!#$%&\'*+-/=?^_`{|}~() "]+)@([()A-z0-9-.:]+)$')
17
18 -- Check exists local-part and domain
19 if (not local_part) or (not domain) then
20 return false, 'Invalid local-part or domain name'
21 end
22
23 -- Check length
24 if #local_part > 63 then
25 return false, 'Local-part over 64 symbol'
26 elseif #domain > 255 then
27 return false, 'Domain over 255 symbol'
28 end
29
30 -- Check local-part in quotes
31 local text_in_quotes = local_part:match('^"(.+)"$')
32 if text_in_quotes then
33 if text_in_quotes:match('[^A-z!#$%&\'*+-/=?^_ `{|}~.0-9]') then
34 return false, 'Invalid characters in quotes local_part'
35 end
36 else
37 if local_part:find('"') then
38 return false, 'Invalid character " in local-part'
39 end
40 end
41
42 -- Check comment
43 local comment_in_local_part = local_part:match('(%(.+%))')
44 local comment_in_domain = domain:match('(%(.+%))')
45
46 if comment_in_local_part then
47 local some_text, count_char = comment_in_local_part:gsub('[()]', '')
48 if count_char > 2 then
49 return false, 'Multiple comment in local-part are not allowed'
50 end
51 local_part = local_part:gsub('%('..some_text..'%)', '')
52 end
53
54 if comment_in_domain then
55 local some_text, count_char = comment_in_domain:gsub('[()]', '')
56 if count_char > 2 then
57 return false, 'Multiple comment in domain are not allowed'
58 end
59 domain = domain:gsub('%('..some_text..'%)', '')
60 end
61
62 -- Check [] characters in local-part
63 if local_part:match('%[.+%]') then
64 return false, 'Invalid local-part, characters []'
65 end
66
67 -- Check correct local-part
68 if local_part:find("%.%.") or
69 local_part:find("%-%-") or
70 local_part:find("%+%+") then
71 return false, 'Too many periods in local-part'
72 end
73
74 -- Dot pos check in local-part
75 if local_part:sub(1, 1) == '.' then
76 return false, 'Dot cannot be the first character'
77 elseif local_part:sub(-1) == '.' then
78 return false, 'Dot cannot be the last character'
79 end
80
81 -- DNS domain check
82 local hostname = domain:match('^[%d%a-.]+$')
83 if hostname then
84 if domain:sub(0, 1) == '.' or
85 domain:sub(-1) == '.' or
86 domain:find('%.%.')
87 then
88 return false, 'Invalid domain name'
89 end
90 end
91
92 -- IpV4 domain check
93 local ipv4 = domain:match('^%[.+%]$')
94 if ipv4 then
95 local a, b, c, d = domain:match('%[(%d+)%.(%d+)%.(%d+)%.(%d+)%]')
96 -- Is ipv4
97 if a and b and c and d then
98 a, b, c, d = tonumber(a), tonumber(b), tonumber(c), tonumber(d)
99 if not ((a < 256) and
100 (b < 256) and
101 (c < 256) and
102 (d < 256))
103 then
104 return false, 'Invalid ipV4 domain'
105 end
106 end
107 end
108
109 -- ipV6 domain check
110 local ipv6 = domain:match('^%[ipv6:(.+)%]$')
111 if ipv6 then
112 -- Is ipv6
113 if not ipv4:find(('([a-fA-F0-9]+):'):rep(7)..'([a-fA-F0-9]+)') then
114 return false, 'Invalid IPv6 domain'
115 end
116 end
117
118 return (hostname or ipv4 or ipv6) and true or false
119end
120
121
122-- Test
123print('Valid Test')
124local valid = {
125 'appdurov@domain.co.tk';
126 'disposable.style.email.with+symbol@example.com';
127 'very.common@example.com';
128 'simple@[127.0.0.255]';
129 'postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]';
130 'postmaster(coment)@domain.lol';
131 'postmaster@(comment)domain.lol';
132}
133
134for i = 1, #valid do
135 if email_validator(valid[i]) then
136 print('Test: '..i, 'True')
137 else
138 print('Test: '..i, 'Failed')
139 end
140end
141
142--
143print('\nNot Valid Test')
144local not_valid = {
145 'blablabla';
146 ' appdurov@gmail.com ';
147 '.John.Doe@example.com';
148 'John.Doe.@example.com';
149 'Abc.example.com';
150 'A@b@c@example.com';
151 'a"b(c)d,e:f;g<h>i[j\\k]l@example.com';
152 'just"not"right@example.com';
153 'this is"not\allowed@example.com';
154 'this\\ still\\"not\\allowed@example.com';
155 '1234567890123456789012345678901234567890123456789012345678901234+x@example.com';
156 'i_like_underscore@but_its_not_allowed_in_this_part.example.com';
157 'QA[icon]CHOCOLATE[icon]@test.com';
158 '[]!@#$%^&@gmail.com';
159}
160
161for i = 1, #not_valid do
162 if not email_validator(not_valid[i]) then
163 print('Test: '..i, 'True')
164 else
165 print('Test: '..i, 'Failed')
166 end
167end