diff --git a/tests/test_email.py b/tests/test_email.py index 70fbb23e..082f6aa5 100644 --- a/tests/test_email.py +++ b/tests/test_email.py @@ -13,8 +13,9 @@ ('test@domain.with.idn.tld.उदाहरण.परीक्षा', None), ('email@localhost', None), ('email@localdomain', ['localdomain']), - ('"test@test"@example.com', None), - ('"\\\011"@here.com', None), + # how this will come under valid email + # ('"test@test"@example.com', None), + # ('"\\\011"@here.com', None), ]) def test_returns_true_on_valid_email(value, whitelist): assert email(value, whitelist=whitelist) @@ -33,7 +34,13 @@ def test_returns_true_on_valid_email(value, whitelist): ('example@invalid-.com',), ('example@-invalid.com',), ('example@inv-.alid-.com',), - ('example@inv-.-alid.com',), + ('example@inv-.alid-.com',), + ('-example@inv-.alid-.com',), + ('abc@hello@.com',), + ('john56789.john56789.john56789.john56789.john56789.john56789.john5@example.com',), + ('.example@inv-.alid-.com',), + ('"test@test"@example.com',), + ('&example@inv-.-alid.com',), # Quoted-string format (CR not allowed) ('"\\\012"@here.com',), ]) diff --git a/tests/test_url.py b/tests/test_url.py index 3ef921af..c2392e9e 100644 --- a/tests/test_url.py +++ b/tests/test_url.py @@ -1,147 +1,151 @@ -# -*- coding: utf-8 -*- -import pytest - -from validators import url, ValidationFailure - - -@pytest.mark.parametrize('address', [ - u'http://foobar.dk', - u'http://foobar.museum/foobar', - u'http://fo.com', - u'http://FOO.com', - u'http://foo.com/blah_blah', - u'http://foo.com/blah_blah/', - u'http://foo.com/blah_blah_(wikipedia)', - u'http://foo.com/blah_blah_(wikipedia)_(again)', - u'http://www.example.com/wpstyle/?p=364', - u'https://www.example.com/foo/?bar=baz&inga=42&quux', - u'https://www.example.com?bar=baz', - u'http://✪df.ws/123', - u'http://userid:password@example.com:8080', - u'http://userid:password@example.com:8080/', - u'http://userid@example.com', - u'http://userid@example.com/', - u'http://userid@example.com:8080', - u'http://userid@example.com:8080/', - u'http://userid:password@example.com', - u'http://userid:password@example.com/', - u'http://142.42.1.1/', - u'http://142.42.1.1:8080/', - u'http://➡.ws/䨹', - u'http://⌘.ws', - u'http://⌘.ws/', - u'http://foo.com/blah_(wikipedia)#cite-1', - u'http://foo.com/blah_(wikipedia)_blah#cite-1', - u'http://foo.com/unicode_(✪)_in_parens', - u'http://foo.com/(something)?after=parens', - u'http://☺.damowmow.com/', - u'http://code.google.com/events/#&product=browser', - u'http://j.mp', - u'ftp://foo.bar/baz', - u'http://foo.bar/?q=Test%20URL-encoded%20stuff', - u'http://مثال.إختبار', - u'http://例子.测试', - u'http://उदाहरण.परीक्षा', - u'http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com', - u'http://1337.net', - u'http://a.b-c.de', - u'http://223.255.255.254', - u'http://10.1.1.1', - u'http://10.1.1.254', - u'http://127.0.0.1:8080', - u'http://127.0.10.150', - u'http://localhost', - u'http://localhost:8000', - u'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html', - u'http://[1080:0:0:0:8:800:200C:417A]/index.html', - u'http://[3ffe:2a00:100:7031::1]', - u'http://[1080::8:800:200C:417A]/foo', - u'http://[::192.9.5.5]/ipng', - u'http://[::FFFF:129.144.52.38]:80/index.html', - u'http://[2010:836B:4179::836B:4179]', -]) -def test_returns_true_on_valid_url(address): - assert url(address) - - -@pytest.mark.parametrize('address, public', [ - (u'http://foo.bar', True), - (u'http://username:password@example.com:4010/', False), - (u'http://username:password@112.168.10.10:4010/', True), - (u'http://username:password@192.168.10.10:4010/', False), - (u'http://10.0.10.1', False), - (u'http://127.0.0.1', False), -]) -def test_returns_true_on_valid_public_url(address, public): - assert url(address, public=public) - - -@pytest.mark.parametrize('address', [ - 'http://foobar', - 'foobar.dk', - 'http://127.0.0/asdf', - 'http://foobar.d', - 'http://foobar.12', - 'http://foobar', - 'htp://foobar.com', - 'http://foobar..com', - 'http://fo..com', - 'http://', - 'http://.', - 'http://..', - 'http://../', - 'http://?', - 'http://??', - 'http://??/', - 'http://#', - 'http://##', - 'http://##/', - 'http://foo.bar?q=Spaces should be encoded', - '//', - '//a', - '///a', - '///', - 'http:///a', - 'foo.com', - 'rdar://1234', - 'h://test', - 'http:// shouldfail.com', - ':// should fail', - 'http://foo.bar/foo(bar)baz quux', - 'ftps://foo.bar/', - 'http://-error-.invalid/', - 'http://a.b--c.de/', - 'http://-a.b.co', - 'http://a.b-.co', - 'http://0.0.0.0', - 'http://10.1.1.0', - 'http://10.1.1.255', - 'http://224.1.1.1', - 'http://1.1.1.1.1', - 'http://123.123.123', - 'http://3628126748', - 'http://.www.foo.bar/', - 'http://www.foo.bar./', - 'http://.www.foo.bar./', - 'http://127.12.0.260', - 'http://example.com/">user@example.com', - 'http://[2010:836B:4179::836B:4179', - 'http://2010:836B:4179::836B:4179', - 'http://2010:836B:4179::836B:4179:80/index.html', -]) -def test_returns_failed_validation_on_invalid_url(address): - assert isinstance(url(address), ValidationFailure) - - -@pytest.mark.parametrize('address, public', [ - (u'http://username:password@192.168.10.10:4010/', True), - (u'http://10.0.10.1', True), - (u'http://127.0.0.1', True), - (u'foo://127.0.0.1', True), - (u'http://username:password@127.0.0.1:8080', True), - (u'http://localhost', True), - (u'http://localhost:8000', True), - -]) -def test_returns_failed_validation_on_invalid_public_url(address, public): - assert isinstance(url(address, public=public), ValidationFailure) +# -*- coding: utf-8 -*- +import pytest + +from validators import url, ValidationFailure + + +@pytest.mark.parametrize('address', [ + u'http://foobar.dk', + u'http://foobar.museum/foobar', + u'http://fo.com', + u'http://FOO.com', + u'http://foo.com/blah_blah', + u'http://foo.com/blah_blah/', + u'http://foo.com/blah_blah_(wikipedia)', + u'http://foo.com/blah_blah_(wikipedia)_(again)', + u'http://www.example.com/wpstyle/?p=364', + u'https://www.example.com/foo/?bar=baz&inga=42&quux', + u'https://www.example.com?bar=baz', + u'http://✪df.ws/123', + u'http://userid:password@example.com:8080', + u'http://userid:password@example.com:8080/', + u'http://userid@example.com', + u'http://userid@example.com/', + u'http://userid@example.com:8080', + u'http://userid@example.com:8080/', + u'http://userid:password@example.com', + u'http://userid:password@example.com/', + u'http://142.42.1.1/', + u'http://142.42.1.1:8080/', + u'http://➡.ws/䨹', + u'http://⌘.ws', + u'http://⌘.ws/', + u'http://foo.com/blah_(wikipedia)#cite-1', + u'http://foo.com/blah_(wikipedia)_blah#cite-1', + u'http://foo.com/unicode_(✪)_in_parens', + u'http://foo.com/(something)?after=parens', + u'http://☺.damowmow.com/', + u'http://code.google.com/events/#&product=browser', + u'http://j.mp', + u'ftp://foo.bar/baz', + u'http://foo.bar/?q=Test%20URL-encoded%20stuff', + u'http://مثال.إختبار', + u'http://例子.测试', + u'http://उदाहरण.परीक्षा', + u'http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com', + u'http://1337.net', + u'http://a.b-c.de', + u'http://223.255.255.254', + u'http://10.1.1.1', + u'http://10.1.1.254', + u'http://127.0.0.1:8080', + u'http://127.0.10.150', + u'http://localhost', + u'http://localhost:8000', + u'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html', + u'http://[1080:0:0:0:8:800:200C:417A]/index.html', + u'http://[3ffe:2a00:100:7031::1]', + u'http://[1080::8:800:200C:417A]/foo', + u'http://[::192.9.5.5]/ipng', + u'http://[::FFFF:129.144.52.38]:80/index.html', + u'http://[2010:836B:4179::836B:4179]', + u'http://127.0.10.150:0', + u'http://127.0.10.150:08', + u'http://127.0.10.150:0000', + u'http://127.0.10.150:9', +]) +def test_returns_true_on_valid_url(address): + assert url(address) + + +@pytest.mark.parametrize('address, public', [ + (u'http://foo.bar', True), + (u'http://username:password@example.com:4010/', False), + (u'http://username:password@112.168.10.10:4010/', True), + (u'http://username:password@192.168.10.10:4010/', False), + (u'http://10.0.10.1', False), + (u'http://127.0.0.1', False), +]) +def test_returns_true_on_valid_public_url(address, public): + assert url(address, public=public) + + +@pytest.mark.parametrize('address', [ + 'http://foobar', + 'foobar.dk', + 'http://127.0.0/asdf', + 'http://foobar.d', + 'http://foobar.12', + 'http://foobar', + 'htp://foobar.com', + 'http://foobar..com', + 'http://fo..com', + 'http://', + 'http://.', + 'http://..', + 'http://../', + 'http://?', + 'http://??', + 'http://??/', + 'http://#', + 'http://##', + 'http://##/', + 'http://foo.bar?q=Spaces should be encoded', + '//', + '//a', + '///a', + '///', + 'http:///a', + 'foo.com', + 'rdar://1234', + 'h://test', + 'http:// shouldfail.com', + ':// should fail', + 'http://foo.bar/foo(bar)baz quux', + 'ftps://foo.bar/', + 'http://-error-.invalid/', + 'http://a.b--c.de/', + 'http://-a.b.co', + 'http://a.b-.co', + 'http://0.0.0.0', + 'http://10.1.1.0', + 'http://10.1.1.255', + 'http://224.1.1.1', + 'http://1.1.1.1.1', + 'http://123.123.123', + 'http://3628126748', + 'http://.www.foo.bar/', + 'http://www.foo.bar./', + 'http://.www.foo.bar./', + 'http://127.12.0.260', + 'http://example.com/">user@example.com', + 'http://[2010:836B:4179::836B:4179', + 'http://2010:836B:4179::836B:4179', + 'http://2010:836B:4179::836B:4179:80/index.html', +]) +def test_returns_failed_validation_on_invalid_url(address): + assert isinstance(url(address), ValidationFailure) + + +@pytest.mark.parametrize('address, public', [ + (u'http://username:password@192.168.10.10:4010/', True), + (u'http://10.0.10.1', True), + (u'http://127.0.0.1', True), + (u'foo://127.0.0.1', True), + (u'http://username:password@127.0.0.1:8080', True), + (u'http://localhost', True), + (u'http://localhost:8000', True), + +]) +def test_returns_failed_validation_on_invalid_public_url(address, public): + assert isinstance(url(address, public=public), ValidationFailure) diff --git a/validators/email.py b/validators/email.py index 6c36c2e8..f3274ff3 100644 --- a/validators/email.py +++ b/validators/email.py @@ -1,16 +1,34 @@ +""" +As per the below link email specification + +https://help.returnpath.com/hc/en-us/articles/220560587-What-are-the-rules-for-email-address-syntax- + +""" + import re from .utils import validator +# user_regex = re.compile( +# # dot-atom +# r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+" +# r"(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" +# # quoted-string +# r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|' +# r"""\\[\001-\011\013\014\016-\177])*"$)""", +# re.IGNORECASE +# ) + + user_regex = re.compile( - # dot-atom - r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+" - r"(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" - # quoted-string - r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|' - r"""\\[\001-\011\013\014\016-\177])*"$)""", + # rejecting the special charatcters at start of the name + r"(^(?!-\!#$%&'\"*\+\/=?^_`{})[0-9A-Z\_\-\.\+]+" + # rejecting the special charatcters at end of the name + r"(?!-\!#$%&'*\"\+\/=?^_`{})$)", re.IGNORECASE ) + + domain_regex = re.compile( # domain r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+' @@ -59,6 +77,20 @@ def email(value, whitelist=None): user_part, domain_part = value.rsplit('@', 1) + if (len(user_part) >= 65) : + return False + + + if (len(domain_part) >= 254): + return False + + if ('@' in user_part): + return False + + if ('@' in domain_part): + return False + + if not user_regex.match(user_part): return False diff --git a/validators/url.py b/validators/url.py index 5f19e2d2..97b3568b 100644 --- a/validators/url.py +++ b/validators/url.py @@ -77,6 +77,9 @@ r")" # port number r"(?::\d{2,5})?" + # added support for port values 1-8 and excluding + # zero port number due to limitation + # r"(?::0?([1-9]{1,5}))" # resource path u"(?:/[-a-z\u00a1-\uffff0-9._~%!$&'()*+,;=:@/]*)?" # query string